reworked caching metadata...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-11-05 06:31:13 +03:00
parent 4cd1da4060
commit da63da2f2c
3 changed files with 139 additions and 60 deletions

View File

@ -446,7 +446,7 @@ var ElectronHostActions = actions.Actions({
...this.images[this.current] ...this.images[this.current]
}, function(c){ }, function(c){
electron.clipboard.write({ electron.clipboard.write({
title: that.images.getImageFileName(), bookmark: that.images.getImageFileName(),
text: url, text: url,
// XXX this seems not to work with images with exif // XXX this seems not to work with images with exif
// orientation -- the ig orientation seems to be // orientation -- the ig orientation seems to be

View File

@ -121,7 +121,7 @@ var MetadataReaderActions = actions.Actions({
return new Promise(function(resolve, reject){ return new Promise(function(resolve, reject){
if(!force if(!force
&& !(img.metadata || {}).ImageGridPartialMetadata){ && (img.metadata || {}).ImageGridMetadata == 'full'){
return resolve(img.metadata) } return resolve(img.metadata) }
fs.readFile(full_path, function(err, file){ fs.readFile(full_path, function(err, file){
@ -150,19 +150,20 @@ var MetadataReaderActions = actions.Actions({
reject(data) reject(data)
} else { } else {
// store metadata...
// XXX
// convert to a real dict... // convert to a real dict...
// NOTE: exiftool appears to return an array // NOTE: exiftool appears to return an array
// object rather than an actual dict/object // object rather than an actual dict/object
// and that is not JSON compatible.... // and that is not JSON compatible....
var m = {} that.images[gid].metadata =
Object.keys(data).forEach(function(k){ m[k] = data[k] }) Object.assign(
// XXX do we need to update or overwrite??
that.images[gid].metadata = m that.images[gid].metadata || {},
data,
// XXX {
ImageGridMetadataReader: 'exiftool/ImageGrid',
// mark metadata as full read...
ImageGridMetadata: 'full',
})
that.markChanged that.markChanged
&& that.markChanged('images', [gid]) } && that.markChanged('images', [gid]) }

View File

@ -342,8 +342,8 @@ var SharpActions = actions.Actions({
&& Math.max(m.width, m.height) < size) && Math.max(m.width, m.height) < size)
|| (fit == 'outside' || (fit == 'outside'
&& Math.min(m.width, m.height) < size)){ && Math.min(m.width, m.height) < size)){
logger && logger.emit('skipping', to) skipping(gid)
return false } return }
// continue... // continue...
return img }) return img })
: Promise.resolve(img)) : Promise.resolve(img))
@ -362,8 +362,8 @@ var SharpActions = actions.Actions({
fse.removeSync(to) fse.removeSync(to)
// skip... // skip...
} else { } else {
logger && logger.emit('skipping', to) skipping(gid)
return false } } return } }
// write... // write...
return img return img
@ -508,7 +508,8 @@ var SharpActions = actions.Actions({
if(!base_path){ if(!base_path){
var preview = img.preview = img.preview || {} var preview = img.preview = img.preview || {}
preview[parseInt(size) + 'px'] = name preview[parseInt(size) + 'px'] = name
that.markChanged('images', [gid]) } that.markChanged
&& that.markChanged('images', [gid]) }
return [gid, size, name] }) }) }) return [gid, size, name] }) }) })
.flat()) }], .flat()) }],
@ -519,13 +520,68 @@ var SharpActions = actions.Actions({
// ...and/or have a generic abort protocol triggered when loading... // ...and/or have a generic abort protocol triggered when loading...
// ...use task queue??? // ...use task queue???
// XXX make each section optional... // XXX make each section optional...
// XXX revise name... cacheMetadata: ['- Sharp|Image/',
cacheImageMetadata: ['- Sharp|Image/', core.doc`Cache metadata
core.doc`
Cache metadata for current image...
.cacheMetadata()
.cacheMetadata('current')
-> promise([ gid | null ])
Force cache metadata for current image...
.cacheMetadata(true)
.cacheMetadata('current', true)
-> promise([ gid | null ])
Cache metadata for all images...
.cacheMetadata('all')
-> promise([ gid | null, .. ])
Force cache metadata for all images...
.cacheMetadata('all', true)
-> promise([ gid | null, .. ])
Cache metadata for specific images...
.cacheMetadata([ gid, .. ])
-> promise([ gid | null, .. ])
Force cache metadata for specific images...
.cacheMetadata([ gid, .. ], true)
-> promise([ gid | null, .. ])
NOTE: this will effectively update metadata format to the new spec...
`, `,
function(images, logger){ function(images, logger){
var that = this var that = this
// handle logging and processing list...
// NOTE: these will maintain .__metadata_reading helping
// avoid processing an image more than once at the same
// time...
var done = function(gid, msg){
logger && logger.emit(msg || 'done', gid)
if(that.__metadata_reading){
that.__metadata_reading.delete(gid)
if(that.__metadata_reading.size == 0){
delete that.__metadata_reading } }
return gid }
var skipping = function(gid){
return done(gid, 'skipping') }
var force = false
if(images === true){
force = true
images = null
} else if(logger === true){
force = true
logger = arguments[2] }
// NOTE: we are caching this to avoid messing things up when
// loading before this was finished...
var cached_images = this.images
// get/normalize images... // get/normalize images...
//images = images || this.current //images = images || this.current
images = images images = images
@ -541,9 +597,12 @@ var SharpActions = actions.Actions({
: images == 'current' ? : images == 'current' ?
this.current this.current
: images : images
images = images instanceof Array ? images = (images instanceof Array ?
images images
: [images] : [images])
.filter(function(gid){
return !that.__metadata_reading
|| !that.__metadata_reading.has(gid) })
logger = logger !== false ? logger = logger !== false ?
(logger || this.logger) (logger || this.logger)
@ -551,13 +610,6 @@ var SharpActions = actions.Actions({
logger = logger && logger.push('Caching image metadata') logger = logger && logger.push('Caching image metadata')
logger && logger.emit('queued', images) logger && logger.emit('queued', images)
// NOTE: we are caching this to avoid messing things up when
// loading before this was finished...
var cached_images = this.images
var loaded = this.ribbons
&& new Set(this.ribbons.getImageGIDs())
/*/ XXX set this to tmp for .location.load =='loadImages' /*/ XXX set this to tmp for .location.load =='loadImages'
// XXX add preview cache directory... // XXX add preview cache directory...
// - user defined path // - user defined path
@ -573,36 +625,62 @@ var SharpActions = actions.Actions({
return images return images
.mapChunks(function(gid){ .mapChunks(function(gid){
var img = cached_images[gid]
var path = img && that.getImagePath(gid)
;(that.__metadata_reading =
that.__metadata_reading || new Set())
.add(gid)
// skip...
if(!(img && path
&& (force
// high priority must be preset...
|| (img.orientation == null
&& img.flipped == null)
// update metadata...
|| (img.metadata || {}).ImageGridMetadata == null))){
skipping(gid)
return }
return sharp(that.getImagePath(gid)) return sharp(that.getImagePath(gid))
.metadata() .metadata()
.catch(function(){ .catch(function(){
logger && logger.emit('skipping', gid) }) skipping(gid) })
.then(function(metadata){ .then(function(metadata){
// XXX what should we return in case of an error??? // no metadata...
if(metadata == null){ if(metadata == null){
skipping(gid)
return } return }
var img = cached_images[gid]
var o = normalizeOrientation(metadata.orientation) var o = normalizeOrientation(metadata.orientation)
// NOTE: we need to set orientation to something ;(force || img.orientation == null)
// or we'll check it again and again... // NOTE: we need to set orientation to something
img.orientation = o.orientation || 0 // or we'll check it again and again...
img.flipped = o.flipped && (img.orientation = o.orientation || 0)
;(force || img.flipped == null)
&& (img.flipped = o.flipped)
// mark metadata as partially read...
// NOTE: this will intentionally overwrite the
// previous reader mark/mode...
img.metadata =
Object.assign(
img.metadata || {},
{
ImageGridMetadataReader: 'sharp/exif-reader/ImageGrid',
// mark metadata as partial read...
// NOTE: partial metadata will get reread by
// the metadata feature upon request...
ImageGridMetadata: 'partial',
})
// read the metadata... // read the metadata...
var exif = metadata.exif var exif = metadata.exif
&& exifReader(metadata.exif) && exifReader(metadata.exif)
exif exif
&& Object.assign( && Object.assign(
(img.metadata = img.metadata || {}), img.metadata,
exifReader2exiftool(exif), exifReader2exiftool(exif))
// mark metadata as partial read...
//
// NOTE: partial metadata will get reread by
// the metadata feature upon request...
// XXX revise name...
{ ImageGridPartialMetadata: true })
// if image too large, generate preview(s)... // if image too large, generate preview(s)...
// XXX EXPERIMENTAL... // XXX EXPERIMENTAL...
@ -619,16 +697,16 @@ var SharpActions = actions.Actions({
base_path, base_path,
logger) } logger) }
that.markChanged('images', [gid]) that.markChanged
&& that.markChanged('images', [gid])
logger && logger.emit('done', gid) that.ribbons
// update loaded image to use the orientation...
loaded
&& loaded.has(gid)
&& that.ribbons.updateImage(gid) && that.ribbons.updateImage(gid)
return gid }) }) }], return done(gid) }) }) }],
cacheAllMetadata: ['- Sharp|Image/',
core.doc`Cache all metadata
NOTE: this is a shorthand to .cacheMetadata('all', ..)`,
'cacheMetadata: "all" ...'],
}) })
@ -653,7 +731,7 @@ module.Sharp = core.ImageGridFeatures.Feature({
// XXX this is best done in a thread + needs to be abortable (on .load(..))... // XXX this is best done in a thread + needs to be abortable (on .load(..))...
['loadImages', ['loadImages',
function(){ function(){
this.cacheImageMetadata('all') }], this.cacheMetadata('all') }],
//*/ //*/
// set orientation if not defined... // set orientation if not defined...
@ -667,12 +745,12 @@ module.Sharp = core.ImageGridFeatures.Feature({
// function(gid){ // function(gid){
['updateImage', ['updateImage',
function(_, gid){ function(_, gid){
var img = this.images[gid] var that = this
img this.cacheMetadata(gid, false)
&& img.orientation == null .then(function([res]){
&& this.cacheImageMetadata(gid, false) res
&& this.logger && that.logger
&& this.logger.emit('Caching metadata for', gid) }], && that.logger.emit('Cached metadata for', gid) }) }],
// XXX need to: // XXX need to:
// - if image too large to set the preview to "loading..." // - if image too large to set the preview to "loading..."