| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | define(function(require){ var module = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //var DEBUG = DEBUG != null ? DEBUG : true
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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'){ | 
					
						
							|  |  |  | 	var ensureDir = file.denodeify(fse.ensureDir) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 16:29:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var SharpActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		'preview-normalized': true, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | 			this.previewConstructorWorker.__post_handlers = {} | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-05-23 19:19:09 +03:00
										 |  |  | 	stopPreviewWorker: ['- Sharp/', | 
					
						
							| 
									
										
										
										
											2016-05-22 23:11:12 +03:00
										 |  |  | 		function(){ | 
					
						
							|  |  |  | 			this.previewConstructorWorker && this.previewConstructorWorker.kill() | 
					
						
							|  |  |  | 			delete this.previewConstructorWorker | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-23 17:54:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	//	.makePreviews()
 | 
					
						
							|  |  |  | 	//	.makePreviews('current')
 | 
					
						
							|  |  |  | 	//		-> actions
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.makePreviews(gid)
 | 
					
						
							|  |  |  | 	//		-> actions
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.makePreviews([gid, gid, ..])
 | 
					
						
							|  |  |  | 	//		-> actions
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.makePreviews('all')
 | 
					
						
							|  |  |  | 	//		-> actions
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX should this account for non-jpeg images???
 | 
					
						
							|  |  |  | 	makePreviews: ['Sharp/Make image previews', | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 		function(images, sizes, base_path, logger){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 			logger = logger || this.logger | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// get/normalize images...
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 			images = images || this.current | 
					
						
							|  |  |  | 			// keywords...
 | 
					
						
							|  |  |  | 			images = images == 'all' ? this.data.getImages('all') | 
					
						
							|  |  |  | 				: images == 'current' ? this.current | 
					
						
							|  |  |  | 				: images | 
					
						
							|  |  |  | 			images = images instanceof Array ? images : [images] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// 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 { | 
					
						
							|  |  |  | 				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') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 			var post_handler = function(err, data){ | 
					
						
							|  |  |  | 				if(data.status == 'done' || data.status == 'skipped'){ | 
					
						
							|  |  |  | 					// get/make preview list...
 | 
					
						
							|  |  |  | 					var preview = that.images[data.gid].preview = | 
					
						
							|  |  |  | 						that.images[data.gid].preview || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					preview[data.res + 'px'] = data.path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					that.markChanged(data.gid) | 
					
						
							|  |  |  | 				}	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				logger && logger.emit(data.status, data.path) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 			// now do the work (async)...
 | 
					
						
							|  |  |  | 			if(this.previewConstructorWorker){ | 
					
						
							|  |  |  | 				return Promise.all(Object.keys(data).map(function(base_path){ | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 					return new Promise(function(resolve, reject){ | 
					
						
							|  |  |  | 						var ticket = Date.now() | 
					
						
							|  |  |  | 						while(ticket in that.previewConstructorWorker.__post_handlers){ | 
					
						
							|  |  |  | 							ticket = Date.now() | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						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){ | 
					
						
							|  |  |  | 							// XXX
 | 
					
						
							|  |  |  | 							if(err){ | 
					
						
							|  |  |  | 								reject(err) | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if(data == 'completed'){ | 
					
						
							|  |  |  | 								resolve() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							} else { | 
					
						
							|  |  |  | 								post_handler(err, data) | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						}  | 
					
						
							| 
									
										
										
										
											2016-05-25 22:09:03 +03:00
										 |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 				})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// now do the work (sync)...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return Promise.all(Object.keys(data).map(function(base_path){ | 
					
						
							|  |  |  | 					return preview.makePreviews( | 
					
						
							| 
									
										
										
										
											2016-05-26 00:49:09 +03:00
										 |  |  | 						data[base_path], sizes, base_path, path_tpl, post_handler) | 
					
						
							| 
									
										
										
										
											2016-05-25 23:16:41 +03:00
										 |  |  | 				})) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											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-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
										 |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                                                */ | 
					
						
							|  |  |  | return module }) |