From e092fbcc40447e686fa8dc94864c562d5874cd7e Mon Sep 17 00:00:00 2001 From: Eyal Arubas Date: Fri, 28 Nov 2014 23:43:17 +0800 Subject: [PATCH] add 'image' decree custom type --- lib/Batch.js | 245 ------------------ lib/BatchPrototypeInit.js | 247 ++++++++++++++++++ lib/Image.js | 523 +------------------------------------ lib/ImagePrototypeInit.js | 525 ++++++++++++++++++++++++++++++++++++++ lib/defs.js | 2 +- lib/util.js | 8 +- 6 files changed, 781 insertions(+), 769 deletions(-) create mode 100644 lib/BatchPrototypeInit.js create mode 100644 lib/ImagePrototypeInit.js diff --git a/lib/Batch.js b/lib/Batch.js index dc61815f..6ff8afd8 100644 --- a/lib/Batch.js +++ b/lib/Batch.js @@ -1,48 +1,5 @@ (function(undefined) { - var path = require('path'), - fs = require('fs'), - async = require('async'), - decree = require('decree'), - defs = require('./defs'), - util = require('./util'), - Image = require('./Image'); - - var judges = { - // slice(0,-1) cuts the callback declaration, which is not needed in - // batch mode. - scale: decree(defs.args.scale.slice(0, -1)), - resize: decree(defs.args.resize.slice(0, -1)), - rotate: decree(defs.args.rotate.slice(0, -1)), - blur: decree(defs.args.blur.slice(0, -1)), - hslaAdjust: decree(defs.args.hslaAdjust.slice(0, -1)), - saturate: decree(defs.args.saturate.slice(0, -1)), - lighten: decree(defs.args.lighten.slice(0, -1)), - darken: decree(defs.args.darken.slice(0, -1)), - fade: decree(defs.args.fade.slice(0, -1)), - opacify: decree(defs.args.opacify.slice(0, -1)), - hue: decree(defs.args.hue.slice(0, -1)), - crop: decree(defs.args.crop.slice(0, -1)), - mirror: decree(defs.args.mirror.slice(0, -1)), - pad: decree(defs.args.pad.slice(0, -1)), - border: decree(defs.args.border.slice(0, -1)), - sharpen: decree(defs.args.sharpen.slice(0, -1)), - paste: decree(defs.args.paste.slice(0, -1)), - clone: decree(defs.args.clone.slice(0, -1)), - extract: decree(defs.args.extract.slice(0, -1)), - exec: decree(defs.args.exec), - toBuffer: decree(defs.args.toBuffer), - writeFile: decree(defs.args.writeFile) - }; - - var undefinedFilter = util.undefinedFilter, - normalizeColor = util.normalizeColor; - - // Extend Image with image.batch() - Image.prototype.batch = function() { - return new Batch(this); - }; - function Batch(image) { this.__image = image; this.__queue = []; @@ -55,208 +12,6 @@ }; } - Batch.prototype.exec = function() { - var that = this; - judges.exec(arguments, function(callback) { - if (that.__running) throw Error("Batch is already running"); - that.__running = true; - async.eachSeries(that.__queue, function(op, done) { - op.args.push(done); - // if an exception is thrown here, it should be caught (because we - // are in the middle of async process) and translated to an 'err' - // parameter. - try { - op.handle.apply(that.__image, op.args); - } catch (e) { - done(e); - } - }, function(err) { - that.__queue.length = 0; // queue is now empty - that.__running = false; - callback(err, that.__image); - }); - }); - }; - - Batch.prototype.scale = function() { - var that = this; - judges.scale(arguments, function(wRatio, hRatio, inter) { - that.__addOp(that.__image.scale, [wRatio, hRatio, inter].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.resize = function() { - var that = this; - judges.resize(arguments, function(width, height, inter) { - that.__addOp(that.__image.resize, [width, height, inter].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.rotate = function() { - var that = this; - judges.rotate(arguments, function(degs, color) { - color = normalizeColor(color); - that.__addOp(that.__image.rotate, [degs, color].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.blur = function() { - var that = this; - judges.blur(arguments, function(sigma) { - that.__addOp(that.__image.blur, [sigma].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.hslaAdjust = function() { - var that = this; - judges.hslaAdjust(arguments, function(hs, sd, ld, ad) { - that.__addOp(that.__image.hslaAdjust, [hs, sd, ld, ad].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.saturate = function() { - var that = this; - judges.saturate(arguments, function(delta) { - that.__addOp(that.__image.saturate, [delta].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.lighten = function() { - var that = this; - judges.lighten(arguments, function(delta) { - that.__addOp(that.__image.lighten, [delta].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.darken = function() { - var that = this; - judges.darken(arguments, function(delta) { - that.__addOp(that.__image.darken, [delta].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.fade = function() { - var that = this; - judges.fade(arguments, function(delta) { - that.__addOp(that.__image.fade, [delta].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.opacify = function() { - this.__addOp(this.__image.opacify, []); - return this; - }; - - Batch.prototype.hue = function() { - var that = this; - judges.hue(arguments, function(shift) { - that.__addOp(that.__image.hue, [shift].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.crop = function() { - var that = this; - judges.crop(arguments, function(left, top, right, bottom) { - that.__addOp(that.__image.crop, [left, top, right, bottom].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.mirror = function() { - var that = this; - judges.mirror(arguments, function(axes) { - that.__addOp(that.__image.mirror, [axes].filter(undefinedFilter)); - }); - return this; - }; - - // mirror alias: - Batch.prototype.flip = Batch.prototype.mirror; - - Batch.prototype.pad = function() { - var that = this; - judges.pad(arguments, function(left, top, right, bottom, color) { - color = normalizeColor(color); - that.__addOp(that.__image.pad, [left, top, right, bottom, color].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.border = function() { - var that = this; - judges.border(arguments, function(width, color) { - color = normalizeColor(color); - that.__addOp(that.__image.border, [width, color].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.sharpen = function() { - var that = this; - judges.sharpen(arguments, function(amplitude) { - that.__addOp(that.__image.sharpen, [amplitude].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.paste = function() { - var that = this; - judges.paste(arguments, function(left, top, img) { - if (!(img instanceof Image)) - throw Error("Pasted image is not a valid Image object"); - that.__addOp(that.__image.paste, [left, top, img].filter(undefinedFilter)); - }); - return this; - }; - - Batch.prototype.toBuffer = function() { - var that = this; - judges.toBuffer(arguments, function(type, params, callback) { - if (type === 'jpg' || type === 'jpeg') { - if (params.quality != 0) - params.quality = params.quality || defs.defaults.DEF_JPEG_QUALITY; - if (params.quality != parseInt(params.quality) || params.quality < 0 || params.quality > 100) - throw Error('Invalid JPEG quality'); - } else if (type === 'png') { - params.compression = params.compression || defs.defaults.PNG_DEF_COMPRESSION; - if (['none', 'fast', 'high'].indexOf(params.compression) === -1) - throw Error('Invalid PNG compression'); - params.interlaced = params.interlaced || defs.defaults.PNG_DEF_INTERLACED; - if (typeof params.interlaced !== 'boolean') throw Error('PNG \'interlaced\' must be boolean'); - params.transparency = params.transparency || defs.defaults.PNG_DEF_TRANSPARENT; - if (typeof params.transparency !== 'boolean' && params.transparency.toLowerCase() !== 'auto') - throw Error('PNG \'transparency\' must be boolean or \'auto\''); - } else throw Error('Unknown type \'' + type + '\''); - that.exec(function(err, image) { - if (err) return callback(err); - image.toBuffer(type, params, callback); - }); - }); - }; - - Batch.prototype.writeFile = function(outpath, type, params, callback) { - var that = this; - judges.writeFile(arguments, function(outpath, type, params, callback) { - type = type || path.extname(outpath).slice(1).toLowerCase(); - that.toBuffer(type, params, function(err, buffer) { - if (err) return callback(err); - fs.writeFile(outpath, buffer, { - encoding: 'binary' - }, callback); - }); - }); - }; - // EXPORTS // ------- module.exports = Batch; diff --git a/lib/BatchPrototypeInit.js b/lib/BatchPrototypeInit.js new file mode 100644 index 00000000..7df163f9 --- /dev/null +++ b/lib/BatchPrototypeInit.js @@ -0,0 +1,247 @@ +(function(undefined) { + + var path = require('path'), + fs = require('fs'), + async = require('async'), + decree = require('decree'), + defs = require('./defs'), + util = require('./util'), + Batch = require('./Batch'), + Image = require('./Image'); + + var judges = { + // slice(0,-1) cuts the callback declaration, which is not needed in + // batch mode. + scale: decree(defs.args.scale.slice(0, -1)), + resize: decree(defs.args.resize.slice(0, -1)), + rotate: decree(defs.args.rotate.slice(0, -1)), + blur: decree(defs.args.blur.slice(0, -1)), + hslaAdjust: decree(defs.args.hslaAdjust.slice(0, -1)), + saturate: decree(defs.args.saturate.slice(0, -1)), + lighten: decree(defs.args.lighten.slice(0, -1)), + darken: decree(defs.args.darken.slice(0, -1)), + fade: decree(defs.args.fade.slice(0, -1)), + opacify: decree(defs.args.opacify.slice(0, -1)), + hue: decree(defs.args.hue.slice(0, -1)), + crop: decree(defs.args.crop.slice(0, -1)), + mirror: decree(defs.args.mirror.slice(0, -1)), + pad: decree(defs.args.pad.slice(0, -1)), + border: decree(defs.args.border.slice(0, -1)), + sharpen: decree(defs.args.sharpen.slice(0, -1)), + paste: decree(defs.args.paste.slice(0, -1)), + clone: decree(defs.args.clone.slice(0, -1)), + extract: decree(defs.args.extract.slice(0, -1)), + exec: decree(defs.args.exec), + toBuffer: decree(defs.args.toBuffer), + writeFile: decree(defs.args.writeFile) + }; + + var undefinedFilter = util.undefinedFilter, + normalizeColor = util.normalizeColor; + + // Extend Image with image.batch() + Image.prototype.batch = function() { + return new Batch(this); + }; + + Batch.prototype.exec = function() { + var that = this; + judges.exec(arguments, function(callback) { + if (that.__running) throw Error("Batch is already running"); + that.__running = true; + async.eachSeries(that.__queue, function(op, done) { + op.args.push(done); + // if an exception is thrown here, it should be caught (because we + // are in the middle of async process) and translated to an 'err' + // parameter. + try { + op.handle.apply(that.__image, op.args); + } catch (e) { + done(e); + } + }, function(err) { + that.__queue.length = 0; // queue is now empty + that.__running = false; + callback(err, that.__image); + }); + }); + }; + + Batch.prototype.scale = function() { + var that = this; + judges.scale(arguments, function(wRatio, hRatio, inter) { + that.__addOp(that.__image.scale, [wRatio, hRatio, inter].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.resize = function() { + var that = this; + judges.resize(arguments, function(width, height, inter) { + that.__addOp(that.__image.resize, [width, height, inter].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.rotate = function() { + var that = this; + judges.rotate(arguments, function(degs, color) { + color = normalizeColor(color); + that.__addOp(that.__image.rotate, [degs, color].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.blur = function() { + var that = this; + judges.blur(arguments, function(sigma) { + that.__addOp(that.__image.blur, [sigma].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.hslaAdjust = function() { + var that = this; + judges.hslaAdjust(arguments, function(hs, sd, ld, ad) { + that.__addOp(that.__image.hslaAdjust, [hs, sd, ld, ad].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.saturate = function() { + var that = this; + judges.saturate(arguments, function(delta) { + that.__addOp(that.__image.saturate, [delta].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.lighten = function() { + var that = this; + judges.lighten(arguments, function(delta) { + that.__addOp(that.__image.lighten, [delta].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.darken = function() { + var that = this; + judges.darken(arguments, function(delta) { + that.__addOp(that.__image.darken, [delta].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.fade = function() { + var that = this; + judges.fade(arguments, function(delta) { + that.__addOp(that.__image.fade, [delta].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.opacify = function() { + this.__addOp(this.__image.opacify, []); + return this; + }; + + Batch.prototype.hue = function() { + var that = this; + judges.hue(arguments, function(shift) { + that.__addOp(that.__image.hue, [shift].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.crop = function() { + var that = this; + judges.crop(arguments, function(left, top, right, bottom) { + that.__addOp(that.__image.crop, [left, top, right, bottom].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.mirror = function() { + var that = this; + judges.mirror(arguments, function(axes) { + that.__addOp(that.__image.mirror, [axes].filter(undefinedFilter)); + }); + return this; + }; + + // mirror alias: + Batch.prototype.flip = Batch.prototype.mirror; + + Batch.prototype.pad = function() { + var that = this; + judges.pad(arguments, function(left, top, right, bottom, color) { + color = normalizeColor(color); + that.__addOp(that.__image.pad, [left, top, right, bottom, color].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.border = function() { + var that = this; + judges.border(arguments, function(width, color) { + color = normalizeColor(color); + that.__addOp(that.__image.border, [width, color].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.sharpen = function() { + var that = this; + judges.sharpen(arguments, function(amplitude) { + that.__addOp(that.__image.sharpen, [amplitude].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.paste = function() { + var that = this; + judges.paste(arguments, function(left, top, img) { + that.__addOp(that.__image.paste, [left, top, img].filter(undefinedFilter)); + }); + return this; + }; + + Batch.prototype.toBuffer = function() { + var that = this; + judges.toBuffer(arguments, function(type, params, callback) { + if (type === 'jpg' || type === 'jpeg') { + if (params.quality != 0) + params.quality = params.quality || defs.defaults.DEF_JPEG_QUALITY; + if (params.quality != parseInt(params.quality) || params.quality < 0 || params.quality > 100) + throw Error('Invalid JPEG quality'); + } else if (type === 'png') { + params.compression = params.compression || defs.defaults.PNG_DEF_COMPRESSION; + if (['none', 'fast', 'high'].indexOf(params.compression) === -1) + throw Error('Invalid PNG compression'); + params.interlaced = params.interlaced || defs.defaults.PNG_DEF_INTERLACED; + if (typeof params.interlaced !== 'boolean') throw Error('PNG \'interlaced\' must be boolean'); + params.transparency = params.transparency || defs.defaults.PNG_DEF_TRANSPARENT; + if (typeof params.transparency !== 'boolean' && params.transparency.toLowerCase() !== 'auto') + throw Error('PNG \'transparency\' must be boolean or \'auto\''); + } else throw Error('Unknown type \'' + type + '\''); + that.exec(function(err, image) { + if (err) return callback(err); + image.toBuffer(type, params, callback); + }); + }); + }; + + Batch.prototype.writeFile = function(outpath, type, params, callback) { + var that = this; + judges.writeFile(arguments, function(outpath, type, params, callback) { + type = type || path.extname(outpath).slice(1).toLowerCase(); + that.toBuffer(type, params, function(err, buffer) { + if (err) return callback(err); + fs.writeFile(outpath, buffer, { + encoding: 'binary' + }, callback); + }); + }); + }; + +})(void 0); diff --git a/lib/Image.js b/lib/Image.js index dc316259..74083061 100644 --- a/lib/Image.js +++ b/lib/Image.js @@ -1,37 +1,6 @@ (function(undefined) { - var path = require('path'), - fs = require('fs'), - decree = require('decree'), - defs = require('./defs'), - util = require('./util'), - encoder = require('../build/Release/lwip_encoder'), - lwip_image = require('../build/Release/lwip_image'), - normalizeColor = util.normalizeColor; - - var judges = { - scale: decree(defs.args.scale), - resize: decree(defs.args.resize), - rotate: decree(defs.args.rotate), - blur: decree(defs.args.blur), - hslaAdjust: decree(defs.args.hslaAdjust), - saturate: decree(defs.args.saturate), - lighten: decree(defs.args.lighten), - darken: decree(defs.args.darken), - fade: decree(defs.args.fade), - opacify: decree(defs.args.opacify), - hue: decree(defs.args.hue), - crop: decree(defs.args.crop), - mirror: decree(defs.args.mirror), - pad: decree(defs.args.pad), - border: decree(defs.args.border), - sharpen: decree(defs.args.sharpen), - paste: decree(defs.args.paste), - clone: decree(defs.args.clone), - extract: decree(defs.args.extract), - toBuffer: decree(defs.args.toBuffer), - writeFile: decree(defs.args.writeFile) - }; + var lwip_image = require('../build/Release/lwip_image'); function Image(pixelsBuf, width, height, trans) { this.__lwip = new lwip_image.LwipImage(pixelsBuf, width, height); @@ -39,496 +8,6 @@ this.__trans = trans; } - Image.prototype.__lock = function() { - if (!this.__locked) this.__locked = true; - else throw Error("Another image operation already in progress"); - }; - - Image.prototype.__release = function() { - this.__locked = false; - }; - - Image.prototype.width = function() { - return this.__lwip.width(); - }; - - Image.prototype.height = function() { - return this.__lwip.height(); - }; - - Image.prototype.size = function() { - return { - width: this.__lwip.width(), - height: this.__lwip.height() - }; - }; - - Image.prototype.scale = function() { - this.__lock(); - var that = this; - judges.scale( - arguments, - function(wRatio, hRatio, inter, callback) { - hRatio = hRatio || wRatio; - var width = +wRatio * that.width(), - height = +hRatio * that.height(); - that.__lwip.resize(width, height, defs.interpolations[inter], function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.resize = function() { - this.__lock(); - var that = this; - judges.resize( - arguments, - function(width, height, inter, callback) { - height = height || width; - that.__lwip.resize(+width, +height, defs.interpolations[inter], function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.rotate = function() { - this.__lock(); - var that = this; - judges.rotate( - arguments, - function(degs, color, callback) { - color = normalizeColor(color); - if (color.a < 100) that.__trans = true; - that.__lwip.rotate(+degs, +color.r, +color.g, +color.b, +color.a, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.blur = function() { - this.__lock(); - var that = this; - judges.blur( - arguments, - function(sigma, callback) { - that.__lwip.blur(+sigma, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.hslaAdjust = function() { - this.__lock(); - var that = this; - judges.hslaAdjust( - arguments, - function(hs, sd, ld, ad, callback) { - that.__lwip.hslaAdj(+hs, +sd, +ld, +ad, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.saturate = function() { - this.__lock(); - var that = this; - judges.saturate( - arguments, - function(delta, callback) { - that.__lwip.hslaAdj(0, +delta, 0, 0, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.lighten = function() { - this.__lock(); - var that = this; - judges.lighten( - arguments, - function(delta, callback) { - that.__lwip.hslaAdj(0, 0, +delta, 0, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.darken = function() { - this.__lock(); - var that = this; - judges.darken( - arguments, - function(delta, callback) { - that.__lwip.hslaAdj(0, 0, -delta, 0, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.fade = function() { - this.__lock(); - var that = this; - judges.fade( - arguments, - function(delta, callback) { - that.__lwip.hslaAdj(0, 0, 0, -delta, function(err) { - if (+delta > 0) that.__trans = true; - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.opacify = function() { - this.__lock(); - var that = this; - judges.opacify( - arguments, - function(callback) { - that.__lwip.opacify(function(err) { - that.__trans = false; - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.hue = function() { - this.__lock(); - var that = this; - judges.hue( - arguments, - function(shift, callback) { - that.__lwip.hslaAdj(+shift, 0, 0, 0, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.crop = function() { - this.__lock(); - var that = this; - judges.crop( - arguments, - function(left, top, right, bottom, callback) { - if (!right && !bottom) { - var size = that.size(), - width = left, - height = top; - left = 0 | (size.width - width) / 2; - top = 0 | (size.height - height) / 2; - right = left + width - 1; - bottom = top + height - 1; - } - that.__lwip.crop(left, top, right, bottom, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.mirror = function() { - this.__lock(); - var that = this; - judges.mirror( - arguments, - function(axes, callback) { - var xaxis = false, - yaxis = false; - if ('x' === axes) xaxis = true; - if ('y' === axes) yaxis = true; - if ('xy' === axes || 'yx' === axes) { - xaxis = true; - yaxis = true; - } - that.__lwip.mirror(xaxis, yaxis, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - // mirror alias: - Image.prototype.flip = Image.prototype.mirror; - - Image.prototype.pad = function() { - this.__lock(); - var that = this; - judges.pad( - arguments, - function(left, top, right, bottom, color, callback) { - color = normalizeColor(color); - if (color.a < 100) that.__trans = true; - that.__lwip.pad(+left, +top, +right, +bottom, +color.r, +color.g, +color.b, +color.a, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.border = function() { - this.__lock(); - var that = this; - judges.border( - arguments, - function(width, color, callback) { - color = normalizeColor(color); - if (color.a < 100) that.__trans = true; - // we can just use image.pad... - that.__lwip.pad(+width, +width, +width, +width, +color.r, +color.g, +color.b, +color.a, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.sharpen = function() { - this.__lock(); - var that = this; - judges.sharpen( - arguments, - function(amplitude, callback) { - that.__lwip.sharpen(+amplitude, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.paste = function() { - this.__lock(); - var that = this; - judges.paste( - arguments, - function(left, top, img, callback) { - if (!(img instanceof Image)) - throw Error("Pasted image is not a valid Image object"); - // first we retrieve what we need (buffer, dimensions, ...) - // synchronously so that the pasted image doesn't have a chance - // to be changed - var pixbuff = img.__lwip.buffer(), - width = img.__lwip.width(), - height = img.__lwip.height(); - if (left + width > that.__lwip.width() || top + height > that.__lwip.height()) - throw Error("Pasted image exceeds dimensions of base image"); - that.__lwip.paste(+left, +top, pixbuff, +width, +height, function(err) { - that.__release(); - callback(err, that); - }); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.clone = function() { - // no need to lock the image. we don't modify the memory buffer. - // just copy it. - var that = this; - judges.clone( - arguments, - function(callback) { - // first we retrieve what we need (buffer, dimensions, ...) - // synchronously so that the original image doesn't have a chance - // to be changed (remember, we don't lock it); and only then call - // the callback asynchronously. - var pixbuff = that.__lwip.buffer(), - width = that.__lwip.width(), - height = that.__lwip.height(), - trans = that.__trans; - setImmediate(function() { - callback(null, new Image(pixbuff, width, height, trans)); - }); - } - ); - }; - - Image.prototype.extract = function() { - // no need to lock the image. we don't modify the memory buffer. - // just copy it and then crop it. - var that = this; - judges.extract( - arguments, - function(left, top, right, bottom, callback) { - // first we retrieve what we need (buffer, dimensions, ...) - // synchronously so that the original image doesn't have a chance - // to be changed (remember, we don't lock it); then we crop it and - // only call the callback asynchronously. - var pixbuff = that.__lwip.buffer(), - width = that.__lwip.width(), - height = that.__lwip.height(), - trans = that.__trans, - eximg = new Image(pixbuff, width, height, trans); - eximg.__lwip.crop(left, top, right, bottom, function(err) { - callback(err, eximg); - }); - } - ); - }; - - Image.prototype.toBuffer = function() { - this.__lock(); - var that = this; - judges.toBuffer( - arguments, - function(type, params, callback) { - if (type === 'jpg' || type === 'jpeg') { - if (params.quality != 0) - params.quality = params.quality || defs.defaults.DEF_JPEG_QUALITY; - if (params.quality != parseInt(params.quality) || params.quality < 0 || params.quality > 100) - throw Error('Invalid JPEG quality'); - return encoder.jpeg( - that.__lwip.buffer(), - that.__lwip.width(), - that.__lwip.height(), - params.quality, - function(err, buffer) { - that.__release(); - callback(err, buffer); - } - ); - } else if (type === 'png') { - params.compression = params.compression || defs.defaults.PNG_DEF_COMPRESSION; - if (params.compression === 'none') params.compression = 0; - else if (params.compression === 'fast') params.compression = 1; - else if (params.compression === 'high') params.compression = 2; - else throw Error('Invalid PNG compression'); - params.interlaced = params.interlaced || defs.defaults.PNG_DEF_INTERLACED; - if (typeof params.interlaced !== 'boolean') throw Error('PNG \'interlaced\' must be boolean'); - params.transparency = params.transparency || defs.defaults.PNG_DEF_TRANSPARENT; - if (typeof params.transparency !== 'boolean'){ - if (typeof params.transparency === 'string' && params.transparency.toLowerCase() === 'auto') - params.transparency = that.__trans; - else throw Error('PNG \'transparency\' must be boolean or \'auto\''); - } - return encoder.png( - that.__lwip.buffer(), - that.__lwip.width(), - that.__lwip.height(), - params.compression, - params.interlaced, - params.transparency, - function(err, buffer) { - that.__release(); - callback(err, buffer); - } - ); - } else throw Error('Unknown type \'' + type + '\''); - }, - function(err) { - that.__release(); - throw err; - } - ); - }; - - Image.prototype.writeFile = function() { - var that = this; - judges.writeFile( - arguments, - function(outpath, type, params, callback) { - type = type || path.extname(outpath).slice(1).toLowerCase(); - that.toBuffer(type, params, function(err, buffer) { - if (err) return callback(err); - fs.writeFile(outpath, buffer, { - encoding: 'binary' - }, callback); - }); - } - ); - }; - // EXPORTS // ------- module.exports = Image; diff --git a/lib/ImagePrototypeInit.js b/lib/ImagePrototypeInit.js new file mode 100644 index 00000000..3dbcea0f --- /dev/null +++ b/lib/ImagePrototypeInit.js @@ -0,0 +1,525 @@ +(function(undefined) { + + var Image = require('./Image'), + path = require('path'), + fs = require('fs'), + decree = require('decree'), + defs = require('./defs'), + util = require('./util'), + encoder = require('../build/Release/lwip_encoder'), + lwip_image = require('../build/Release/lwip_image'), + normalizeColor = util.normalizeColor; + + var judges = { + scale: decree(defs.args.scale), + resize: decree(defs.args.resize), + rotate: decree(defs.args.rotate), + blur: decree(defs.args.blur), + hslaAdjust: decree(defs.args.hslaAdjust), + saturate: decree(defs.args.saturate), + lighten: decree(defs.args.lighten), + darken: decree(defs.args.darken), + fade: decree(defs.args.fade), + opacify: decree(defs.args.opacify), + hue: decree(defs.args.hue), + crop: decree(defs.args.crop), + mirror: decree(defs.args.mirror), + pad: decree(defs.args.pad), + border: decree(defs.args.border), + sharpen: decree(defs.args.sharpen), + paste: decree(defs.args.paste), + clone: decree(defs.args.clone), + extract: decree(defs.args.extract), + toBuffer: decree(defs.args.toBuffer), + writeFile: decree(defs.args.writeFile) + }; + + Image.prototype.__lock = function() { + if (!this.__locked) this.__locked = true; + else throw Error("Another image operation already in progress"); + }; + + Image.prototype.__release = function() { + this.__locked = false; + }; + + Image.prototype.width = function() { + return this.__lwip.width(); + }; + + Image.prototype.height = function() { + return this.__lwip.height(); + }; + + Image.prototype.size = function() { + return { + width: this.__lwip.width(), + height: this.__lwip.height() + }; + }; + + Image.prototype.scale = function() { + this.__lock(); + var that = this; + judges.scale( + arguments, + function(wRatio, hRatio, inter, callback) { + hRatio = hRatio || wRatio; + var width = +wRatio * that.width(), + height = +hRatio * that.height(); + that.__lwip.resize(width, height, defs.interpolations[inter], function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.resize = function() { + this.__lock(); + var that = this; + judges.resize( + arguments, + function(width, height, inter, callback) { + height = height || width; + that.__lwip.resize(+width, +height, defs.interpolations[inter], function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.rotate = function() { + this.__lock(); + var that = this; + judges.rotate( + arguments, + function(degs, color, callback) { + color = normalizeColor(color); + if (color.a < 100) that.__trans = true; + that.__lwip.rotate(+degs, +color.r, +color.g, +color.b, +color.a, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.blur = function() { + this.__lock(); + var that = this; + judges.blur( + arguments, + function(sigma, callback) { + that.__lwip.blur(+sigma, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.hslaAdjust = function() { + this.__lock(); + var that = this; + judges.hslaAdjust( + arguments, + function(hs, sd, ld, ad, callback) { + that.__lwip.hslaAdj(+hs, +sd, +ld, +ad, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.saturate = function() { + this.__lock(); + var that = this; + judges.saturate( + arguments, + function(delta, callback) { + that.__lwip.hslaAdj(0, +delta, 0, 0, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.lighten = function() { + this.__lock(); + var that = this; + judges.lighten( + arguments, + function(delta, callback) { + that.__lwip.hslaAdj(0, 0, +delta, 0, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.darken = function() { + this.__lock(); + var that = this; + judges.darken( + arguments, + function(delta, callback) { + that.__lwip.hslaAdj(0, 0, -delta, 0, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.fade = function() { + this.__lock(); + var that = this; + judges.fade( + arguments, + function(delta, callback) { + that.__lwip.hslaAdj(0, 0, 0, -delta, function(err) { + if (+delta > 0) that.__trans = true; + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.opacify = function() { + this.__lock(); + var that = this; + judges.opacify( + arguments, + function(callback) { + that.__lwip.opacify(function(err) { + that.__trans = false; + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.hue = function() { + this.__lock(); + var that = this; + judges.hue( + arguments, + function(shift, callback) { + that.__lwip.hslaAdj(+shift, 0, 0, 0, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.crop = function() { + this.__lock(); + var that = this; + judges.crop( + arguments, + function(left, top, right, bottom, callback) { + if (!right && !bottom) { + var size = that.size(), + width = left, + height = top; + left = 0 | (size.width - width) / 2; + top = 0 | (size.height - height) / 2; + right = left + width - 1; + bottom = top + height - 1; + } + that.__lwip.crop(left, top, right, bottom, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.mirror = function() { + this.__lock(); + var that = this; + judges.mirror( + arguments, + function(axes, callback) { + var xaxis = false, + yaxis = false; + if ('x' === axes) xaxis = true; + if ('y' === axes) yaxis = true; + if ('xy' === axes || 'yx' === axes) { + xaxis = true; + yaxis = true; + } + that.__lwip.mirror(xaxis, yaxis, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + // mirror alias: + Image.prototype.flip = Image.prototype.mirror; + + Image.prototype.pad = function() { + this.__lock(); + var that = this; + judges.pad( + arguments, + function(left, top, right, bottom, color, callback) { + color = normalizeColor(color); + if (color.a < 100) that.__trans = true; + that.__lwip.pad(+left, +top, +right, +bottom, +color.r, +color.g, +color.b, +color.a, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.border = function() { + this.__lock(); + var that = this; + judges.border( + arguments, + function(width, color, callback) { + color = normalizeColor(color); + if (color.a < 100) that.__trans = true; + // we can just use image.pad... + that.__lwip.pad(+width, +width, +width, +width, +color.r, +color.g, +color.b, +color.a, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.sharpen = function() { + this.__lock(); + var that = this; + judges.sharpen( + arguments, + function(amplitude, callback) { + that.__lwip.sharpen(+amplitude, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.paste = function() { + this.__lock(); + var that = this; + judges.paste( + arguments, + function(left, top, img, callback) { + // first we retrieve what we need (buffer, dimensions, ...) + // synchronously so that the pasted image doesn't have a chance + // to be changed + var pixbuff = img.__lwip.buffer(), + width = img.__lwip.width(), + height = img.__lwip.height(); + if (left + width > that.__lwip.width() || top + height > that.__lwip.height()) + throw Error("Pasted image exceeds dimensions of base image"); + that.__lwip.paste(+left, +top, pixbuff, +width, +height, function(err) { + that.__release(); + callback(err, that); + }); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.clone = function() { + // no need to lock the image. we don't modify the memory buffer. + // just copy it. + var that = this; + judges.clone( + arguments, + function(callback) { + // first we retrieve what we need (buffer, dimensions, ...) + // synchronously so that the original image doesn't have a chance + // to be changed (remember, we don't lock it); and only then call + // the callback asynchronously. + var pixbuff = that.__lwip.buffer(), + width = that.__lwip.width(), + height = that.__lwip.height(), + trans = that.__trans; + setImmediate(function() { + callback(null, new Image(pixbuff, width, height, trans)); + }); + } + ); + }; + + Image.prototype.extract = function() { + // no need to lock the image. we don't modify the memory buffer. + // just copy it and then crop it. + var that = this; + judges.extract( + arguments, + function(left, top, right, bottom, callback) { + // first we retrieve what we need (buffer, dimensions, ...) + // synchronously so that the original image doesn't have a chance + // to be changed (remember, we don't lock it); then we crop it and + // only call the callback asynchronously. + var pixbuff = that.__lwip.buffer(), + width = that.__lwip.width(), + height = that.__lwip.height(), + trans = that.__trans, + eximg = new Image(pixbuff, width, height, trans); + eximg.__lwip.crop(left, top, right, bottom, function(err) { + callback(err, eximg); + }); + } + ); + }; + + Image.prototype.toBuffer = function() { + this.__lock(); + var that = this; + judges.toBuffer( + arguments, + function(type, params, callback) { + if (type === 'jpg' || type === 'jpeg') { + if (params.quality != 0) + params.quality = params.quality || defs.defaults.DEF_JPEG_QUALITY; + if (params.quality != parseInt(params.quality) || params.quality < 0 || params.quality > 100) + throw Error('Invalid JPEG quality'); + return encoder.jpeg( + that.__lwip.buffer(), + that.__lwip.width(), + that.__lwip.height(), + params.quality, + function(err, buffer) { + that.__release(); + callback(err, buffer); + } + ); + } else if (type === 'png') { + params.compression = params.compression || defs.defaults.PNG_DEF_COMPRESSION; + if (params.compression === 'none') params.compression = 0; + else if (params.compression === 'fast') params.compression = 1; + else if (params.compression === 'high') params.compression = 2; + else throw Error('Invalid PNG compression'); + params.interlaced = params.interlaced || defs.defaults.PNG_DEF_INTERLACED; + if (typeof params.interlaced !== 'boolean') throw Error('PNG \'interlaced\' must be boolean'); + params.transparency = params.transparency || defs.defaults.PNG_DEF_TRANSPARENT; + if (typeof params.transparency !== 'boolean'){ + if (typeof params.transparency === 'string' && params.transparency.toLowerCase() === 'auto') + params.transparency = that.__trans; + else throw Error('PNG \'transparency\' must be boolean or \'auto\''); + } + return encoder.png( + that.__lwip.buffer(), + that.__lwip.width(), + that.__lwip.height(), + params.compression, + params.interlaced, + params.transparency, + function(err, buffer) { + that.__release(); + callback(err, buffer); + } + ); + } else throw Error('Unknown type \'' + type + '\''); + }, + function(err) { + that.__release(); + throw err; + } + ); + }; + + Image.prototype.writeFile = function() { + var that = this; + judges.writeFile( + arguments, + function(outpath, type, params, callback) { + type = type || path.extname(outpath).slice(1).toLowerCase(); + that.toBuffer(type, params, function(err, buffer) { + if (err) return callback(err); + fs.writeFile(outpath, buffer, { + encoding: 'binary' + }, callback); + }); + } + ); + }; + +})(void 0); diff --git a/lib/defs.js b/lib/defs.js index 92d4efd7..118e6783 100644 --- a/lib/defs.js +++ b/lib/defs.js @@ -305,7 +305,7 @@ type: 'nn-number' }, { name: 'image', - type: '*' + type: 'image' }, { name: 'callback', type: 'function' diff --git a/lib/util.js b/lib/util.js index 5302835a..7201213f 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,11 +1,13 @@ (function(undefined) { var defs = require('./defs'), - decree = require('decree'); + decree = require('decree'), + Image = require('./Image'); decree.register('color', validateColor); decree.register('interpolation', validateInterpolation); decree.register('axes', validateAxes); + decree.register('image', validateImage); function undefinedFilter(v) { return v !== undefined; @@ -20,6 +22,10 @@ return ['x', 'y', 'xy', 'yx'].indexOf(axes) !== -1; } + function validateImage(img){ + return img instanceof Image; + } + function validateColor(color) { if (typeof color === 'string') { if (!defs.colors[color]) return false;