buildcache.py now supports RAW input images (slow), some refactoring on ui...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2013-05-28 21:59:38 +04:00
parent 156797f15b
commit b50f399f3d
5 changed files with 189 additions and 121 deletions

View File

@ -1,7 +1,7 @@
#=======================================================================
__version__ = '''0.0.01'''
__sub_version__ = '''20130528154633'''
__sub_version__ = '''20130528215723'''
__copyright__ = '''(c) Alex A. Naanou 2011'''
@ -13,8 +13,14 @@ import json
import sha
import urllib2
import time
import tempfile
from optparse import OptionParser, OptionGroup
try:
import pyexiv2 as metadata
except:
metadata = None
from pli.logictypes import OR
import gid
@ -51,6 +57,7 @@ CONFIG = {
'900px': '900px/',
'1080px': '1080px/',
'1920px': '1920px/',
'preview': 'preview/',
},
'sizes': {
'150px': 150,
@ -69,10 +76,6 @@ DATA = {
'image_file': None,
}
IMAGE_EXT = OR(*(
'.jpg', '.jpeg', '.JPG', '.JPEG',
))
ERR_LOG = '''\
ERROR: %(error)s
SOURCE: %(source-file)s
@ -82,6 +85,25 @@ TARGET: %(target-file)s
'''
RAW = OR(
# Nikon
'NEF', 'nef',
# Panasonic/Leica
'RW2', 'rw2',
# Canon
'CRW', 'crw',
'CR2', 'cr2',
# Sigma
'X3F', 'x3f',
# Adobe/Leica
'DNG', 'dng',
)
IMAGE = OR(
'jpg', 'jpeg', 'JPG', 'JPEG',
)
#-----------------------------------------------------------------------
# Helpers...
#------------------------------------------------------------pathjoin---
@ -95,6 +117,10 @@ def pathjoin(*p):
def getpath(root, path, absolute=False):
'''
'''
if root in path:
path = path.split(root)[-1]
if path[0] in ('\\', '/'):
path = path[1:]
if absolute == True:
return 'file:///' + urllib2.quote(pathjoin(root, path), safe='/:')
else:
@ -217,24 +243,52 @@ def build_images(path, config=CONFIG, gid_generator=hash_gid, verbosity=0):
for name in os.listdir(path):
fname, ext = os.path.splitext(name)
ext = ext[1:]
if ext != IMAGE_EXT:
# extract raw preview...
# XXX this is really slow, need a better way to do this...
if ext == RAW and metadata != None:
source_path = pathjoin(path, name)
raw = metadata.ImageMetadata(source_path)
raw.read()
##!!! can there be no previews?
# get the biggest preview...
preview = raw.previews[0]
for p in raw.previews:
if max(preview.dimensions) < max(p.dimensions):
preview = p
source_path = pathjoin(path, CONFIG['cache-dir'], CONFIG['cache-structure']['preview'], fname + '.jpg')
with open(source_path, 'w+b') as p:
p.write(preview.data)
# copy metadata...
preview = metadata.ImageMetadata(source_path)
preview.read()
raw.copy(preview)
preview.write()
# normal images...
elif ext == IMAGE:
source_path = pathjoin(path, name)
# skip other files...
else:
continue
source_path = pathjoin(path, name)
img = {
'id': gid_generator(source_path),
'name': name,
'type': 'image',
'state': 'single',
'path': getpath(path, name, absolute_path),
'ctime': os.path.getctime(source_path),
'path': getpath(path, source_path, absolute_path),
'ctime': os.path.getctime(pathjoin(path, name)),
'preview': {},
}
if verbosity >= 2:
print (' '*72) + '\rProcessing image: %s' % getpath(path, name, absolute_path)
print (' '*72) + '\rProcessing image: %s' % getpath(path, source_path, absolute_path)
yield img
@ -281,7 +335,7 @@ def build_previews(image, path=None, config=CONFIG, dry_run=True, verbosity=0):
continue
# build the two paths: relative and full...
n = pathjoin(cache_dir, dirs[k], cache_name % {'guid': gid, 'name': img_name})
n = pathjoin(cache_dir, dirs[k], cache_name % {'guid': gid, 'name': name + '.jpg'})
p = pathjoin(path, n)
# do not upscale images...

View File

@ -103,23 +103,51 @@ function flashIndicator(direction){
}
function getRibbon(image){
image = image == null ? $('.current.image') : $(image)
return image.closest('.ribbon')
function getImage(gid){
var res
// current or first (no gid given)
if(gid == null){
res = $('.current.image')
return res.length == 0 ? $('.image').first() : res
}
// gid...
res = $('.image[gid='+ JSON.stringify(gid) +']')
if(res.length != null){
return res
}
// order...
res = $('.image[order='+ JSON.stringify(gid) +']')
if(res.length != null){
return res
}
return null
}
function getImage(gid){
if(e == null){
return $('.current.image')
function getImageOrder(image){
image = image == null ? getImage() : $(image)
if(image.length == 0){
return
}
// XXX do a proper check...
// gid...
return $('.image[gid='+ JSON.stringify(gid) +']')
// order...
// XXX
//return $('.image[order='+ JSON.stringify(gid) +']')
return JSON.parse(image.attr('order'))
}
function getImageGID(image){
image = image == null ? getImage() : $(image)
if(image.length == 0){
return
}
return JSON.parse(image.attr('gid'))
}
function getRibbon(image){
image = image == null ? getImage() : $(image)
return image.closest('.ribbon')
}
@ -139,24 +167,6 @@ function getRibbonIndex(elem){
}
function getImageOrder(image){
image = image == null ? $('.current.image') : $(image)
if(image.length == 0){
return
}
return JSON.parse(image.attr('order'))
}
function getImageGID(image){
image = image == null ? $('.current.image') : $(image)
if(image.length == 0){
return
}
return JSON.parse(image.attr('gid'))
}
// Calculate relative position between two elements
//
// NOTE: tried to make this as brain-dead-stupidly-simple as possible...
@ -213,7 +223,7 @@ function getScreenWidthInImages(size){
// getGIDBefore(...) that will check the full data...
function getImageBefore(image, ribbon, mode){
mode = mode == null ? NAV_DEFAULT : mode
image = image == null ? $('.current.image') : $(image)
image = image == null ? getImage() : $(image)
if(ribbon == null){
ribbon = getRibbon(image)
}
@ -260,7 +270,7 @@ function shiftTo(image, ribbon){
function shiftImage(direction, image, force_create_ribbon){
image = image == null ? $('.current.image') : $(image)
image = image == null ? getImage() : $(image)
var old_ribbon = getRibbon(image)
var ribbon = old_ribbon[direction]('.ribbon')
@ -534,7 +544,7 @@ function centerView(image, mode){
$('.viewer').trigger('preCenteringView', [getRibbon(image), image])
if(image == null || image.length == 0){
image = $('.current.image')
image = getImage()
}
var viewer = $('.viewer')
// XXX should these be "inner"???
@ -583,7 +593,7 @@ function centerView(image, mode){
// center relative to target (given) via the ribbon left
// only left coordinate is changed...
//
// NOTE: image defaults to $('.current.image').
// NOTE: image defaults to getImage().
//
// XXX might be good to merge this and centerImage...
// ...or make a generic centering function...
@ -593,7 +603,7 @@ function centerView(image, mode){
function centerRibbon(ribbon, image, mode){
mode = mode == null ? TRANSITION_MODE_DEFAULT : mode
ribbon = ribbon == null ? getRibbon() : $(ribbon)
image = image == null ? $('.current.image') : $(image)
image = image == null ? getImage() : $(image)
$('.viewer').trigger('preCenteringRibbon', [ribbon, image])
@ -684,7 +694,7 @@ function dblClickHandler(evt){
function nextImage(n, mode){
mode = mode == null ? NAV_DEFAULT : mode
n = n == null ? 1 : n
var target = $('.current.image').nextAll('.image' + mode)
var target = getImage().nextAll('.image' + mode)
if(target.length < n){
target = target.last()
// XXX this fires if we hit the end of the currently loaded
@ -699,7 +709,7 @@ function nextImage(n, mode){
function prevImage(n, mode){
mode = mode == null ? NAV_DEFAULT : mode
n = n == null ? 1 : n
var target = $('.current.image').prevAll('.image' + mode)
var target = getImage().prevAll('.image' + mode)
if(target.length < n){
target = target.last()
// XXX this fires if we hit the end of the currently loaded
@ -726,7 +736,7 @@ function firstImage(mode){
$('.viewer').trigger('requestedFirstImage', [getRibbon()])
mode = mode == null ? NAV_DEFAULT : mode
if($('.current.image').prevAll('.image' + mode).length == 0){
if(getImage().prevAll('.image' + mode).length == 0){
flashIndicator('start')
}
return centerView(
@ -738,7 +748,7 @@ function lastImage(mode){
$('.viewer').trigger('requestedLastImage', [getRibbon()])
mode = mode == null ? NAV_DEFAULT : mode
if($('.current.image').nextAll('.image' + mode).length == 0){
if(getImage().nextAll('.image' + mode).length == 0){
flashIndicator('end')
}
return centerView(
@ -753,7 +763,7 @@ function lastImage(mode){
// on direction...
function prevRibbon(mode){
mode = mode == null ? NAV_DEFAULT : mode
var cur = $('.current.image')
var cur = getImage()
var target = getImageBefore(cur,
getRibbon(cur).prevAll('.ribbon' + NAV_RIBBON_DEFAULT).first())
@ -772,7 +782,7 @@ function prevRibbon(mode){
}
function nextRibbon(mode){
mode = mode == null ? NAV_DEFAULT : mode
var cur = $('.current.image')
var cur = getImage()
var target = getImageBefore(cur,
getRibbon(cur).nextAll('.ribbon' + NAV_RIBBON_DEFAULT).first())
@ -870,7 +880,7 @@ var _ccw = {
function rotateImage(direction, image){
var r_table = direction == 'left' ? _cw : _ccw
image = image == null ? $('.current.image') : $(image)
image = image == null ? getImage() : $(image)
image.each(function(i, e){
var img = $(this)
var o = r_table[img.attr('orientation')]
@ -909,7 +919,7 @@ function flipHorizontal(image){
/********************************************************* Zooming ***/
function fitNImages(n){
var image = $('.current.image')
var image = getImage()
var w = image.outerWidth(true)
var h = image.outerHeight(true)
@ -952,7 +962,7 @@ function zoomOut(){
function shiftImageTo(image, direction, moving, force_create_ribbon, mode){
if(image == null){
image = $('.current.image')
image = getImage()
}
mode = mode == null ? NAV_DEFAULT : mode

View File

@ -213,10 +213,66 @@ Array.prototype.binSearch = function(target, cmp){
}
// Normalize the path...
//
// This will:
// - convert windows absolute paths 'X:\...' -> 'file:///X:/...'
// - if mode is 'absolute':
// - return absolute paths as-is
// - base relative paths on base/BASE_URL, returning an absolute
// path
// - if mode is relative:
// - if absolute path is based on base/BASE_URL make a relative
// to base path out of it buy cutting the base out.
// - return absolute paths as-is
// - return relative paths as-is
//
// NOTE: mode can be either 'absolute' (default) or 'relative'...
function normalizePath(url, base, mode){
mode = mode == null ? 'absolute' : mode
base = base == null ? BASE_URL : base
// windows path...
// - replace all '\\' with '/'...
url = url.replace(/\\/g, '/')
// - replace 'X:/...' with 'file:///X:/...'
if(/^[A-Z]:\//.test(url)){
url = 'file:///' + url
}
// we got absolute path...
if(/^(file|http|https):\/\/.*$/.test(url)){
// check if we start with base, and remove it if so...
if(mode == 'relative' && url.substring(0, base.length) == base){
url = url.substring(base.length - 1)
return url[0] == '/' ? url.substring(1) : url
// if it's a different path, return as-is
} else if(mode == 'absolute'){
return url
}
// make an absolute path...
} else if(mode == 'absolute') {
// if base ends and url starts with '.' avoid making it a '..'
if(base[base.length-1] == '.' && url[0] == '.'){
return base + url.substring(1)
// avoid creating '//'...
} else if(base[base.length-1] != '/' && url[0] != '/'){
return base + '/' + url
} else {
return base + url
}
}
}
// Same as getImageBefore, but uses gids and searches in DATA...
//
// NOTE: this uses it's own predicate...
function getGIDBefore(gid, ribbon, search){
gid = gid == null ? getImageGID() : gid
ribbon = ribbon == null ? getRibbonIndex() : ribbon
search = search == null ? binSearch : search
//search = search == null ? match2(linSearch, binSearch) : search
ribbon = DATA.ribbons[ribbon]
@ -293,6 +349,7 @@ function getImageGIDs(from, count, ribbon, inclusive){
//
// NOTE: this will use the original if everything else is smaller...
function getBestPreview(gid, size){
gid = gid == null ? getImageGID(): gid
size = size == null ? getVisibleImageSize('max') : size
var s
var img_data = IMAGES[gid]
@ -315,66 +372,12 @@ function getBestPreview(gid, size){
}
// Normalize the path...
//
// This will:
// - convert windows absolute paths 'X:\...' -> 'file:///X:/...'
// - if mode is 'absolute':
// - return absolute paths as-is
// - base relative paths on base/BASE_URL, returning an absolute
// path
// - if mode is relative:
// - if absolute path is based on base/BASE_URL make a relative
// to base path out of it buy cutting the base out.
// - return absolute paths as-is
// - return relative paths as-is
//
// NOTE: mode can be either 'absolute' (default) or 'relative'...
function normalizePath(url, base, mode){
mode = mode == null ? 'absolute' : mode
base = base == null ? BASE_URL : base
// windows path...
// - replace all '\\' with '/'...
url = url.replace(/\\/g, '/')
// - replace 'X:/...' with 'file:///X:/...'
if(/^[A-Z]:\//.test(url)){
url = 'file:///' + url
}
// we got absolute path...
if(/^(file|http|https):\/\/.*$/.test(url)){
// check if we start with base, and remove it if so...
if(mode == 'relative' && url.substring(0, base.length) == base){
url = url.substring(base.length - 1)
return url[0] == '/' ? url.substring(1) : url
// if it's a different path, return as-is
} else if(mode == 'absolute'){
return url
}
// make an absolute path...
} else if(mode == 'absolute') {
// if base ends and url starts with '.' avoid making it a '..'
if(base[base.length-1] == '.' && url[0] == '.'){
return base + url.substring(1)
// avoid creating '//'...
} else if(base[base.length-1] != '/' && url[0] != '/'){
return base + '/' + url
} else {
return base + url
}
}
}
/**********************************************************************
* Constructors
*/
function urlList2Images(lst){
function imagesFromUrls(lst){
var res = {}
$.each(lst, function(i, e){
@ -509,7 +512,7 @@ function updateImage(image, gid, size){
}
// shorthand...
// Same as updateImage(...) but will update all images.
function updateImages(size){
size = size == null ? getVisibleImageSize('max') : size
return $('.image').each(function(){
@ -841,6 +844,7 @@ function saveLocalStorage(attr){
* XXX need to cleanup this section...
*/
// load the target-specific handlers...
// CEF
if(window.CEF_dumpJSON != null){
var dumpJSON = CEF_dumpJSON
@ -1091,7 +1095,7 @@ function loadDir(path, raw_load){
return
}
IMAGES = urlList2Images(image_paths)
IMAGES = imagesFromUrls(image_paths)
DATA = dataFromImages(IMAGES)
MARKED = []
BASE_URL = orig_path

View File

@ -246,7 +246,7 @@ var KEYBOARD_CONFIG = {
} else {
prevImage()
}
if($('.current.image').filter(':visible').length == 0){
if(getImage().filter(':visible').length == 0){
centerView(focusImage(getImageBefore()))
}
centerRibbons()
@ -260,7 +260,7 @@ var KEYBOARD_CONFIG = {
} else {
prevImage()
}
if($('.current.image').filter(':visible').length == 0){
if(getImage().filter(':visible').length == 0){
centerView(focusImage(getImageBefore()))
}
centerRibbons()
@ -274,7 +274,7 @@ var KEYBOARD_CONFIG = {
// XXX STUB -- replace with a real info window...
default: doc('Show current image info',
function(){
var gid = getImageGID($('.current.image'))
var gid = getImageGID(getImage())
var r = getRibbonIndex(getRibbon())
var data = IMAGES[gid]
var orientation = data.orientation

View File

@ -77,7 +77,7 @@ var toggleMarkedOnlyView = createCSSClassToggler('.viewer',
// XXX shifting images and unmarking in this mode do not work correctly...
var toggleMarkesView = createCSSClassToggler('.viewer', 'marks-visible',
function(){
var cur = $('.current.image')
var cur = getImage()
// current is marked...
if(cur.hasClass('marked')){
centerView(null, 'css')
@ -91,7 +91,7 @@ var toggleMarkesView = createCSSClassToggler('.viewer', 'marks-visible',
}
// get marked image from other ribbons...
prevRibbon()
if($('.current.image').hasClass('marked')){
if(getImage().hasClass('marked')){
return
}
nextRibbon()
@ -106,7 +106,7 @@ var toggleMarkesView = createCSSClassToggler('.viewer', 'marks-visible',
var toggleImageMark = createCSSClassToggler('.current.image', 'marked',
function(action){
toggleMarkesView('on')
$('.viewer').trigger('togglingMark', [$('.current.image'), action])
$('.viewer').trigger('togglingMark', [getImage(), action])
})
@ -162,7 +162,7 @@ function invertImageMarks(){
// XXX need to make this dynamic data compatible...
function toggleImageMarkBlock(image){
if(image == null){
image = $('.current.image')
image = getImage()
}
//$('.viewer').trigger('togglingImageBlockMarks', [image])
// we need to invert this...