migrated .makeResizedImage(..) to queue...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-12-06 04:39:42 +03:00
parent 10c966f387
commit 9f4b877e37
3 changed files with 154 additions and 198 deletions

View File

@ -2694,8 +2694,9 @@ function(title, func){
;(items instanceof Array ? ;(items instanceof Array ?
items items
: [items]) : [items])
.forEach(function(item){ .map(function(item){
func.call(that, item, ...args) }) return func.call(that, item, ...args) })
// XXX should we return anything in sync mode???
return Promise.resolve() return Promise.resolve()
// queue mode... // queue mode...
@ -2725,14 +2726,17 @@ function(title, func){
return [e, ...args] }) return [e, ...args] })
: [items, ...args])) : [items, ...args]))
// make a promise... // make a promise...
var res = new Promise(function(resolve, reject){ return new Promise(function(resolve, reject){
q.then(resolve, reject) }) q.then(resolve, reject) }) } }),
return res } }),
{ {
title, title,
toString: function(){ toString: function(){
// XXX add opts of given...
return `core.queueHandler('${action.name}',\n\t${ return `core.queueHandler('${action.name}',\n\t${
object.normalizeIndent( '\t'+ func.toString() ) })` }, (arg_handler ?
object.normalizeIndent( '\t'+ arg_handler.toString() ) + ',\n\t'
: '')
+ object.normalizeIndent( '\t'+ func.toString() ) })` },
}) } }) }
var sessionQueueHandler = var sessionQueueHandler =

View File

@ -185,18 +185,9 @@ var SharpActions = actions.Actions({
// from filesystem.IndexFormat... // from filesystem.IndexFormat...
}, },
// XXX need to distinguish if something was written in the promise chain... // XXX revise return values...
// ...return false???
// ......should the return value be a bit more informative???
// something like:
// {
// gid: ..
// path: ..
// status: ..
// ...
// }
// XXX make backup name pattern configurable... // XXX make backup name pattern configurable...
// XXX add crop support... // XXX CROP ready for crop support...
makeResizedImage: ['- Image/', makeResizedImage: ['- Image/',
core.doc`Make resized image(s)... core.doc`Make resized image(s)...
@ -213,15 +204,16 @@ var SharpActions = actions.Actions({
options format: options format:
{ {
// output image name... // output image name / name pattern...
// //
// Used if processing a single image, ignored otherwise. // NOTE: for multiple images this should be a pattern and not an
// explicit name...
// NOTE: if not given this defaults to: "%n"
name: null | <str>, name: null | <str>,
// image name pattern and data... // image name pattern data...
// //
// NOTE: for more info on pattern see: .formatImageName(..) // NOTE: for more info on pattern see: .formatImageName(..)
pattern: null | <str>,
data: null | { .. }, data: null | { .. },
// if true and image is smaller than size enlarge it... // if true and image is smaller than size enlarge it...
@ -251,193 +243,151 @@ var SharpActions = actions.Actions({
NOTE: all options are optional. NOTE: all options are optional.
NOTE: this will not overwrite existing images. NOTE: this will not overwrite existing images.
`, `,
core.taskAction('makeResizedImage', function(ticket, images, size, path, options={}){ core.queueHandler('Make resized image',
var that = this
// sanity check...
if(arguments.length < 4){
ticket.reject()
throw new Error('.makeResizedImage(..): '
+'need at least images, size and path.') }
// setup runtime interactions...
//
// NOTE: we will resolve the ticket when we are fully done
// and not on stop...
var STOP = false
ticket
.onmessage('stop', function(){
STOP = true })
.then(function(){
// close progress bar...
// NOTE: if we have multiple tasks let the last one
// close the progress bar...
if(that.tasks.titled(ticket.title).length == 0){
logger
&& logger.emit('close') }
// cleanup...
delete that.__cache_metadata_reading })
var abort = function(){
that.tasks.stop(ticket.title) }
var CHUNK_SIZE = 4
// get/normalize images... // get/normalize images...
//images = images || this.current function(queue, images, size, path, options){
images = images // sanity check...
|| 'all' if(arguments.length < 4){
// keywords... throw new Error('.makeResizedImage(..): '
images = images == 'all' ? +'need at least: images, size and path.') }
this.data.getImages('all') return [
: images == 'current' ? (!images || images == 'all') ?
this.current this.data.getImages('all')
: images : images == 'current' ?
images = images instanceof Array ? [this.current]
images : images instanceof Array ?
: [images] images
// sizing... : [images],
var fit = ...[...arguments].slice(2),
typeof(size) == typeof('str') ? ]},
(size.endsWith('px') ? function(image, size, path, options={}){
'inside' var that = this
: size.endsWith('p') ?
'outside'
: 'inside')
: 'inside'
size = parseInt(size)
// options...
var {
// naming...
name,
pattern,
data,
// file handling... // sizing...
enlarge, var fit =
skipSmaller, typeof(size) == typeof('str') ?
overwrite, (size.endsWith('px') ?
'inside'
: size.endsWith('p') ?
'outside'
: 'inside')
: 'inside'
size = parseInt(size)
// options...
var {
// naming...
name,
data,
// transformations... // file handling...
transform, enlarge,
// XXX not implemented... skipSmaller,
crop, overwrite,
timestamp, // transformations...
logger, transform,
} = options // XXX CROP not implemented...
// defaults... //crop,
pattern = pattern || '%n'
transform = transform === undefined ?
true
: transform
timestamp = timestamp || Date.timeStamp()
logger = logger !== false ?
(logger || this.logger)
: false
logger = logger
&& logger.push('Resize', {onclose: abort})
// backup... timestamp,
// XXX make backup name pattern configurable... //logger,
var backupName = function(to){ } = options
var i = 0 // defaults...
while(fse.existsSync(`${to}.${timestamp}.bak`+ (i || ''))){ name = name || '%n'
i++ } transform = transform === undefined ?
return `${to}.${timestamp}.bak`+ (i || '') } true
: transform
timestamp = timestamp || Date.timeStamp()
return images // backup...
.mapChunks(CHUNK_SIZE, function(gid){ // XXX make backup name pattern configurable...
if(STOP){ var backupName = function(to){
throw Array.STOP('aborted') } var i = 0
while(fse.existsSync(`${to}.${timestamp}.bak`+ (i || ''))){
i++ }
return `${to}.${timestamp}.bak`+ (i || '') }
// skip non-images... // skip non-images...
if(!['image', null, undefined] if(!['image', null, undefined]
.includes(that.images[gid].type)){ .includes(this.images[image].type)){
return false } // XXX what should we return???
return Promise.resolve() }
// paths... // paths...
var source = that.getImagePath(gid) var source = this.getImagePath(image)
var to = pathlib.join( var to = pathlib.resolve(
this.location.path,
pathlib.join(
path, path,
(images.length == 1 && name) ? this.formatImageName(name, image, data || {})))
name
: that.formatImageName(pattern, gid, data || {}))
logger && logger.emit('queued', to) var img = sharp(source)
return (skipSmaller ?
// skip if smaller than size...
img
.metadata()
.then(function(m){
// skip...
if((fit == 'inside'
&& Math.max(m.width, m.height) < size)
|| (fit == 'outside'
&& Math.min(m.width, m.height) < size)){
return }
// continue...
return img })
: Promise.resolve(img))
// prepare to write...
.then(function(img){
return img
&& ensureDir(pathlib.dirname(to))
.then(function(){
// handle existing image...
if(fse.existsSync(to)){
// rename...
if(overwrite == 'backup'){
fse.renameSync(to, backupName(to))
// remove...
} else if(overwrite){
fse.removeSync(to)
// skip...
} else {
return Promise.reject('target exists') } }
var img = sharp(source) // write...
return (skipSmaller ? return img
// skip if smaller than size... .clone()
img // handle transform (.orientation / .flip) and .crop...
.metadata() .run(function(){
.then(function(m){ var img_data = that.images[image]
// skip... if(transform && (img_data.orientation || img_data.flipped)){
if((fit == 'inside' img_data.orientation
&& Math.max(m.width, m.height) < size) && this.rotate(img_data.orientation)
|| (fit == 'outside' img_data.flipped
&& Math.min(m.width, m.height) < size)){ && img_data.flipped.includes('horizontal')
//logger && logger.emit('skipping', gid) && this.flip() }
return } img_data.flipped
// continue... && img_data.flipped.includes('vertical')
return img }) && this.flop()
: Promise.resolve(img)) // XXX CROP
// prepare to write... //if(crop){
.then(function(img){ // // XXX
return img //}
&& ensureDir(pathlib.dirname(to)) })
.then(function(){ .resize({
// handle existing image... width: size,
if(fse.existsSync(to)){ height: size,
// rename... fit: fit,
if(overwrite == 'backup'){ withoutEnlargement: !enlarge,
fse.renameSync(to, backupName(to)) })
// remove... .withMetadata()
} else if(overwrite){ .toFile(to)
fse.removeSync(to) .then(function(){
// skip... // XXX what should we return???
} else { return to }) }) }) })],
//logger && logger.emit('skipping', gid)
return } }
// write...
return img
.clone()
// handle transform (.orientation / .flip) and .crop...
.run(function(){
var img_data = that.images[gid]
if(transform && (img_data.orientation || img_data.flipped)){
img_data.orientation
&& this.rotate(img_data.orientation)
img_data.flipped
&& img_data.flipped.includes('horizontal')
&& this.flip() }
img_data.flipped
&& img_data.flipped.includes('vertical')
&& this.flop()
// XXX
if(crop){
// XXX
}
})
.resize({
width: size,
height: size,
fit: fit,
withoutEnlargement: !enlarge,
})
.withMetadata()
.toFile(to)
.then(function(){
logger
&& logger.emit('done', to)
return img }) }) }) })
.then(function(res){
ticket.resolve(res)
return res == 'aborted' ?
Promise.reject('aborted')
: res }) })],
// XXX move to core.queue... // XXX move to core.queue...
// XXX should this use .makeResizedImage(..) in sync mode???
// ...would be interesting to try a nested queue...
// XXX this does not update image.base_path -- is this correct??? // XXX this does not update image.base_path -- is this correct???
// XXX add support for offloading the processing to a thread/worker... // XXX add support for offloading the processing to a thread/worker...
makePreviews: ['Sharp|File/Make image $previews', makePreviews: ['Sharp|File/Make image $previews',
@ -559,7 +509,8 @@ var SharpActions = actions.Actions({
.replace(/\$RESOLUTION|\$\{RESOLUTION\}/g, parseInt(size)) .replace(/\$RESOLUTION|\$\{RESOLUTION\}/g, parseInt(size))
.replace(/\$GID|\$\{GID\}/g, gid) .replace(/\$GID|\$\{GID\}/g, gid)
.replace(/\$NAME|\$\{NAME\}/g, img.name) .replace(/\$NAME|\$\{NAME\}/g, img.name)
return that.makeResizedImage(gid, size, base, { // XXX do we need this to be sync???
return that.makeResizedImage('sync', gid, size, base, {
name, name,
skipSmaller: true, skipSmaller: true,
transform: false, transform: false,
@ -567,7 +518,8 @@ var SharpActions = actions.Actions({
false false
: logger, : logger,
}) })
.then(function([res]){ // XXX handle errors -- rejected because image exists...
.then(function(res){
i == sizes.length-1 i == sizes.length-1
&& gid_logger && gid_logger.emit('done', gid) && gid_logger && gid_logger.emit('done', gid)

View File

@ -250,7 +250,7 @@ var ProgressActions = actions.Actions({
this.config['progress-done-delay'] || 1000))) } }], this.config['progress-done-delay'] || 1000))) } }],
// handle logger progress... // handle logger progress...
// XXX revise... // XXX show progress after a timeout if still not finished...
handleLogItem: ['- System/', handleLogItem: ['- System/',
function(logger, path, status, ...rest){ function(logger, path, status, ...rest){
var msg = path.join(': ') var msg = path.join(': ')