| 
									
										
										
										
											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') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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') | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 	var exifReader = requirejs('exif-reader') | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | // helpers...
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | if(typeof(process) != 'undefined'){ | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 	var copy = file.denodeify(fse.copy) | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	var ensureDir = file.denodeify(fse.ensureDir) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var normalizeOrientation = | 
					
						
							|  |  |  | module.normalizeOrientation = | 
					
						
							|  |  |  | function(orientation){ | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 	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], | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 	} } | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Convert image metadata from exif-reader output to format compatible 
 | 
					
						
							|  |  |  | // with exiftool (features/metadata.js)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							|  |  |  | // 		// simple key-key pair...
 | 
					
						
							|  |  |  | // 		'path.to.value': 'output-key',
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// key with value handler...
 | 
					
						
							|  |  |  | // 		'path.to.other.value': ['output-key', handler],
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// alias to handler...
 | 
					
						
							|  |  |  | // 		'path.to.yet.another.value': ['output-key', 'path.to.other.value'],
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | var EXIF_FORMAT = | 
					
						
							|  |  |  | module.EXIF_FORMAT = { | 
					
						
							|  |  |  | 	// camera / lens...
 | 
					
						
							|  |  |  | 	'image.Make': 'make', | 
					
						
							|  |  |  | 	'image.Model': 'cameraModelName', | 
					
						
							|  |  |  | 	'image.Software': 'software', | 
					
						
							|  |  |  | 	'exif.LensModel': 'lensModel', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// exposure...
 | 
					
						
							|  |  |  | 	'exif.ISO': 'iso', | 
					
						
							| 
									
										
										
										
											2020-11-29 16:52:22 +03:00
										 |  |  | 	'exif.FNumber': [ | 
					
						
							|  |  |  | 		'fNumber',  | 
					
						
							|  |  |  | 		function(v){  | 
					
						
							|  |  |  | 			return 'f/'+v }], | 
					
						
							|  |  |  | 	'exif.ExposureTime': [ | 
					
						
							|  |  |  | 		'exposureTime', | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 		// NOTE: this is a bit of a brute-fore approach but for shutter 
 | 
					
						
							|  |  |  | 		// 		speeds this should not matter...
 | 
					
						
							|  |  |  | 		function(v){ | 
					
						
							|  |  |  | 			if(v > 0.5){ | 
					
						
							|  |  |  | 				return ''+ v } | 
					
						
							|  |  |  | 			for(var d = 1; (v * d) % 1 != 0; d++){} | 
					
						
							|  |  |  | 			return (v * d) +'/'+ d }], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// dates...
 | 
					
						
							| 
									
										
										
										
											2020-11-29 16:52:22 +03:00
										 |  |  | 	'exif.DateTimeOriginal': [ | 
					
						
							|  |  |  | 		'date/timeOriginal', | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 		function(v){ | 
					
						
							|  |  |  | 			return v.toShortDate() }], | 
					
						
							| 
									
										
										
										
											2020-11-29 16:52:22 +03:00
										 |  |  | 	'image.ModifyDate': [ | 
					
						
							|  |  |  | 		'modifyDate',  | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 		'exif.DateTimeOriginal'], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// IPCT...
 | 
					
						
							|  |  |  | 	'image.Artist': 'artist', | 
					
						
							|  |  |  | 	'image.Copyright': 'copyright', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX anything else???
 | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 17:48:44 +03:00
										 |  |  | // NOTE: this only reads the .rating from xmp...
 | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | var exifReader2exiftool =  | 
					
						
							|  |  |  | module.exifReader2exiftool = | 
					
						
							| 
									
										
										
										
											2020-11-10 17:48:44 +03:00
										 |  |  | function(exif, xmp){ | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 	return Object.entries(EXIF_FORMAT) | 
					
						
							| 
									
										
										
										
											2020-11-10 17:48:44 +03:00
										 |  |  | 		// handle exif...
 | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 		.reduce(function(res, [path, to]){ | 
					
						
							|  |  |  | 			var handler | 
					
						
							|  |  |  | 			;[to, handler] = to instanceof Array ? | 
					
						
							|  |  |  | 				to | 
					
						
							|  |  |  | 				: [to] | 
					
						
							|  |  |  | 			// resolve handler reference/alias...
 | 
					
						
							|  |  |  | 			while(typeof(handler) == typeof('str')){ | 
					
						
							|  |  |  | 				handler = EXIF_FORMAT[handler][1] } | 
					
						
							|  |  |  | 			// resolve source path...
 | 
					
						
							|  |  |  | 			var value = path.split(/\./g) | 
					
						
							|  |  |  | 				.reduce(function(res, e){  | 
					
						
							| 
									
										
										
										
											2020-11-10 17:48:44 +03:00
										 |  |  | 					return res && res[e] }, exif) | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 			// set the value...
 | 
					
						
							|  |  |  | 			if(value !== undefined){ | 
					
						
							|  |  |  | 				res[to] = handler ? | 
					
						
							|  |  |  | 					handler(value) | 
					
						
							|  |  |  | 					: value } | 
					
						
							|  |  |  | 			return res }, {}) | 
					
						
							|  |  |  | 		// handle xmp...
 | 
					
						
							|  |  |  | 		.run(function(){ | 
					
						
							| 
									
										
										
										
											2020-11-10 17:48:44 +03:00
										 |  |  | 			var rating = xmp  | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 				// NOTE: we do not need the full XML 
 | 
					
						
							|  |  |  | 				// 		fluff here, just get some values...
 | 
					
						
							|  |  |  | 				&& parseInt( | 
					
						
							| 
									
										
										
										
											2020-11-10 17:48:44 +03:00
										 |  |  | 					(xmp.toString() | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 							.match(/(?<match><(xmp:Rating)[^>]*>(?<value>.*)<\/\2>)/i)  | 
					
						
							|  |  |  | 						|| {groups: {}}) | 
					
						
							|  |  |  | 					.groups.value) | 
					
						
							|  |  |  | 			rating | 
					
						
							|  |  |  | 				&& (this.rating = rating) }) } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +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, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 18:13:52 +03:00
										 |  |  | 		// can be:
 | 
					
						
							|  |  |  | 		// 	'gids'
 | 
					
						
							|  |  |  | 		// 	'files'
 | 
					
						
							|  |  |  | 		'preview-progress-mode': 'gids', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 05:33:29 +03:00
										 |  |  | 		'preview-generate-threshold': 2000, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 	// XXX revise return values...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 	// XXX make backup name pattern configurable...
 | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 	// XXX CROP ready for crop support...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 	makeResizedImage: ['- Image/', | 
					
						
							|  |  |  | 		core.doc`Make resized image(s)...
 | 
					
						
							| 
									
										
										
										
											2016-05-23 17:54:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 			.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: | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 				// output image name / name pattern...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 				//
 | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 				// NOTE: for multiple images this should be a pattern and not an
 | 
					
						
							|  |  |  | 				// 		explicit name...
 | 
					
						
							|  |  |  | 				// NOTE: if not given this defaults to: "%n"
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 				name: null | <str>, | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 				// image name pattern data...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 				//
 | 
					
						
							|  |  |  | 				// NOTE: for more info on pattern see: .formatImageName(..)
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 				data: null | { .. }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// if true and image is smaller than size enlarge it...
 | 
					
						
							|  |  |  | 				// 
 | 
					
						
							|  |  |  | 				// default: null / false
 | 
					
						
							|  |  |  | 				enlarge: null | true, | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// overwrite, backup or skip (default) existing images...
 | 
					
						
							|  |  |  | 				//
 | 
					
						
							|  |  |  | 				// default: null / false
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 				overwrite: null | true | 'backup', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// if true do not write an image if it's smaller than size...
 | 
					
						
							|  |  |  | 				// 
 | 
					
						
							|  |  |  | 				// default: null / false
 | 
					
						
							|  |  |  | 				skipSmaller: null | true, | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// XXX not implemented...
 | 
					
						
							|  |  |  | 				transform: ..., | 
					
						
							|  |  |  | 				crop: ..., | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-31 02:10:27 +03:00
										 |  |  | 				timestamp: ..., | 
					
						
							|  |  |  | 				logger: ..., | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | ,			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 		NOTE: all options are optional. | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 		NOTE: this will not overwrite existing images. | 
					
						
							|  |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 		core.queueHandler('Make resized image',  | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 			// get/normalize images...
 | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 			function(queue, images, size, path, options){ | 
					
						
							|  |  |  | 				// sanity check...
 | 
					
						
							|  |  |  | 				if(arguments.length < 4){ | 
					
						
							|  |  |  | 					throw new Error('.makeResizedImage(..): ' | 
					
						
							|  |  |  | 						+'need at least: images, size and path.') } | 
					
						
							|  |  |  | 				return [ | 
					
						
							|  |  |  | 					(!images || images == 'all') ?  | 
					
						
							|  |  |  | 							this.data.getImages('all') | 
					
						
							|  |  |  | 						: images == 'current' ?  | 
					
						
							|  |  |  | 							[this.current] | 
					
						
							|  |  |  | 						: images instanceof Array ?  | 
					
						
							|  |  |  | 							images  | 
					
						
							|  |  |  | 						: [images], | 
					
						
							|  |  |  | 					...[...arguments].slice(2), | 
					
						
							|  |  |  | 				]}, | 
					
						
							|  |  |  | 			function(image, size, path, options={}){ | 
					
						
							|  |  |  | 				var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// sizing...
 | 
					
						
							|  |  |  | 				var fit =  | 
					
						
							|  |  |  | 					typeof(size) == typeof('str') ? | 
					
						
							|  |  |  | 						(size.endsWith('px') ? | 
					
						
							|  |  |  | 							'inside' | 
					
						
							|  |  |  | 						: size.endsWith('p') ? | 
					
						
							|  |  |  | 							'outside' | 
					
						
							|  |  |  | 						: 'inside') | 
					
						
							|  |  |  | 					: 'inside' | 
					
						
							|  |  |  | 				size = parseInt(size) | 
					
						
							|  |  |  | 				// options...
 | 
					
						
							|  |  |  | 				var { | 
					
						
							|  |  |  | 					// naming...
 | 
					
						
							|  |  |  | 					name,  | 
					
						
							|  |  |  | 					data,  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// file handling...
 | 
					
						
							|  |  |  | 					enlarge, | 
					
						
							|  |  |  | 					skipSmaller, | 
					
						
							|  |  |  | 					overwrite, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// transformations...
 | 
					
						
							|  |  |  | 					transform,  | 
					
						
							|  |  |  | 					// XXX CROP not implemented...
 | 
					
						
							|  |  |  | 					//crop, 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					timestamp, | 
					
						
							|  |  |  | 					//logger, 
 | 
					
						
							|  |  |  | 				} = options | 
					
						
							|  |  |  | 				// defaults...
 | 
					
						
							|  |  |  | 				name = name || '%n' | 
					
						
							|  |  |  | 				transform = transform === undefined ?  | 
					
						
							|  |  |  | 					true  | 
					
						
							|  |  |  | 					: transform | 
					
						
							|  |  |  | 				timestamp = timestamp || Date.timeStamp() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// backup...
 | 
					
						
							|  |  |  | 				// XXX make backup name pattern configurable...
 | 
					
						
							|  |  |  | 				var backupName = function(to){ | 
					
						
							|  |  |  | 					var i = 0 | 
					
						
							|  |  |  | 					while(fse.existsSync(`${to}.${timestamp}.bak`+ (i || ''))){ | 
					
						
							|  |  |  | 						i++ } | 
					
						
							|  |  |  | 					return `${to}.${timestamp}.bak`+ (i || '') } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// skip non-images...
 | 
					
						
							|  |  |  | 				if(!['image', null, undefined] | 
					
						
							|  |  |  | 						.includes(this.images[image].type)){ | 
					
						
							|  |  |  | 					// XXX what should we return???
 | 
					
						
							|  |  |  | 					return Promise.resolve() } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// paths...
 | 
					
						
							|  |  |  | 				var source = this.getImagePath(image) | 
					
						
							|  |  |  | 				var to = pathlib.resolve( | 
					
						
							|  |  |  | 					this.location.path, | 
					
						
							|  |  |  | 					pathlib.join( | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 						path,  | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 						this.formatImageName(name, image, data || {}))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				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') } } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									// write...
 | 
					
						
							|  |  |  | 									return img | 
					
						
							|  |  |  | 										.clone() | 
					
						
							|  |  |  | 										// handle transform (.orientation / .flip) and .crop...
 | 
					
						
							|  |  |  | 										.run(function(){ | 
					
						
							|  |  |  | 											var img_data = that.images[image] | 
					
						
							|  |  |  | 											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 CROP
 | 
					
						
							|  |  |  | 											//if(crop){
 | 
					
						
							|  |  |  | 											//	// XXX
 | 
					
						
							|  |  |  | 											//}
 | 
					
						
							|  |  |  | 										}) | 
					
						
							|  |  |  | 										.resize({ | 
					
						
							|  |  |  | 											width: size, | 
					
						
							|  |  |  | 											height: size, | 
					
						
							|  |  |  | 											fit: fit, | 
					
						
							|  |  |  | 											withoutEnlargement: !enlarge, | 
					
						
							|  |  |  | 										}) | 
					
						
							|  |  |  | 										.withMetadata() | 
					
						
							|  |  |  | 										.toFile(to)  | 
					
						
							|  |  |  | 										.then(function(){ | 
					
						
							|  |  |  | 											// XXX what should we return???
 | 
					
						
							|  |  |  | 											return to }) }) }) })], | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 05:22:57 +03:00
										 |  |  | 	// XXX move to core.queue...
 | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 	// XXX should this use .makeResizedImage(..) in sync mode???
 | 
					
						
							|  |  |  | 	// 		...would be interesting to try a nested queue...
 | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 	// XXX this does not update image.base_path -- is this correct???
 | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 	// XXX add support for offloading the processing to a thread/worker...
 | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 	makePreviews: ['Sharp|File/Make image $previews', | 
					
						
							|  |  |  | 		core.doc`Make image previews
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Make previews for all images... | 
					
						
							|  |  |  | 			.makePreviews() | 
					
						
							|  |  |  | 			.makePreviews('all') | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 				-> promise | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			Make previews for current image... | 
					
						
							|  |  |  | 			.makePreviews('current') | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 				-> promise | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			Make previews for specific image(s)... | 
					
						
							|  |  |  | 			.makePreviews(gid) | 
					
						
							|  |  |  | 			.makePreviews([gid, gid, ..]) | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 				-> promise | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Make previews of images, size and at base_path... | 
					
						
							|  |  |  | 			.makePreviews(images, sizes) | 
					
						
							|  |  |  | 			.makePreviews(images, sizes, base_path) | 
					
						
							|  |  |  | 				-> promise | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 		NOTE: if base_path is given .images will not be updated with new  | 
					
						
							|  |  |  | 			preview paths... | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 		core.taskAction('makePreviews', function(ticket, images, sizes, base_path, logger){ | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 			// 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){ | 
					
						
							|  |  |  | 						gid_logger | 
					
						
							|  |  |  | 							&& gid_logger.emit('close') | 
					
						
							|  |  |  | 						logger  | 
					
						
							|  |  |  | 							&& logger.emit('close') } | 
					
						
							|  |  |  | 					// cleanup...
 | 
					
						
							|  |  |  | 					delete that.__cache_metadata_reading }) | 
					
						
							|  |  |  | 			var abort = function(){ | 
					
						
							|  |  |  | 				that.tasks.stop(ticket.title) } | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 			var CHUNK_SIZE = 4 | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 			var logger_mode = this.config['preview-progress-mode'] || 'gids' | 
					
						
							|  |  |  | 			logger = logger !== false ? | 
					
						
							|  |  |  | 				(logger || this.logger) | 
					
						
							|  |  |  | 				: false | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 			var gid_logger = logger  | 
					
						
							|  |  |  | 				&& logger.push('Images',  | 
					
						
							|  |  |  | 					{onclose: abort}) | 
					
						
							|  |  |  | 			logger = logger  | 
					
						
							|  |  |  | 				&& logger.push('Previews',  | 
					
						
							|  |  |  | 					{onclose: abort}) | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 			// get/normalize images...
 | 
					
						
							|  |  |  | 			images = images  | 
					
						
							|  |  |  | 				|| 'all' | 
					
						
							|  |  |  | 			// keywords...
 | 
					
						
							|  |  |  | 			images = images == 'all' ?  | 
					
						
							|  |  |  | 					this.data.getImages('all') | 
					
						
							|  |  |  | 				: images == 'current' ?  | 
					
						
							|  |  |  | 					this.current | 
					
						
							|  |  |  | 				: images | 
					
						
							|  |  |  | 			images = images instanceof Array ?  | 
					
						
							|  |  |  | 				images  | 
					
						
							|  |  |  | 				: [images] | 
					
						
							|  |  |  | 			// get/normalize sizes....
 | 
					
						
							|  |  |  | 			var cfg_sizes = this.config['preview-sizes'].slice() || [] | 
					
						
							|  |  |  | 			cfg_sizes | 
					
						
							|  |  |  | 				.sort() | 
					
						
							|  |  |  | 				.reverse() | 
					
						
							|  |  |  | 			// XXX revise...
 | 
					
						
							|  |  |  | 			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 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var path_tpl = that.config['preview-path-template'] | 
					
						
							|  |  |  | 				.replace(/\$INDEX|\$\{INDEX\}/g, that.config['index-dir'] || '.ImageGrid') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 02:25:55 +03:00
										 |  |  | 			gid_logger && gid_logger.emit('queued', images) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 			return images | 
					
						
							|  |  |  | 				.mapChunks(CHUNK_SIZE, function(gid){ | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 					if(STOP){ | 
					
						
							|  |  |  | 						throw Array.STOP('aborted') } | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 					var img = that.images[gid] | 
					
						
							|  |  |  | 					var base = base_path  | 
					
						
							|  |  |  | 						|| img.base_path  | 
					
						
							|  |  |  | 						|| that.location.path | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 					return sizes | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 						.map(function(size, i){ | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 							if(STOP){ | 
					
						
							|  |  |  | 								throw Array.STOP('aborted') } | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 							var name = path = path_tpl | 
					
						
							|  |  |  | 								.replace(/\$RESOLUTION|\$\{RESOLUTION\}/g, parseInt(size)) | 
					
						
							|  |  |  | 								.replace(/\$GID|\$\{GID\}/g, gid)  | 
					
						
							|  |  |  | 								.replace(/\$NAME|\$\{NAME\}/g, img.name) | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 							// XXX do we need this to be sync???
 | 
					
						
							|  |  |  | 							return that.makeResizedImage('sync', gid, size, base, {  | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 									name,  | 
					
						
							|  |  |  | 									skipSmaller: true, | 
					
						
							|  |  |  | 									transform: false, | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 									logger: logger_mode == 'gids' ?  | 
					
						
							|  |  |  | 										false  | 
					
						
							|  |  |  | 										: logger, | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 								}) | 
					
						
							| 
									
										
										
										
											2020-12-06 04:39:42 +03:00
										 |  |  | 								// XXX handle errors -- rejected because image exists...
 | 
					
						
							|  |  |  | 								.then(function(res){ | 
					
						
							| 
									
										
										
										
											2020-11-01 15:24:22 +03:00
										 |  |  | 									i == sizes.length-1 | 
					
						
							|  |  |  | 										&& gid_logger && gid_logger.emit('done', gid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									// did not create a preview...
 | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 									if(!res){ | 
					
						
							|  |  |  | 										return false } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									// update metadata...
 | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 									if(!base_path){ | 
					
						
							|  |  |  | 										var preview = img.preview = img.preview || {}  | 
					
						
							|  |  |  | 										preview[parseInt(size) + 'px'] = name | 
					
						
							| 
									
										
										
										
											2020-11-05 06:31:13 +03:00
										 |  |  | 										that.markChanged | 
					
						
							|  |  |  | 											&& that.markChanged('images', [gid]) } | 
					
						
							| 
									
										
										
										
											2020-10-31 05:10:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 									return [gid, size, name] }) }) }) | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 				.then(function(res){ | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 					ticket.resolve(res) | 
					
						
							| 
									
										
										
										
											2020-11-26 00:44:46 +03:00
										 |  |  | 					return res == 'aborted' ? | 
					
						
							|  |  |  | 						Promise.reject('aborted') | 
					
						
							|  |  |  | 						: res.flat() }) })], | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-03 04:49:56 +03:00
										 |  |  | 	// XXX add support for offloading the processing to a thread/worker...
 | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 	// XXX revise logging and logger passing...
 | 
					
						
							| 
									
										
										
										
											2020-11-05 06:31:13 +03:00
										 |  |  | 	cacheMetadata: ['- Sharp|Image/', | 
					
						
							|  |  |  | 		core.doc`Cache metadata
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			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, .. ]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 02:25:55 +03:00
										 |  |  | 		This will: | 
					
						
							|  |  |  | 			- quickly reads/caches essential (.orientation and .flipped) metadata | 
					
						
							|  |  |  | 			- quickly read some non-essential but already there values | 
					
						
							|  |  |  | 			- generate priority previews for very large images (only when in index) | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		This will overwrite/update if: | 
					
						
							|  |  |  | 			- .orientation and .flipped iff image .orientation AND .flipped  | 
					
						
							|  |  |  | 				are unset or force is true | 
					
						
							|  |  |  | 			- metadata if image .metadata is not set or  | 
					
						
							|  |  |  | 				.metadata.ImageGridMetadata is not set | 
					
						
							|  |  |  | 			- all metadata if force is set to true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 06:31:13 +03:00
										 |  |  | 		NOTE: this will effectively update metadata format to the new spec... | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 		NOTE: for info on full metadata format see: .readMetadata(..) | 
					
						
							| 
									
										
										
										
											2020-11-02 05:33:29 +03:00
										 |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 		core.sessionQueueHandler('Cache image metadata',  | 
					
						
							| 
									
										
										
										
											2020-12-03 04:03:20 +03:00
										 |  |  | 			// XXX timeouts still need tweaking...
 | 
					
						
							|  |  |  | 			{quiet: true, pool_size: 2, busy_timeout: 400},  | 
					
						
							| 
									
										
										
										
											2020-12-03 05:19:50 +03:00
										 |  |  | 			//{quiet: true, pool_size: 2, busy_timeout_scale: 10}, 
 | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 			// parse args...
 | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 			function(queue, image, ...args){ | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 				var force = false | 
					
						
							|  |  |  | 				if(image === true){ | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 					var [force, image, ...args] = arguments } | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 				return [ | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 					...(force ? [true] : []), | 
					
						
							|  |  |  | 					// expand images..
 | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 					image == 'all' ? | 
					
						
							|  |  |  | 							this.images.keys() | 
					
						
							|  |  |  | 						: image == 'loaded' ? | 
					
						
							|  |  |  | 							this.data.getImages('loaded') | 
					
						
							|  |  |  | 						: (image || 'current'), | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 					...args, | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 				] }, | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 			function(image, logger){ | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 				var that = this | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 				if(image === true){ | 
					
						
							|  |  |  | 					var [force, image, logger] = arguments } | 
					
						
							| 
									
										
										
										
											2020-11-02 06:06:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 				// XXX cache the image data???
 | 
					
						
							|  |  |  | 				var gid = this.data.getImage(image) | 
					
						
							|  |  |  | 				var img = this.images[gid] | 
					
						
							|  |  |  | 				var path = img && that.getImagePath(gid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// XXX
 | 
					
						
							|  |  |  | 				//var base_path = that.location.load == 'loadIndex' ?
 | 
					
						
							|  |  |  | 				//	null
 | 
					
						
							|  |  |  | 				//	: tmp
 | 
					
						
							|  |  |  | 				//var base_path = img && img.base_path
 | 
					
						
							|  |  |  | 				var base_path | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 				// skip...
 | 
					
						
							|  |  |  | 				if(!(img && path | 
					
						
							|  |  |  | 						&& (force | 
					
						
							|  |  |  | 							// high priority must be preset...
 | 
					
						
							|  |  |  | 							|| (img.orientation == null | 
					
						
							|  |  |  | 								&& img.flipped == null) | 
					
						
							|  |  |  | 							// update metadata...
 | 
					
						
							|  |  |  | 							|| (img.metadata || {}).ImageGridMetadata == null))){ | 
					
						
							|  |  |  | 					return } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// XXX handle/report errors...
 | 
					
						
							|  |  |  | 				return sharp(that.getImagePath(gid)) | 
					
						
							|  |  |  | 					.metadata() | 
					
						
							|  |  |  | 					.then(function(metadata){ | 
					
						
							|  |  |  | 						// no metadata...
 | 
					
						
							|  |  |  | 						if(metadata == null){ | 
					
						
							|  |  |  | 							return } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						var o = normalizeOrientation(metadata.orientation) | 
					
						
							|  |  |  | 						;(force || img.orientation == null) | 
					
						
							|  |  |  | 							// NOTE: we need to set orientation to something
 | 
					
						
							|  |  |  | 							// 		or we'll check it again and again...
 | 
					
						
							|  |  |  | 							&& (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',  | 
					
						
							|  |  |  | 								}) | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-02 18:49:45 +03:00
										 |  |  | 						// read the metadata...
 | 
					
						
							|  |  |  | 						var exif = metadata.exif  | 
					
						
							|  |  |  | 							&& exifReader(metadata.exif)  | 
					
						
							|  |  |  | 						exif | 
					
						
							|  |  |  | 							&& Object.assign( | 
					
						
							|  |  |  | 								img.metadata,  | 
					
						
							|  |  |  | 								exifReader2exiftool(exif, metadata.xmp)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// if image too large, generate preview(s)...
 | 
					
						
							|  |  |  | 						// XXX EXPERIMENTAL...
 | 
					
						
							|  |  |  | 						var size_threshold = that.config['preview-generate-threshold'] | 
					
						
							|  |  |  | 						if(size_threshold | 
					
						
							|  |  |  | 								&& img.preview == null | 
					
						
							|  |  |  | 								&& Math.max(metadata.width, metadata.height) > size_threshold){ | 
					
						
							|  |  |  | 							logger && logger.emit('Image too large', gid) | 
					
						
							|  |  |  | 							// XXX make this more generic...
 | 
					
						
							|  |  |  | 							// 		...if 'loadImages' should create previews in tmp...
 | 
					
						
							|  |  |  | 							that.location.load == 'loadIndex' | 
					
						
							|  |  |  | 								&& that.makePreviews(gid,  | 
					
						
							|  |  |  | 									that.config['preview-sizes-priority'] || 1080, | 
					
						
							|  |  |  | 									base_path, | 
					
						
							|  |  |  | 									logger) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						that.markChanged | 
					
						
							|  |  |  | 							&& that.markChanged('images', [gid]) | 
					
						
							|  |  |  | 						that.ribbons | 
					
						
							|  |  |  | 							&& that.ribbons.updateImage(gid)  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						return gid }) })], | 
					
						
							|  |  |  | 	cacheAllMetadata: ['- Sharp/Image/', | 
					
						
							| 
									
										
										
										
											2020-11-05 06:31:13 +03:00
										 |  |  | 		'cacheMetadata: "all" ...'], | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// shorthands...
 | 
					
						
							|  |  |  | 	// XXX do we need these???
 | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 	// 		...better have a task manager UI...
 | 
					
						
							| 
									
										
										
										
											2020-11-06 05:17:39 +03:00
										 |  |  | 	abortMakeResizedImage: ['- Sharp/', | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 		'tasks.stop: "makeResizedImage"'], | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 	abortMakePreviews: ['- Sharp/', | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 		'tasks.stop: "makePreviews"'], | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 	abortCacheMetadata: ['- Sharp/', | 
					
						
							| 
									
										
										
										
											2020-11-27 01:25:31 +03:00
										 |  |  | 		'tasks.stop: "cacheMetadata"'], | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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: [ | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 		//* XXX this needs to be run in the background...
 | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 		// XXX this is best done in a thread 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 22:46:27 +03:00
										 |  |  | 		[['loadImages',  | 
					
						
							|  |  |  | 				'loadNewImages'], | 
					
						
							| 
									
										
										
										
											2020-11-27 02:33:46 +03:00
										 |  |  | 			'cacheMetadata: "all"'], | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 		//*/
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 		// set orientation if not defined...
 | 
					
						
							| 
									
										
										
										
											2020-11-02 05:33:29 +03:00
										 |  |  | 		// NOTE: progress on this is not shown so as to avoid spamming 
 | 
					
						
							|  |  |  | 		// 		the UI...
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 		['updateImage', | 
					
						
							|  |  |  | 			function(_, gid){ | 
					
						
							| 
									
										
										
										
											2020-11-05 06:31:13 +03:00
										 |  |  | 				var that = this | 
					
						
							| 
									
										
										
										
											2020-11-10 18:00:14 +03:00
										 |  |  | 				// NOTE: as this directly affects the visible lag, this 
 | 
					
						
							|  |  |  | 				// 		must be as fast as possible...
 | 
					
						
							| 
									
										
										
										
											2020-11-27 02:33:46 +03:00
										 |  |  | 				// NOTE: running .cacheMetadata(..) in sync mode here forces
 | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 				// 		the image to update before it gets a change to get
 | 
					
						
							| 
									
										
										
										
											2020-11-27 02:33:46 +03:00
										 |  |  | 				// 		drawn...
 | 
					
						
							| 
									
										
										
										
											2020-11-10 18:00:14 +03:00
										 |  |  | 				;((this.images[gid] || {}).metadata || {}).ImageGridMetadata | 
					
						
							| 
									
										
										
										
											2020-12-03 20:51:54 +03:00
										 |  |  | 					|| this.cacheMetadata('sync', gid, false) }], | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-30 05:21:23 +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 }) |