mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-10-30 10:50:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			341 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			341 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| /**********************************************************************
 | |
| * 
 | |
| *
 | |
| *
 | |
| **********************************************************************/
 | |
| ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
 | |
| (function(require){ var module={} // make module AMD/node compatible...
 | |
| /*********************************************************************/
 | |
| 
 | |
| var actions = require('lib/actions')
 | |
| var features = require('lib/features')
 | |
| var preview = require('lib/preview')
 | |
| 
 | |
| var core = require('features/core')
 | |
| 
 | |
| try{
 | |
| 	var sharp = requirejs('sharp')
 | |
| 
 | |
| } catch(err){
 | |
| 	var sharp = null
 | |
| }
 | |
| 
 | |
| if(typeof(process) != 'undefined'){
 | |
| 	var cp = requirejs('child_process')
 | |
| 	var fse = requirejs('fs-extra')
 | |
| 	var pathlib = requirejs('path')
 | |
| 	var glob = requirejs('glob')
 | |
| 
 | |
| 	var file = require('imagegrid/file')
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*********************************************************************/
 | |
| 
 | |
| if(typeof(process) != 'undefined'){
 | |
| 	var ensureDir = file.denodeify(fse.ensureDir)
 | |
| }
 | |
| 
 | |
| 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],
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*********************************************************************/
 | |
| 
 | |
| var SharpActions = actions.Actions({
 | |
| 	config: {
 | |
| 		'preview-normalized': true,
 | |
| 
 | |
| 		// NOTE: this uses 'preview-sizes' and 'preview-path-template' 
 | |
| 		// 		from filesystem.IndexFormat...
 | |
| 	},
 | |
| 
 | |
| 	// 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....
 | |
| 	startPreviewWorker: ['- Sharp/',
 | |
| 		function(){
 | |
| 			var that = this
 | |
| 			if(this.previewConstructorWorker){
 | |
| 				return
 | |
| 			}
 | |
| 			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
 | |
| 						// clear listener...
 | |
| 						if(res.status == 'completed'){
 | |
| 							that.previewConstructorWorker.__post_handlers[res.ticket](null, 'completed')
 | |
| 							delete that.previewConstructorWorker.__post_handlers[res.ticket]
 | |
| 						
 | |
| 						} else {
 | |
| 							that.previewConstructorWorker.__post_handlers[res.ticket](res.err, res.data)
 | |
| 						}
 | |
| 					}
 | |
| 				})
 | |
| 
 | |
| 			this.previewConstructorWorker.__post_handlers = {}
 | |
| 		}],
 | |
| 	stopPreviewWorker: ['- Sharp/',
 | |
| 		function(){
 | |
| 			this.previewConstructorWorker && this.previewConstructorWorker.kill()
 | |
| 			delete this.previewConstructorWorker
 | |
| 		}],
 | |
| 
 | |
| 
 | |
| 	// XXX should this account for non-jpeg images???
 | |
| 	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
 | |
| 	
 | |
| 		`,
 | |
| 		function(images, sizes, base_path, logger){
 | |
| 			var that = this
 | |
| 			logger = logger || this.logger
 | |
| 			logger = logger && logger.push('Previews')
 | |
| 
 | |
| 
 | |
| 			// 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]
 | |
| 
 | |
| 			// 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() || []
 | |
| 			cfg_sizes
 | |
| 				.sort()
 | |
| 				.reverse()
 | |
| 
 | |
| 			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')
 | |
| 
 | |
| 			var post_handler = function(err, data){
 | |
| 				if(data.status == 'done' || data.status == 'skipped'){
 | |
| 					// get/make preview list...
 | |
| 					var img = that.images[data.gid]
 | |
| 					var preview = img.preview =
 | |
| 						img.preview || {}
 | |
| 
 | |
| 					// save previews...
 | |
| 					preview[data.res + 'px'] = data.path
 | |
| 
 | |
| 					var o = normalizeOrientation(data.orientation)
 | |
| 
 | |
| 					// save orientation...
 | |
| 					img.orientation = o.orientation
 | |
| 					img.flipped = o.flipped
 | |
| 
 | |
| 					that.markChanged('images', [data.gid])
 | |
| 				}	
 | |
| 
 | |
| 				logger && logger.emit(data.status, data.path)
 | |
| 			}
 | |
| 
 | |
| 			// now do the work (async)...
 | |
| 			if(this.previewConstructorWorker){
 | |
| 				return Promise.all(Object.keys(data).map(function(base_path){
 | |
| 					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)
 | |
| 							}
 | |
| 						} 
 | |
| 					})
 | |
| 				}))
 | |
| 
 | |
| 			// now do the work (sync)...
 | |
| 			} else {
 | |
| 				return Promise.all(Object.keys(data).map(function(base_path){
 | |
| 					return preview.makePreviews(
 | |
| 						data[base_path], sizes, base_path, path_tpl, post_handler)
 | |
| 				}))
 | |
| 			}
 | |
| 		}],
 | |
| })
 | |
| 
 | |
| 
 | |
| // XXX need to auto-generate previews for very large images...
 | |
| var Sharp = 
 | |
| module.Sharp = core.ImageGridFeatures.Feature({
 | |
| 	title: '',
 | |
| 	doc: '',
 | |
| 
 | |
| 	tag: 'sharp',
 | |
| 	depends: [
 | |
| 		'location',
 | |
| 		'index-format',
 | |
| 	],
 | |
| 
 | |
| 	actions: SharpActions, 
 | |
| 
 | |
| 	isApplicable: function(){ return !!sharp },
 | |
| 
 | |
| 	handlers: [
 | |
| 		// 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
 | |
| 
 | |
| 							that.markChanged('images', [gid])
 | |
| 
 | |
| 							// 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)
 | |
| 						})
 | |
| 				}
 | |
| 			}],
 | |
| 
 | |
| 		// XXX need to:
 | |
| 		// 		- if image too large to set the preview to "loading..."
 | |
| 		// 		- create previews...
 | |
| 		// 		- update image...
 | |
| 		/*
 | |
| 		['updateImage.pre',
 | |
| 			function(gid){
 | |
| 				var that = this
 | |
| 				if(this.images[gid].preview == null){
 | |
| 					sharp(this.getImagePath(gid))
 | |
| 						.metadata()
 | |
| 						.then(function(metadata){
 | |
| 							// current image is larger than any of the previews...
 | |
| 							if(Math.max(metadata.width, metadata.height) 
 | |
| 									> Math.max.apply(Math, that.config['preview-sizes'])){
 | |
| 								// 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)
 | |
| 									})
 | |
| 							}
 | |
| 						})
 | |
| 				}
 | |
| 			}]
 | |
| 		//*/
 | |
| 	],
 | |
| })
 | |
| 
 | |
| 
 | |
| 
 | |
| /**********************************************************************
 | |
| * vim:set ts=4 sw=4 :                               */ return module })
 |