mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-11-03 04:40:10 +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 })
 |