| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-08-21 02:19:24 +03:00
										 |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 22:49:36 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var actions = require('lib/actions') | 
					
						
							|  |  |  | var features = require('lib/features') | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | var preview = require('lib/preview') | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var core = require('features/core') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try{ | 
					
						
							|  |  |  | 	var sharp = requirejs('sharp') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } catch(err){ | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 	var sharp = null | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if(typeof(process) != 'undefined'){ | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 	var cp = requirejs('child_process') | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	var fse = requirejs('fs-extra') | 
					
						
							|  |  |  | 	var pathlib = requirejs('path') | 
					
						
							|  |  |  | 	var glob = requirejs('glob') | 
					
						
							| 
									
										
										
										
											2016-05-28 16:29:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 16:12:10 +03:00
										 |  |  | 	var file = require('imagegrid/file') | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if(typeof(process) != 'undefined'){ | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | function normalizeOrientation(orientation){ | 
					
						
							|  |  |  | 	return { | 
					
						
							|  |  |  | 		orientation: ({ | 
					
						
							|  |  |  | 				0: 0, | 
					
						
							|  |  |  | 				1: 0, | 
					
						
							|  |  |  | 				2: 0, | 
					
						
							|  |  |  | 				3: 180, | 
					
						
							|  |  |  | 				4: 0, | 
					
						
							|  |  |  | 				5: 90, | 
					
						
							|  |  |  | 				6: 90, | 
					
						
							|  |  |  | 				7: 90,  | 
					
						
							|  |  |  | 				8: 270, | 
					
						
							|  |  |  | 			})[orientation], | 
					
						
							|  |  |  | 		flipped: ({ | 
					
						
							|  |  |  | 				0: null, | 
					
						
							|  |  |  | 				1: null, | 
					
						
							|  |  |  | 				2: ['horizontal'], | 
					
						
							|  |  |  | 				3: null, | 
					
						
							|  |  |  | 				4: ['vertical'], | 
					
						
							|  |  |  | 				5: ['vertical'], | 
					
						
							|  |  |  | 				6: null, | 
					
						
							|  |  |  | 				7: ['horizontal'], | 
					
						
							|  |  |  | 				8: null, | 
					
						
							|  |  |  | 			})[orientation], | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 16:29:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var SharpActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		'preview-normalized': true, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 18:13:52 +03:00
										 |  |  | 		// can be:
 | 
					
						
							|  |  |  | 		// 	'gids'
 | 
					
						
							|  |  |  | 		// 	'files'
 | 
					
						
							|  |  |  | 		'preview-progress-mode': 'gids', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | 		// NOTE: this uses 'preview-sizes' and 'preview-path-template' 
 | 
					
						
							|  |  |  | 		// 		from filesystem.IndexFormat...
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 	// NOTE: post handlers are pushed in .makePreviews(..)
 | 
					
						
							|  |  |  | 	// XXX might be a good idea to make this a bit more generic...
 | 
					
						
							|  |  |  | 	// XXX might be a good idea to use tasks to throttle....
 | 
					
						
							| 
									
										
										
										
											2016-05-23 19:19:09 +03:00
										 |  |  | 	startPreviewWorker: ['- Sharp/', | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 		function(){ | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 			if(this.previewConstructorWorker){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 			this.previewConstructorWorker = cp.fork( | 
					
						
							|  |  |  | 				'./workers/preview-constructor.js', { | 
					
						
							|  |  |  | 					cwd: process.cwd(), | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.on('message', function(res){ | 
					
						
							|  |  |  | 					if(res.err){ | 
					
						
							|  |  |  | 						// XXX
 | 
					
						
							|  |  |  | 						console.error(res) | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						var ticket = res.ticket | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 						// clear listener...
 | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 						if(res.status == 'completed'){ | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 							that.previewConstructorWorker.__post_handlers[res.ticket](null, 'completed') | 
					
						
							|  |  |  | 							delete that.previewConstructorWorker.__post_handlers[res.ticket] | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 						 | 
					
						
							|  |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 							that.previewConstructorWorker.__post_handlers[res.ticket](res.err, res.data) | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 			this.previewConstructorWorker.__post_handlers = {} }], | 
					
						
							| 
									
										
										
										
											2016-05-23 19:19:09 +03:00
										 |  |  | 	stopPreviewWorker: ['- Sharp/', | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 		function(){ | 
					
						
							|  |  |  | 			this.previewConstructorWorker && this.previewConstructorWorker.kill() | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 			delete this.previewConstructorWorker }], | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 	// XXX Q: if skipSmaller and overwrite: 'backup' and image smaller (skiped) do we backup???
 | 
					
						
							|  |  |  | 	// 		...I think no...
 | 
					
						
							|  |  |  | 	// XXX make backup name pattern configurable...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 	// XXX add transform/crop support...
 | 
					
						
							|  |  |  | 	// XXX revise logging...
 | 
					
						
							|  |  |  | 	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: | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				// output image name...
 | 
					
						
							|  |  |  | 				//
 | 
					
						
							|  |  |  | 				// Used if processing a single image, ignored otherwise.
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 				name: null | <str>, | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// image name pattern and data...
 | 
					
						
							|  |  |  | 				//
 | 
					
						
							|  |  |  | 				// NOTE: for more info on pattern see: .formatImageName(..)
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 				pattern: null | <str>, | 
					
						
							|  |  |  | 				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: ..., | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				logger: ... | 
					
						
							|  |  |  | ,			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		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,  | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 				// file handling...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 				enlarge, | 
					
						
							|  |  |  | 				skipSmaller, | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 				overwrite, | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 				// 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') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:24:38 +03:00
										 |  |  | 			// backup...
 | 
					
						
							|  |  |  | 			// XXX make backup name pattern configurable...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 			var timestamp = Date.timeStamp() | 
					
						
							| 
									
										
										
										
											2020-10-30 19:24:38 +03:00
										 |  |  | 			var backupName = function(to){ | 
					
						
							|  |  |  | 				var i = 0 | 
					
						
							|  |  |  | 				while(fse.existsSync(`${to}.${timestamp}.bak`+ (i || ''))){ | 
					
						
							|  |  |  | 					i++ } | 
					
						
							|  |  |  | 				return `${to}.${timestamp}.bak`+ (i || '') } | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 					var img = sharp(source) | 
					
						
							|  |  |  | 					return (skipSmaller ? | 
					
						
							| 
									
										
										
										
											2020-10-30 19:24:38 +03:00
										 |  |  | 							// skip if smaller than size...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 							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)){ | 
					
						
							|  |  |  | 										logger && logger.emit('skipping', to) | 
					
						
							|  |  |  | 										return } | 
					
						
							| 
									
										
										
										
											2020-10-30 19:24:38 +03:00
										 |  |  | 									// continue...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 									return img }) | 
					
						
							|  |  |  | 							: Promise.resolve(img)) | 
					
						
							| 
									
										
										
										
											2020-10-30 19:24:38 +03:00
										 |  |  | 						// prepare to write...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 						.then(function(img){ | 
					
						
							|  |  |  | 							return img  | 
					
						
							|  |  |  | 								&& ensureDir(pathlib.dirname(to)) | 
					
						
							|  |  |  | 									.then(function(){ | 
					
						
							|  |  |  | 										// handle existing image...
 | 
					
						
							|  |  |  | 										if(fse.existsSync(to)){ | 
					
						
							|  |  |  | 											// rename...
 | 
					
						
							|  |  |  | 											if(overwrite == 'backup'){ | 
					
						
							| 
									
										
										
										
											2020-10-30 19:24:38 +03:00
										 |  |  | 												fse.renameSync(to, backupName(to)) | 
					
						
							| 
									
										
										
										
											2020-10-30 19:16:42 +03:00
										 |  |  | 											// remove...
 | 
					
						
							|  |  |  | 											} else if(overwrite){ | 
					
						
							|  |  |  | 												fse.removeSync(to) | 
					
						
							|  |  |  | 											// skip...
 | 
					
						
							|  |  |  | 											} else { | 
					
						
							|  |  |  | 												logger && logger.emit('skipping', to) | 
					
						
							|  |  |  | 												return } } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 										// write...
 | 
					
						
							|  |  |  | 										return img | 
					
						
							|  |  |  | 											.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){ | 
					
						
							|  |  |  | 													// XXX
 | 
					
						
							|  |  |  | 												} | 
					
						
							|  |  |  | 												if(crop){ | 
					
						
							|  |  |  | 													// XXX
 | 
					
						
							|  |  |  | 												} | 
					
						
							|  |  |  | 											}) | 
					
						
							|  |  |  | 											.resize({ | 
					
						
							|  |  |  | 												width: size, | 
					
						
							|  |  |  | 												height: size, | 
					
						
							|  |  |  | 												fit: fit, | 
					
						
							|  |  |  | 												withoutEnlargement: !enlarge, | 
					
						
							|  |  |  | 											}) | 
					
						
							|  |  |  | 											.withMetadata() | 
					
						
							|  |  |  | 											.toFile(to)  | 
					
						
							|  |  |  | 											.then(function(){ | 
					
						
							|  |  |  | 												logger  | 
					
						
							|  |  |  | 													&& logger.emit('done', to) }) }) }) })) }], | 
					
						
							|  |  |  | 										 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 	// XXX use .makeResizedImage(..)
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	// XXX should this account for non-jpeg images???
 | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 	// XXX BUG?: this breaks on PNG images...
 | 
					
						
							|  |  |  | 	// XXX log: count gids and not specific images...
 | 
					
						
							| 
									
										
										
										
											2017-04-04 13:21:12 +03:00
										 |  |  | 	makePreviews: ['Sharp|File/Make image $previews', | 
					
						
							|  |  |  | 		core.doc`Make image previews
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Make previews for all images... | 
					
						
							|  |  |  | 			.makePreviews() | 
					
						
							|  |  |  | 			.makePreviews('all') | 
					
						
							|  |  |  | 				-> actions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Make previews for current image... | 
					
						
							|  |  |  | 			.makePreviews('current') | 
					
						
							|  |  |  | 				-> actions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Make previews for specific image(s)... | 
					
						
							|  |  |  | 			.makePreviews(gid) | 
					
						
							|  |  |  | 			.makePreviews([gid, gid, ..]) | 
					
						
							|  |  |  | 				-> actions | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 		function(images, sizes, base_path, logger){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2020-04-07 18:13:52 +03:00
										 |  |  | 			var logger_mode = this.config['preview-progress-mode'] || 'gids' | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 			logger = logger || this.logger | 
					
						
							| 
									
										
										
										
											2016-12-14 02:09:42 +03:00
										 |  |  | 			logger = logger && logger.push('Previews') | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 			// get/normalize images...
 | 
					
						
							| 
									
										
										
										
											2017-04-03 11:02:55 +03:00
										 |  |  | 			//images = images || this.current
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 			images = images  | 
					
						
							|  |  |  | 				|| 'all' | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 			// keywords...
 | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 			images = images == 'all' ?  | 
					
						
							|  |  |  | 					this.data.getImages('all') | 
					
						
							|  |  |  | 				: images == 'current' ?  | 
					
						
							|  |  |  | 					this.current | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 				: images | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 			images = images instanceof Array ?  | 
					
						
							|  |  |  | 				images  | 
					
						
							|  |  |  | 				: [images] | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 			//
 | 
					
						
							|  |  |  | 			// Format:
 | 
					
						
							|  |  |  | 			// 	{
 | 
					
						
							|  |  |  | 			// 		<base_path>: [
 | 
					
						
							|  |  |  | 			// 			{
 | 
					
						
							|  |  |  | 			// 				source: <image-path>,
 | 
					
						
							|  |  |  | 			// 				gid: <gid>,
 | 
					
						
							|  |  |  | 			// 			},
 | 
					
						
							|  |  |  | 			// 			...
 | 
					
						
							|  |  |  | 			// 		],
 | 
					
						
							|  |  |  | 			// 		...
 | 
					
						
							|  |  |  | 			// 	}
 | 
					
						
							|  |  |  | 			//
 | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 			// NOTE: if base_path is not provided this will base the 
 | 
					
						
							|  |  |  | 			// 		previews in .base_path for each image, usually this
 | 
					
						
							|  |  |  | 			// 		is where the index resides but might not be the 
 | 
					
						
							|  |  |  | 			// 		case for compound indexes...
 | 
					
						
							|  |  |  | 			var data = {} | 
					
						
							|  |  |  | 			images.forEach(function(gid){ | 
					
						
							|  |  |  | 				var img = that.images[gid] | 
					
						
							|  |  |  | 				var base = base_path || img.base_path || that.location.path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var d = data[base] = data[base] || [] | 
					
						
							|  |  |  | 				d.push({ | 
					
						
							|  |  |  | 					source: that.getImagePath(gid), | 
					
						
							|  |  |  | 					gid: gid, | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 				}) }) | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// get/normalize sizes....
 | 
					
						
							|  |  |  | 			var cfg_sizes = this.config['preview-sizes'].slice() || [] | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 			cfg_sizes | 
					
						
							|  |  |  | 				.sort() | 
					
						
							|  |  |  | 				.reverse() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 			if(sizes){ | 
					
						
							|  |  |  | 				sizes = sizes instanceof Array ? sizes : [sizes] | 
					
						
							|  |  |  | 				// normalize to preview size...
 | 
					
						
							|  |  |  | 				sizes = (this.config['preview-normalized'] ?  | 
					
						
							|  |  |  | 					sizes | 
					
						
							|  |  |  | 						.map(function(s){  | 
					
						
							|  |  |  | 							return cfg_sizes.filter(function(c){ return c >= s }).pop() || s }) | 
					
						
							|  |  |  | 					: sizes) | 
					
						
							|  |  |  | 						.unique() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 				sizes = cfg_sizes } | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 			var path_tpl = that.config['preview-path-template'] | 
					
						
							|  |  |  | 				.replace(/\$INDEX|\$\{INDEX\}/g, that.config['index-dir'] || '.ImageGrid') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 			var post_handler = function(err, data){ | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 				if(data.res != 'all'  | 
					
						
							|  |  |  | 						&& (data.status == 'done'  | 
					
						
							|  |  |  | 							|| data.status == 'skipped')){ | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 					// get/make preview list...
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 					var img = that.images[data.gid] | 
					
						
							|  |  |  | 					var preview = img.preview = | 
					
						
							|  |  |  | 						img.preview || {} | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 					// save previews...
 | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 					preview[data.res + 'px'] = data.path | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 					var o = normalizeOrientation(data.orientation) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// save orientation...
 | 
					
						
							|  |  |  | 					img.orientation = o.orientation | 
					
						
							|  |  |  | 					img.flipped = o.flipped | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-13 05:47:14 +03:00
										 |  |  | 					that.markChanged('images', [data.gid]) | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 				}	 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 				// NOTE: this will handle both 'queue' and 'resolved' statuses...
 | 
					
						
							|  |  |  | 				logger &&  | 
					
						
							| 
									
										
										
										
											2020-04-07 18:13:52 +03:00
										 |  |  | 					( logger_mode == 'gids' ? | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 						// report gid-level progress...
 | 
					
						
							|  |  |  | 						(data.res == 'all'  | 
					
						
							| 
									
										
										
										
											2020-04-07 18:13:52 +03:00
										 |  |  | 							&& logger.emit(data.status, data.gid)) | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 						// report preview-level progress...
 | 
					
						
							|  |  |  | 						: (data.res != 'all'  | 
					
						
							|  |  |  | 							&& logger.emit(data.status, data.path)) ) } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 			// now do the work (async)...
 | 
					
						
							|  |  |  | 			if(this.previewConstructorWorker){ | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 				return Promise.all( | 
					
						
							|  |  |  | 					Object.keys(data) | 
					
						
							|  |  |  | 						.map(function(base_path){ | 
					
						
							|  |  |  | 							return new Promise(function(resolve, reject){ | 
					
						
							|  |  |  | 								do { | 
					
						
							|  |  |  | 									var ticket = Date.now() | 
					
						
							|  |  |  | 								} while(ticket in that.previewConstructorWorker.__post_handlers) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								that.previewConstructorWorker.send({ | 
					
						
							|  |  |  | 									ticket: ticket, | 
					
						
							|  |  |  | 									images: data[base_path],  | 
					
						
							|  |  |  | 									sizes: sizes,  | 
					
						
							|  |  |  | 									base_path: base_path,  | 
					
						
							|  |  |  | 									target_tpl: path_tpl,  | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 								that.previewConstructorWorker.__post_handlers[ticket] =  | 
					
						
							|  |  |  | 									function(err, data){ | 
					
						
							|  |  |  | 										if(err){ | 
					
						
							|  |  |  | 											return reject(err) | 
					
						
							|  |  |  | 										} | 
					
						
							|  |  |  | 										data == 'completed' ? | 
					
						
							|  |  |  | 											resolve() | 
					
						
							|  |  |  | 											: post_handler(err, data) } | 
					
						
							|  |  |  | 							}) })) | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// now do the work (sync)...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-04-07 17:50:22 +03:00
										 |  |  | 				return Promise.all( | 
					
						
							|  |  |  | 					Object.keys(data) | 
					
						
							|  |  |  | 						// NOTE: this will handle images batched by .base_path...
 | 
					
						
							|  |  |  | 						.map(function(base_path){ | 
					
						
							|  |  |  | 							return preview.makePreviews( | 
					
						
							|  |  |  | 								data[base_path],  | 
					
						
							|  |  |  | 								sizes,  | 
					
						
							|  |  |  | 								base_path,  | 
					
						
							|  |  |  | 								path_tpl,  | 
					
						
							| 
									
										
										
										
											2020-10-30 18:13:53 +03:00
										 |  |  | 								post_handler) }))} }], | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | // XXX need to auto-generate previews for very large images...
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | var Sharp =  | 
					
						
							|  |  |  | module.Sharp = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'sharp', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'location', | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | 		'index-format', | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions: SharpActions,  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	isApplicable: function(){ return !!sharp }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 		// set orientation if not defined...
 | 
					
						
							|  |  |  | 		['updateImage', | 
					
						
							|  |  |  | 			function(_, gid){ | 
					
						
							|  |  |  | 				var that = this | 
					
						
							|  |  |  | 				var img = this.images[gid] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(img && img.orientation == null){ | 
					
						
							|  |  |  | 					img.orientation = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					sharp(this.getImagePath(gid)) | 
					
						
							|  |  |  | 						.metadata() | 
					
						
							|  |  |  | 						.then(function(data){ | 
					
						
							|  |  |  | 							var o = normalizeOrientation(data.orientation) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// NOTE: we need to set orientation to something
 | 
					
						
							|  |  |  | 							// 		or we'll check it again and again...
 | 
					
						
							|  |  |  | 							img.orientation = o.orientation || 0 | 
					
						
							|  |  |  | 							img.flipped = o.flipped | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-13 05:47:14 +03:00
										 |  |  | 							that.markChanged('images', [gid]) | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							// update image to use the orientation...
 | 
					
						
							|  |  |  | 							// XXX this might be a source for recursion 
 | 
					
						
							|  |  |  | 							// 		as it triggers .updateImage(..) again...
 | 
					
						
							|  |  |  | 							that.ribbons && that.ribbons.updateImage(gid) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 		// XXX need to:
 | 
					
						
							|  |  |  | 		// 		- if image too large to set the preview to "loading..."
 | 
					
						
							|  |  |  | 		// 		- create previews...
 | 
					
						
							|  |  |  | 		// 		- update image...
 | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 		/* | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 		['updateImage.pre', | 
					
						
							|  |  |  | 			function(gid){ | 
					
						
							|  |  |  | 				var that = this | 
					
						
							|  |  |  | 				if(this.images[gid].preview == null){ | 
					
						
							|  |  |  | 					sharp(this.getImagePath(gid)) | 
					
						
							|  |  |  | 						.metadata() | 
					
						
							|  |  |  | 						.then(function(metadata){ | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 							// current image is larger than any of the previews...
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 							if(Math.max(metadata.width, metadata.height)  | 
					
						
							|  |  |  | 									> Math.max.apply(Math, that.config['preview-sizes'])){ | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 								// create the currently needed preview first...
 | 
					
						
							|  |  |  | 								that.makePreviews(gid, that.ribbons.getVisibleImageSize()) | 
					
						
							|  |  |  | 									.then(function(){ | 
					
						
							|  |  |  | 										// load the created preview...
 | 
					
						
							|  |  |  | 										that.ribbons.updateImage(gid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 										// create the rest...
 | 
					
						
							|  |  |  | 										that.makePreviews(gid) | 
					
						
							|  |  |  | 									}) | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 							} | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}] | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 		//*/
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							| 
									
										
										
										
											2016-08-20 22:49:36 +03:00
										 |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |