2016-05-22 21:10:37 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
2016-08-21 02:19:24 +03:00
|
|
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
|
|
|
(function(require){ var module={} // make module AMD/node compatible...
|
2016-08-20 22:49:36 +03:00
|
|
|
/*********************************************************************/
|
2016-05-22 21:10:37 +03:00
|
|
|
|
|
|
|
|
var actions = require('lib/actions')
|
|
|
|
|
var features = require('lib/features')
|
2016-05-25 22:09:03 +03:00
|
|
|
var preview = require('lib/preview')
|
2016-05-22 21:10:37 +03:00
|
|
|
|
|
|
|
|
var core = require('features/core')
|
|
|
|
|
|
|
|
|
|
try{
|
|
|
|
|
var sharp = requirejs('sharp')
|
|
|
|
|
|
|
|
|
|
} catch(err){
|
2016-05-25 22:09:03 +03:00
|
|
|
var sharp = null
|
2016-05-22 21:10:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(typeof(process) != 'undefined'){
|
2016-05-22 23:11:12 +03:00
|
|
|
var cp = requirejs('child_process')
|
2016-05-22 21:10:37 +03:00
|
|
|
var fse = requirejs('fs-extra')
|
|
|
|
|
var pathlib = requirejs('path')
|
|
|
|
|
var glob = requirejs('glob')
|
2016-05-28 16:29:57 +03:00
|
|
|
|
2016-06-01 16:12:10 +03:00
|
|
|
var file = require('imagegrid/file')
|
2016-05-22 21:10:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
|
|
if(typeof(process) != 'undefined'){
|
|
|
|
|
var ensureDir = file.denodeify(fse.ensureDir)
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-03 04:46:51 +03:00
|
|
|
function normalizeOrientation(orientation){
|
|
|
|
|
return {
|
|
|
|
|
orientation: ({
|
|
|
|
|
0: 0,
|
|
|
|
|
1: 0,
|
|
|
|
|
2: 0,
|
|
|
|
|
3: 180,
|
|
|
|
|
4: 0,
|
|
|
|
|
5: 90,
|
|
|
|
|
6: 90,
|
|
|
|
|
7: 90,
|
|
|
|
|
8: 270,
|
|
|
|
|
})[orientation],
|
|
|
|
|
flipped: ({
|
|
|
|
|
0: null,
|
|
|
|
|
1: null,
|
|
|
|
|
2: ['horizontal'],
|
|
|
|
|
3: null,
|
|
|
|
|
4: ['vertical'],
|
|
|
|
|
5: ['vertical'],
|
|
|
|
|
6: null,
|
|
|
|
|
7: ['horizontal'],
|
|
|
|
|
8: null,
|
|
|
|
|
})[orientation],
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-22 21:10:37 +03:00
|
|
|
|
2016-05-28 16:29:57 +03:00
|
|
|
|
2016-05-22 21:10:37 +03:00
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
|
|
var SharpActions = actions.Actions({
|
|
|
|
|
config: {
|
|
|
|
|
'preview-normalized': true,
|
|
|
|
|
|
2016-05-26 05:36:28 +03:00
|
|
|
// NOTE: this uses 'preview-sizes' and 'preview-path-template'
|
|
|
|
|
// from filesystem.IndexFormat...
|
2016-05-22 21:10:37 +03:00
|
|
|
},
|
|
|
|
|
|
2016-05-26 00:49:09 +03:00
|
|
|
// NOTE: post handlers are pushed in .makePreviews(..)
|
|
|
|
|
// XXX might be a good idea to make this a bit more generic...
|
|
|
|
|
// XXX might be a good idea to use tasks to throttle....
|
2016-05-23 19:19:09 +03:00
|
|
|
startPreviewWorker: ['- Sharp/',
|
2016-05-22 23:11:12 +03:00
|
|
|
function(){
|
2016-05-26 00:49:09 +03:00
|
|
|
var that = this
|
2016-05-22 23:11:12 +03:00
|
|
|
if(this.previewConstructorWorker){
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-05-25 23:16:41 +03:00
|
|
|
this.previewConstructorWorker = cp.fork(
|
|
|
|
|
'./workers/preview-constructor.js', {
|
|
|
|
|
cwd: process.cwd(),
|
|
|
|
|
})
|
|
|
|
|
.on('message', function(res){
|
|
|
|
|
if(res.err){
|
|
|
|
|
// XXX
|
|
|
|
|
console.error(res)
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
var ticket = res.ticket
|
2016-05-26 00:49:09 +03:00
|
|
|
// clear listener...
|
2016-05-25 23:16:41 +03:00
|
|
|
if(res.status == 'completed'){
|
2016-05-26 00:49:09 +03:00
|
|
|
that.previewConstructorWorker.__post_handlers[res.ticket](null, 'completed')
|
|
|
|
|
delete that.previewConstructorWorker.__post_handlers[res.ticket]
|
2016-05-25 23:16:41 +03:00
|
|
|
|
|
|
|
|
} else {
|
2016-05-26 00:49:09 +03:00
|
|
|
that.previewConstructorWorker.__post_handlers[res.ticket](res.err, res.data)
|
2016-05-25 23:16:41 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
2016-05-26 00:49:09 +03:00
|
|
|
|
|
|
|
|
this.previewConstructorWorker.__post_handlers = {}
|
2016-05-22 23:11:12 +03:00
|
|
|
}],
|
2016-05-23 19:19:09 +03:00
|
|
|
stopPreviewWorker: ['- Sharp/',
|
2016-05-22 23:11:12 +03:00
|
|
|
function(){
|
|
|
|
|
this.previewConstructorWorker && this.previewConstructorWorker.kill()
|
|
|
|
|
delete this.previewConstructorWorker
|
|
|
|
|
}],
|
|
|
|
|
|
2016-05-23 17:54:11 +03:00
|
|
|
|
2016-05-22 21:10:37 +03:00
|
|
|
// .makePreviews()
|
|
|
|
|
// .makePreviews('current')
|
|
|
|
|
// -> actions
|
|
|
|
|
//
|
|
|
|
|
// .makePreviews(gid)
|
|
|
|
|
// -> actions
|
|
|
|
|
//
|
|
|
|
|
// .makePreviews([gid, gid, ..])
|
|
|
|
|
// -> actions
|
|
|
|
|
//
|
|
|
|
|
// .makePreviews('all')
|
|
|
|
|
// -> actions
|
|
|
|
|
//
|
|
|
|
|
// XXX should this account for non-jpeg images???
|
|
|
|
|
makePreviews: ['Sharp/Make image previews',
|
2016-05-25 22:09:03 +03:00
|
|
|
function(images, sizes, base_path, logger){
|
|
|
|
|
var that = this
|
2016-05-22 21:10:37 +03:00
|
|
|
logger = logger || this.logger
|
|
|
|
|
|
2016-05-25 22:09:03 +03:00
|
|
|
|
|
|
|
|
// get/normalize images...
|
2016-05-22 21:10:37 +03:00
|
|
|
images = images || this.current
|
|
|
|
|
// keywords...
|
|
|
|
|
images = images == 'all' ? this.data.getImages('all')
|
|
|
|
|
: images == 'current' ? this.current
|
|
|
|
|
: images
|
|
|
|
|
images = images instanceof Array ? images : [images]
|
|
|
|
|
|
2016-05-25 22:09:03 +03:00
|
|
|
// NOTE: if base_path is not provided this will base the
|
|
|
|
|
// previews in .base_path for each image, usually this
|
|
|
|
|
// is where the index resides but might not be the
|
|
|
|
|
// case for compound indexes...
|
|
|
|
|
var data = {}
|
|
|
|
|
images.forEach(function(gid){
|
|
|
|
|
var img = that.images[gid]
|
|
|
|
|
var base = base_path || img.base_path || that.location.path
|
|
|
|
|
|
|
|
|
|
var d = data[base] = data[base] || []
|
|
|
|
|
|
|
|
|
|
d.push({
|
|
|
|
|
source: that.getImagePath(gid),
|
|
|
|
|
gid: gid,
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get/normalize sizes....
|
|
|
|
|
var cfg_sizes = this.config['preview-sizes'].slice() || []
|
2016-05-22 21:10:37 +03:00
|
|
|
cfg_sizes
|
|
|
|
|
.sort()
|
|
|
|
|
.reverse()
|
|
|
|
|
|
2016-05-23 03:42:53 +03:00
|
|
|
if(sizes){
|
|
|
|
|
sizes = sizes instanceof Array ? sizes : [sizes]
|
|
|
|
|
// normalize to preview size...
|
|
|
|
|
sizes = (this.config['preview-normalized'] ?
|
|
|
|
|
sizes
|
|
|
|
|
.map(function(s){
|
|
|
|
|
return cfg_sizes.filter(function(c){ return c >= s }).pop() || s })
|
|
|
|
|
: sizes)
|
|
|
|
|
.unique()
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
sizes = cfg_sizes
|
|
|
|
|
}
|
2016-05-22 21:10:37 +03:00
|
|
|
|
2016-05-25 22:09:03 +03:00
|
|
|
var path_tpl = that.config['preview-path-template']
|
|
|
|
|
.replace(/\$INDEX|\$\{INDEX\}/g, that.config['index-dir'] || '.ImageGrid')
|
|
|
|
|
|
2016-05-26 00:49:09 +03:00
|
|
|
var post_handler = function(err, data){
|
|
|
|
|
if(data.status == 'done' || data.status == 'skipped'){
|
|
|
|
|
// get/make preview list...
|
2016-06-03 04:46:51 +03:00
|
|
|
var img = that.images[data.gid]
|
|
|
|
|
var preview = img.preview =
|
|
|
|
|
img.preview || {}
|
2016-05-26 00:49:09 +03:00
|
|
|
|
2016-06-03 04:46:51 +03:00
|
|
|
// save previews...
|
2016-05-26 00:49:09 +03:00
|
|
|
preview[data.res + 'px'] = data.path
|
|
|
|
|
|
2016-06-03 04:46:51 +03:00
|
|
|
var o = normalizeOrientation(data.orientation)
|
|
|
|
|
|
|
|
|
|
// save orientation...
|
|
|
|
|
img.orientation = o.orientation
|
|
|
|
|
img.flipped = o.flipped
|
|
|
|
|
|
2016-05-26 00:49:09 +03:00
|
|
|
that.markChanged(data.gid)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger && logger.emit(data.status, data.path)
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-25 23:16:41 +03:00
|
|
|
// now do the work (async)...
|
|
|
|
|
if(this.previewConstructorWorker){
|
|
|
|
|
return Promise.all(Object.keys(data).map(function(base_path){
|
2016-05-26 00:49:09 +03:00
|
|
|
return new Promise(function(resolve, reject){
|
|
|
|
|
var ticket = Date.now()
|
|
|
|
|
while(ticket in that.previewConstructorWorker.__post_handlers){
|
|
|
|
|
ticket = Date.now()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
that.previewConstructorWorker.send({
|
|
|
|
|
ticket: ticket,
|
|
|
|
|
|
|
|
|
|
images: data[base_path],
|
|
|
|
|
sizes: sizes,
|
|
|
|
|
base_path: base_path,
|
|
|
|
|
target_tpl: path_tpl,
|
|
|
|
|
})
|
|
|
|
|
that.previewConstructorWorker.__post_handlers[ticket] = function(err, data){
|
|
|
|
|
// XXX
|
|
|
|
|
if(err){
|
|
|
|
|
reject(err)
|
|
|
|
|
}
|
|
|
|
|
if(data == 'completed'){
|
|
|
|
|
resolve()
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
post_handler(err, data)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-25 22:09:03 +03:00
|
|
|
})
|
2016-05-25 23:16:41 +03:00
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
// now do the work (sync)...
|
|
|
|
|
} else {
|
|
|
|
|
return Promise.all(Object.keys(data).map(function(base_path){
|
|
|
|
|
return preview.makePreviews(
|
2016-05-26 00:49:09 +03:00
|
|
|
data[base_path], sizes, base_path, path_tpl, post_handler)
|
2016-05-25 23:16:41 +03:00
|
|
|
}))
|
|
|
|
|
}
|
2016-05-22 21:10:37 +03:00
|
|
|
}],
|
|
|
|
|
})
|
|
|
|
|
|
2016-05-26 05:36:28 +03:00
|
|
|
|
|
|
|
|
// XXX need to auto-generate previews for very large images...
|
2016-05-22 21:10:37 +03:00
|
|
|
var Sharp =
|
|
|
|
|
module.Sharp = core.ImageGridFeatures.Feature({
|
|
|
|
|
title: '',
|
|
|
|
|
doc: '',
|
|
|
|
|
|
|
|
|
|
tag: 'sharp',
|
|
|
|
|
depends: [
|
|
|
|
|
'location',
|
2016-05-26 05:36:28 +03:00
|
|
|
'index-format',
|
2016-05-22 21:10:37 +03:00
|
|
|
],
|
|
|
|
|
|
|
|
|
|
actions: SharpActions,
|
|
|
|
|
|
|
|
|
|
isApplicable: function(){ return !!sharp },
|
|
|
|
|
|
|
|
|
|
handlers: [
|
2016-06-03 04:46:51 +03:00
|
|
|
// set orientation if not defined...
|
|
|
|
|
['updateImage',
|
|
|
|
|
function(_, gid){
|
|
|
|
|
var that = this
|
|
|
|
|
var img = this.images[gid]
|
|
|
|
|
|
|
|
|
|
if(img && img.orientation == null){
|
|
|
|
|
img.orientation = 0
|
|
|
|
|
|
|
|
|
|
sharp(this.getImagePath(gid))
|
|
|
|
|
.metadata()
|
|
|
|
|
.then(function(data){
|
|
|
|
|
var o = normalizeOrientation(data.orientation)
|
|
|
|
|
|
|
|
|
|
// NOTE: we need to set orientation to something
|
|
|
|
|
// or we'll check it again and again...
|
|
|
|
|
img.orientation = o.orientation || 0
|
|
|
|
|
img.flipped = o.flipped
|
|
|
|
|
|
|
|
|
|
that.markChanged(gid)
|
|
|
|
|
|
|
|
|
|
// update image to use the orientation...
|
|
|
|
|
// XXX this might be a source for recursion
|
|
|
|
|
// as it triggers .updateImage(..) again...
|
|
|
|
|
that.ribbons && that.ribbons.updateImage(gid)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}],
|
|
|
|
|
|
2016-05-22 23:11:12 +03:00
|
|
|
// XXX need to:
|
|
|
|
|
// - if image too large to set the preview to "loading..."
|
|
|
|
|
// - create previews...
|
|
|
|
|
// - update image...
|
2016-05-23 03:42:53 +03:00
|
|
|
/*
|
2016-05-22 21:10:37 +03:00
|
|
|
['updateImage.pre',
|
|
|
|
|
function(gid){
|
|
|
|
|
var that = this
|
|
|
|
|
if(this.images[gid].preview == null){
|
|
|
|
|
sharp(this.getImagePath(gid))
|
|
|
|
|
.metadata()
|
|
|
|
|
.then(function(metadata){
|
2016-05-22 23:11:12 +03:00
|
|
|
// current image is larger than any of the previews...
|
2016-05-22 21:10:37 +03:00
|
|
|
if(Math.max(metadata.width, metadata.height)
|
|
|
|
|
> Math.max.apply(Math, that.config['preview-sizes'])){
|
2016-05-22 23:11:12 +03:00
|
|
|
// create the currently needed preview first...
|
|
|
|
|
that.makePreviews(gid, that.ribbons.getVisibleImageSize())
|
|
|
|
|
.then(function(){
|
|
|
|
|
// load the created preview...
|
|
|
|
|
that.ribbons.updateImage(gid)
|
|
|
|
|
|
|
|
|
|
// create the rest...
|
|
|
|
|
that.makePreviews(gid)
|
|
|
|
|
})
|
2016-05-22 21:10:37 +03:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}]
|
2016-05-23 03:42:53 +03:00
|
|
|
//*/
|
2016-05-22 21:10:37 +03:00
|
|
|
],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
2016-08-20 22:49:36 +03:00
|
|
|
* vim:set ts=4 sw=4 : */ return module })
|