mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-29 10:20:08 +00:00
added image resizing to export, still needs UI and details...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
43f0499843
commit
a34591065a
@ -2082,8 +2082,10 @@ var FileSystemWriterActions = actions.Actions({
|
||||
// XXX handle .image.path and other stack files...
|
||||
// XXX local collections???
|
||||
//
|
||||
// XXX BUG: seems to ignore max_size...
|
||||
// ...'preview-size' does not affect the base image size...
|
||||
// XXX BUG: max_size is measured by preview size and ignores main
|
||||
// image size...
|
||||
// ...this results in exported images being previews ONLY IF
|
||||
// they have previews larger than max_size...
|
||||
// XXX BUG: this does not remove previews correctly...
|
||||
// to reproduce:
|
||||
// open: L:\media\img\my\2019
|
||||
@ -2123,10 +2125,14 @@ var FileSystemWriterActions = actions.Actions({
|
||||
path = path || './exported'
|
||||
path = util.normalizePath(path)
|
||||
|
||||
max_size = parseInt(max_size || settings['preview-size-limit']) || null
|
||||
max_size = parseInt(max_size
|
||||
|| settings['preview-size-limit'])
|
||||
|| null
|
||||
// XXX make this dependant on max_size....
|
||||
include_orig = include_orig || true
|
||||
|
||||
var resize = max_size && this.makeResizedImage
|
||||
|
||||
// clear/backup target...
|
||||
clean_target_dir = clean_target_dir === undefined ?
|
||||
settings['clean-target']
|
||||
@ -2258,8 +2264,12 @@ var FileSystemWriterActions = actions.Actions({
|
||||
// we are using as the primary image to
|
||||
// save space...
|
||||
: null })
|
||||
// add primary image...
|
||||
.concat(include_orig && img.path ?
|
||||
// add primary image (copy)...
|
||||
// XXX check if any of the previews/main images
|
||||
// matches the size and copy instead of resize...
|
||||
.concat((!resize
|
||||
&& include_orig
|
||||
&& img.path) ?
|
||||
[[
|
||||
(replace_orig && max != null) ?
|
||||
// replace the base image with the
|
||||
@ -2306,18 +2316,25 @@ var FileSystemWriterActions = actions.Actions({
|
||||
// XXX do we queue these or let the OS handle it???
|
||||
// ...needs testing, if node's fs queues the io
|
||||
// internally then we do not need to bother...
|
||||
queue.push(copy(from, to)
|
||||
.then(function(){
|
||||
logger && logger.emit('done', to) })
|
||||
.catch(function(err){
|
||||
logger && logger.emit('error', err) })) } }) } })
|
||||
queue
|
||||
.push(copy(from, to)
|
||||
.then(function(){
|
||||
logger && logger.emit('done', to) })
|
||||
.catch(function(err){
|
||||
logger && logger.emit('error', err) })) } }) } })
|
||||
|
||||
// prep the index...
|
||||
// primary image (resize)...
|
||||
resize
|
||||
&& include_orig
|
||||
&& queue
|
||||
.push(this.makeResizedImage(gids, max_size, path, { logger }))
|
||||
|
||||
// index...
|
||||
var index = this.prepareIndexForWrite(json, true)
|
||||
|
||||
// NOTE: if we are to use .saveIndex(..) here, do not forget
|
||||
// to reset .changes
|
||||
queue.push(
|
||||
queue
|
||||
.push(
|
||||
file.writeIndex(
|
||||
index.index,
|
||||
index_path,
|
||||
@ -2335,8 +2352,7 @@ var FileSystemWriterActions = actions.Actions({
|
||||
|
||||
return Promise.all(queue) }],
|
||||
|
||||
// XXX BUG: seems to ignore max_size...
|
||||
// ...'preview-size' does not affect the base image size...
|
||||
// XXX ASAP add option to control copy/resize -> .makeResizedImage(..)...
|
||||
// XXX might also be good to save/load the export options to .ImageGrid-export.json
|
||||
// XXX resolve env variables in path... (???)
|
||||
// XXX make custom previews (option)...
|
||||
@ -2458,8 +2474,14 @@ var FileSystemWriterActions = actions.Actions({
|
||||
&& !fse.existsSync(to)
|
||||
&& outputFile(to, img.text || '')
|
||||
|
||||
// normal images...
|
||||
// normal images (resize)...
|
||||
} else if(that.makeResizedImage){
|
||||
// XXX can we make this batch...
|
||||
return that.makeResizedImage(gid, size, img_dir, { name, logger })
|
||||
|
||||
// normal images (copy)...
|
||||
} else {
|
||||
//*/
|
||||
// NOTE: we are intentionally losing image dir
|
||||
// name here -- we do not need to preserve
|
||||
// topology when exporting...
|
||||
@ -2470,10 +2492,6 @@ var FileSystemWriterActions = actions.Actions({
|
||||
+'/'
|
||||
+ that.images.getBestPreview(gid, size).url
|
||||
|
||||
|
||||
// XXX see if we need to make a preview (sharp)
|
||||
// XXX
|
||||
|
||||
var to = img_dir +'/'+ name
|
||||
|
||||
logger && logger.emit('queued', to)
|
||||
|
||||
@ -34,6 +34,7 @@ if(typeof(process) != 'undefined'){
|
||||
/*********************************************************************/
|
||||
|
||||
if(typeof(process) != 'undefined'){
|
||||
var copy = file.denodeify(fse.copy)
|
||||
var ensureDir = file.denodeify(fse.ensureDir)
|
||||
}
|
||||
|
||||
@ -112,15 +113,184 @@ var SharpActions = actions.Actions({
|
||||
}
|
||||
})
|
||||
|
||||
this.previewConstructorWorker.__post_handlers = {}
|
||||
}],
|
||||
this.previewConstructorWorker.__post_handlers = {} }],
|
||||
stopPreviewWorker: ['- Sharp/',
|
||||
function(){
|
||||
this.previewConstructorWorker && this.previewConstructorWorker.kill()
|
||||
delete this.previewConstructorWorker
|
||||
}],
|
||||
delete this.previewConstructorWorker }],
|
||||
|
||||
// XXX should this resize up??? ...option???
|
||||
// XXX add transform/crop support...
|
||||
// XXX revise logging...
|
||||
makeResizedImage: ['- Image/',
|
||||
core.doc`Make resized image(s)...
|
||||
|
||||
.makeResizedImage(gid, size, path[, options])
|
||||
.makeResizedImage(gids, size, path[, options])
|
||||
-> promise
|
||||
|
||||
|
||||
Image size formats:
|
||||
500px - resize to make image's *largest* dimension 500 pixels (default).
|
||||
500p - resize to make image's *smallest* dimension 500 pixels.
|
||||
500 - same as 500px
|
||||
|
||||
|
||||
options format:
|
||||
{
|
||||
// output image name...
|
||||
//
|
||||
// Used if processing a single image, ignored otherwise.
|
||||
name: <str>,
|
||||
|
||||
// image name pattern and data...
|
||||
//
|
||||
// NOTE: for more info on pattern see: .formatImageName(..)
|
||||
pattern: <str>,
|
||||
data: { .. },
|
||||
|
||||
// overwrite, backup or skip (default) existing images...
|
||||
//
|
||||
// default: null / false
|
||||
overwrite: true | 'backup' | false,
|
||||
|
||||
// XXX not implemented...
|
||||
transform: ...,
|
||||
crop: ...,
|
||||
|
||||
logger: ...
|
||||
, }
|
||||
|
||||
|
||||
NOTE: this will not overwrite existing images.
|
||||
`,
|
||||
function(images, size, path, options={}){
|
||||
var that = this
|
||||
|
||||
// sanity check...
|
||||
if(arguments.length < 3){
|
||||
throw new Error('.makeResizedImage(..): '
|
||||
+'need at least images, size and path.') }
|
||||
// get/normalize images...
|
||||
//images = images || this.current
|
||||
images = images
|
||||
|| 'all'
|
||||
// keywords...
|
||||
images = images == 'all' ?
|
||||
this.data.getImages('all')
|
||||
: images == 'current' ?
|
||||
this.current
|
||||
: images
|
||||
images = images instanceof Array ?
|
||||
images
|
||||
: [images]
|
||||
// sizing...
|
||||
var fit =
|
||||
typeof(size) == typeof('str') ?
|
||||
(size.endsWith('px') ?
|
||||
'inside'
|
||||
: size.endsWith('p') ?
|
||||
'outside'
|
||||
: 'inside')
|
||||
: 'inside'
|
||||
size = parseInt(size)
|
||||
// options...
|
||||
var {
|
||||
// naming...
|
||||
name,
|
||||
pattern,
|
||||
data,
|
||||
// file handling...
|
||||
overwrite,
|
||||
// transformations...
|
||||
// XXX not implemented...
|
||||
transform,
|
||||
// XXX not implemented...
|
||||
crop,
|
||||
|
||||
logger,
|
||||
} = options
|
||||
// defaults...
|
||||
pattern = pattern || '%n'
|
||||
/* XXX
|
||||
transform = transform === undefined ?
|
||||
true
|
||||
: transform
|
||||
//*/
|
||||
logger = logger || this.logger
|
||||
logger = logger && logger.push('Resize')
|
||||
|
||||
var timestamp = Date.timeStamp()
|
||||
|
||||
return Promise.all(images
|
||||
.map(function(gid){
|
||||
// skip non-images...
|
||||
if(that.images[gid].type != undefined){
|
||||
return }
|
||||
|
||||
// paths...
|
||||
var source = that.getImagePath(gid)
|
||||
var to = pathlib.join(
|
||||
path,
|
||||
(images.length == 1 && name) ?
|
||||
name
|
||||
: that.formatImageName(pattern, gid, data || {}))
|
||||
|
||||
logger && logger.emit('queued', to)
|
||||
|
||||
// existing image...
|
||||
if(fse.existsSync(to)){
|
||||
// rename...
|
||||
if(overwrite == 'backup'){
|
||||
var i = 0
|
||||
while(fse.existsSync(`${to}.${timestamp}'-bak`+ (i || ''))){
|
||||
i++ }
|
||||
fse.renameSync(
|
||||
to,
|
||||
fse.existsSync(`${to}.${timestamp}'-bak`+ (i || '')))
|
||||
// remove...
|
||||
} else if(overwrite){
|
||||
fse.removeSync(to)
|
||||
// skip...
|
||||
} else {
|
||||
logger && logger.emit('skipping', to)
|
||||
return } }
|
||||
|
||||
return ensureDir(pathlib.dirname(to))
|
||||
.then(function(){
|
||||
return sharp(source)
|
||||
.clone()
|
||||
// handle transform (.orientation / .flip) and .crop...
|
||||
.run(function(){
|
||||
// XXX
|
||||
if(transform || crop){
|
||||
throw new Error('.makeResizedImage(..): '
|
||||
+[
|
||||
transform ? 'transform' : [],
|
||||
crop ? 'crop' : [],
|
||||
].flat().join(' and ')
|
||||
+' not implemented...') }
|
||||
// XXX need clear spec defining what
|
||||
// order transforms are applied
|
||||
// and in which coordinates we
|
||||
// crop (i.e. pre/post transform)...
|
||||
if(transform){
|
||||
}
|
||||
if(crop){
|
||||
}
|
||||
})
|
||||
.resize({
|
||||
width: size,
|
||||
height: size,
|
||||
fit: fit,
|
||||
})
|
||||
.withMetadata()
|
||||
.toFile(to)
|
||||
.then(function(){
|
||||
logger
|
||||
&& logger.emit('done', to) })}) })) }],
|
||||
|
||||
// XXX use .makeResizedImage(..)
|
||||
// XXX should this account for non-jpeg images???
|
||||
// XXX BUG?: this breaks on PNG images...
|
||||
// XXX log: count gids and not specific images...
|
||||
@ -150,12 +320,17 @@ var SharpActions = actions.Actions({
|
||||
|
||||
// get/normalize images...
|
||||
//images = images || this.current
|
||||
images = images || 'all'
|
||||
images = images
|
||||
|| 'all'
|
||||
// keywords...
|
||||
images = images == 'all' ? this.data.getImages('all')
|
||||
: images == 'current' ? this.current
|
||||
images = images == 'all' ?
|
||||
this.data.getImages('all')
|
||||
: images == 'current' ?
|
||||
this.current
|
||||
: images
|
||||
images = images instanceof Array ? images : [images]
|
||||
images = images instanceof Array ?
|
||||
images
|
||||
: [images]
|
||||
|
||||
//
|
||||
// Format:
|
||||
@ -203,8 +378,7 @@ var SharpActions = actions.Actions({
|
||||
.unique()
|
||||
|
||||
} else {
|
||||
sizes = cfg_sizes
|
||||
}
|
||||
sizes = cfg_sizes }
|
||||
|
||||
var path_tpl = that.config['preview-path-template']
|
||||
.replace(/\$INDEX|\$\{INDEX\}/g, that.config['index-dir'] || '.ImageGrid')
|
||||
@ -280,8 +454,7 @@ var SharpActions = actions.Actions({
|
||||
sizes,
|
||||
base_path,
|
||||
path_tpl,
|
||||
post_handler) }))}
|
||||
}],
|
||||
post_handler) }))} }],
|
||||
})
|
||||
|
||||
|
||||
|
||||
@ -80,8 +80,7 @@ function(images, sizes, base_path, target_tpl, callback){
|
||||
.map(function(res){
|
||||
// skip if image is smaller than res...
|
||||
if(res >= orig_res){
|
||||
return
|
||||
}
|
||||
return }
|
||||
|
||||
var rel = target
|
||||
.replace(/\$RESOLUTION|\$\{RESOLUTION\}/g, res)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user