"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.addConstants = addConstants; exports.addJimpMethods = addJimpMethods; exports.jimpEvMethod = jimpEvMethod; exports.jimpEvChange = jimpEvChange; Object.defineProperty(exports, "addType", { enumerable: true, get: function get() { return MIME.addType; } }); exports["default"] = void 0; var _construct2 = _interopRequireDefault(require("@babel/runtime/helpers/construct")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _fs = _interopRequireDefault(require("fs")); var _path = _interopRequireDefault(require("path")); var _events = _interopRequireDefault(require("events")); var _utils = require("@jimp/utils"); var _anyBase = _interopRequireDefault(require("any-base")); var _mkdirp = _interopRequireDefault(require("mkdirp")); var _pixelmatch = _interopRequireDefault(require("pixelmatch")); var _tinycolor = _interopRequireDefault(require("tinycolor2")); var _phash = _interopRequireDefault(require("./modules/phash")); var _request = _interopRequireDefault(require("./request")); var _composite = _interopRequireDefault(require("./composite")); var _promisify = _interopRequireDefault(require("./utils/promisify")); var MIME = _interopRequireWildcard(require("./utils/mime")); var _imageBitmap = require("./utils/image-bitmap"); var constants = _interopRequireWildcard(require("./constants")); var alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_'; // an array storing the maximum string length of hashes at various bases // 0 and 1 do not exist as possible hash lengths var maxHashLength = [NaN, NaN]; for (var i = 2; i < 65; i++) { var maxHash = (0, _anyBase["default"])(_anyBase["default"].BIN, alphabet.slice(0, i))(new Array(64 + 1).join('1')); maxHashLength.push(maxHash.length); } // no operation function noop() {} // error checking methods function isArrayBuffer(test) { return Object.prototype.toString.call(test).toLowerCase().indexOf('arraybuffer') > -1; } // Prepare a Buffer object from the arrayBuffer. Necessary in the browser > node conversion, // But this function is not useful when running in node directly function bufferFromArrayBuffer(arrayBuffer) { var buffer = Buffer.alloc(arrayBuffer.byteLength); var view = new Uint8Array(arrayBuffer); for (var _i = 0; _i < buffer.length; ++_i) { buffer[_i] = view[_i]; } return buffer; } function loadFromURL(options, cb) { (0, _request["default"])(options, function (err, response, data) { if (err) { return cb(err); } if ('headers' in response && 'location' in response.headers) { options.url = response.headers.location; return loadFromURL(options, cb); } if ((0, _typeof2["default"])(data) === 'object' && Buffer.isBuffer(data)) { return cb(null, data); } var msg = 'Could not load Buffer from <' + options.url + '> ' + '(HTTP: ' + response.statusCode + ')'; return new Error(msg); }); } function loadBufferFromPath(src, cb) { if (_fs["default"] && typeof _fs["default"].readFile === 'function' && !src.match(/^(http|ftp)s?:\/\/./)) { _fs["default"].readFile(src, cb); } else { loadFromURL({ url: src }, cb); } } function isRawRGBAData(obj) { return obj && (0, _typeof2["default"])(obj) === 'object' && typeof obj.width === 'number' && typeof obj.height === 'number' && (Buffer.isBuffer(obj.data) || obj.data instanceof Uint8Array || typeof Uint8ClampedArray === 'function' && obj.data instanceof Uint8ClampedArray) && (obj.data.length === obj.width * obj.height * 4 || obj.data.length === obj.width * obj.height * 3); } function makeRGBABufferFromRGB(buffer) { if (buffer.length % 3 !== 0) { throw new Error('Buffer length is incorrect'); } var rgbaBuffer = Buffer.allocUnsafe(buffer.length / 3 * 4); var j = 0; for (var _i2 = 0; _i2 < buffer.length; _i2++) { rgbaBuffer[j] = buffer[_i2]; if ((_i2 + 1) % 3 === 0) { rgbaBuffer[++j] = 255; } j++; } return rgbaBuffer; } var emptyBitmap = { data: null, width: null, height: null }; /** * Jimp constructor (from a file) * @param path a path to the image * @param {function(Error, Jimp)} cb (optional) a function to call when the image is parsed to a bitmap */ /** * Jimp constructor (from a url with options) * @param options { url, otherOptions} * @param {function(Error, Jimp)} cb (optional) a function to call when the image is parsed to a bitmap */ /** * Jimp constructor (from another Jimp image or raw image data) * @param image a Jimp image to clone * @param {function(Error, Jimp)} cb a function to call when the image is parsed to a bitmap */ /** * Jimp constructor (from a Buffer) * @param data a Buffer containing the image data * @param {function(Error, Jimp)} cb a function to call when the image is parsed to a bitmap */ /** * Jimp constructor (to generate a new image) * @param w the width of the image * @param h the height of the image * @param {function(Error, Jimp)} cb (optional) a function to call when the image is parsed to a bitmap */ /** * Jimp constructor (to generate a new image) * @param w the width of the image * @param h the height of the image * @param background color to fill the image with * @param {function(Error, Jimp)} cb (optional) a function to call when the image is parsed to a bitmap */ var Jimp = /*#__PURE__*/ function (_EventEmitter) { (0, _inherits2["default"])(Jimp, _EventEmitter); // An object representing a bitmap in memory, comprising: // - data: a buffer of the bitmap data // - width: the width of the image in pixels // - height: the height of the image in pixels // Default colour to use for new pixels // Default MIME is PNG // Exif data for the image // Whether Transparency supporting formats will be exported as RGB or RGBA function Jimp() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } (0, _classCallCheck2["default"])(this, Jimp); _this = (0, _possibleConstructorReturn2["default"])(this, (0, _getPrototypeOf2["default"])(Jimp).call(this)); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "bitmap", emptyBitmap); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_background", 0x00000000); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_originalMime", Jimp.MIME_PNG); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_exif", null); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_rgba", true); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "writeAsync", function (path) { return (0, _promisify["default"])(_this.write, (0, _assertThisInitialized2["default"])(_this), path); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getBase64Async", function (mime) { return (0, _promisify["default"])(_this.getBase64, (0, _assertThisInitialized2["default"])(_this), mime); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getBuffer", _imageBitmap.getBuffer); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getBufferAsync", _imageBitmap.getBufferAsync); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getPixelColour", _this.getPixelColor); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "setPixelColour", _this.setPixelColor); var jimpInstance = (0, _assertThisInitialized2["default"])(_this); var cb = noop; if (isArrayBuffer(args[0])) { args[0] = bufferFromArrayBuffer(args[0]); } function finish() { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } var err = args[0]; var evData = err || {}; evData.methodName = 'constructor'; setTimeout(function () { var _cb; // run on next tick. if (err && cb === noop) { jimpInstance.emitError('constructor', err); } else if (!err) { jimpInstance.emitMulti('constructor', 'initialized'); } (_cb = cb).call.apply(_cb, [jimpInstance].concat(args)); }, 1); } if (typeof args[0] === 'number' && typeof args[1] === 'number' || parseInt(args[0], 10) && parseInt(args[1], 10)) { // create a new image var w = parseInt(args[0], 10); var h = parseInt(args[1], 10); cb = args[2]; // with a hex color if (typeof args[2] === 'number') { _this._background = args[2]; cb = args[3]; } // with a css color if (typeof args[2] === 'string') { _this._background = Jimp.cssColorToHex(args[2]); cb = args[3]; } if (typeof cb === 'undefined') { cb = noop; } if (typeof cb !== 'function') { return (0, _possibleConstructorReturn2["default"])(_this, _utils.throwError.call((0, _assertThisInitialized2["default"])(_this), 'cb must be a function', finish)); } _this.bitmap = { data: Buffer.alloc(w * h * 4), width: w, height: h }; for (var _i3 = 0; _i3 < _this.bitmap.data.length; _i3 += 4) { _this.bitmap.data.writeUInt32BE(_this._background, _i3); } finish(null, (0, _assertThisInitialized2["default"])(_this)); } else if ((0, _typeof2["default"])(args[0]) === 'object' && args[0].url) { cb = args[1] || noop; if (typeof cb !== 'function') { return (0, _possibleConstructorReturn2["default"])(_this, _utils.throwError.call((0, _assertThisInitialized2["default"])(_this), 'cb must be a function', finish)); } loadFromURL(args[0], function (err, data) { if (err) { return _utils.throwError.call((0, _assertThisInitialized2["default"])(_this), err, finish); } _this.parseBitmap(data, args[0].url, finish); }); } else if (args[0] instanceof Jimp) { // clone an existing Jimp var original = args[0]; cb = args[1]; if (typeof cb === 'undefined') { cb = noop; } if (typeof cb !== 'function') { return (0, _possibleConstructorReturn2["default"])(_this, _utils.throwError.call((0, _assertThisInitialized2["default"])(_this), 'cb must be a function', finish)); } _this.bitmap = { data: Buffer.from(original.bitmap.data), width: original.bitmap.width, height: original.bitmap.height }; _this._quality = original._quality; _this._deflateLevel = original._deflateLevel; _this._deflateStrategy = original._deflateStrategy; _this._filterType = original._filterType; _this._rgba = original._rgba; _this._background = original._background; _this._originalMime = original._originalMime; finish(null, (0, _assertThisInitialized2["default"])(_this)); } else if (isRawRGBAData(args[0])) { var imageData = args[0]; cb = args[1] || noop; var isRGBA = imageData.width * imageData.height * 4 === imageData.data.length; var buffer = isRGBA ? Buffer.from(imageData.data) : makeRGBABufferFromRGB(imageData.data); _this.bitmap = { data: buffer, width: imageData.width, height: imageData.height }; finish(null, (0, _assertThisInitialized2["default"])(_this)); } else if (typeof args[0] === 'string') { // read from a path var path = args[0]; cb = args[1]; if (typeof cb === 'undefined') { cb = noop; } if (typeof cb !== 'function') { return (0, _possibleConstructorReturn2["default"])(_this, _utils.throwError.call((0, _assertThisInitialized2["default"])(_this), 'cb must be a function', finish)); } loadBufferFromPath(path, function (err, data) { if (err) { return _utils.throwError.call((0, _assertThisInitialized2["default"])(_this), err, finish); } _this.parseBitmap(data, path, finish); }); } else if ((0, _typeof2["default"])(args[0]) === 'object' && Buffer.isBuffer(args[0])) { // read from a buffer var data = args[0]; cb = args[1]; if (typeof cb !== 'function') { return (0, _possibleConstructorReturn2["default"])(_this, _utils.throwError.call((0, _assertThisInitialized2["default"])(_this), 'cb must be a function', finish)); } _this.parseBitmap(data, null, finish); } else { // Allow client libs to add new ways to build a Jimp object. // Extra constructors must be added by `Jimp.appendConstructorOption()` cb = args[args.length - 1]; if (typeof cb !== 'function') { // TODO: try to solve the args after cb problem. cb = args[args.length - 2]; if (typeof cb !== 'function') { cb = noop; } } var extraConstructor = Jimp.__extraConstructors.find(function (c) { return c.test.apply(c, args); }); if (extraConstructor) { new Promise(function (resolve, reject) { var _extraConstructor$run; return (_extraConstructor$run = extraConstructor.run).call.apply(_extraConstructor$run, [(0, _assertThisInitialized2["default"])(_this), resolve, reject].concat(args)); }).then(function () { return finish(null, (0, _assertThisInitialized2["default"])(_this)); })["catch"](finish); } else { return (0, _possibleConstructorReturn2["default"])(_this, _utils.throwError.call((0, _assertThisInitialized2["default"])(_this), 'No matching constructor overloading was found. ' + 'Please see the docs for how to call the Jimp constructor.', finish)); } } return _this; } /** * Parse a bitmap with the loaded image types. * * @param {Buffer} data raw image data * @param {string} path optional path to file * @param {function(Error, Jimp)} finish (optional) a callback for when complete * @memberof Jimp */ (0, _createClass2["default"])(Jimp, [{ key: "parseBitmap", value: function parseBitmap(data, path, finish) { _imageBitmap.parseBitmap.call(this, data, null, finish); } /** * Sets the type of the image (RGB or RGBA) when saving in a format that supports transparency (default is RGBA) * @param {boolean} bool A Boolean, true to use RGBA or false to use RGB * @param {function(Error, Jimp)} cb (optional) a callback for when complete * @returns {Jimp} this for chaining of methods */ }, { key: "rgba", value: function rgba(bool, cb) { if (typeof bool !== 'boolean') { return _utils.throwError.call(this, 'bool must be a boolean, true for RGBA or false for RGB', cb); } this._rgba = bool; if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, this); } return this; } /** * Emit for multiple listeners * @param {string} methodName name of the method to emit an error for * @param {string} eventName name of the eventName to emit an error for * @param {object} data to emit */ }, { key: "emitMulti", value: function emitMulti(methodName, eventName) { var data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; data = Object.assign(data, { methodName: methodName, eventName: eventName }); this.emit('any', data); if (methodName) { this.emit(methodName, data); } this.emit(eventName, data); } }, { key: "emitError", value: function emitError(methodName, err) { this.emitMulti(methodName, 'error', err); } /** * Get the current height of the image * @return {number} height of the image */ }, { key: "getHeight", value: function getHeight() { return this.bitmap.height; } /** * Get the current width of the image * @return {number} width of the image */ }, { key: "getWidth", value: function getWidth() { return this.bitmap.width; } /** * Nicely format Jimp object when sent to the console e.g. console.log(image) * @returns {string} pretty printed */ }, { key: "inspect", value: function inspect() { return ''; } /** * Nicely format Jimp object when converted to a string * @returns {string} pretty printed */ }, { key: "toString", value: function toString() { return '[object Jimp]'; } /** * Returns the original MIME of the image (default: "image/png") * @returns {string} the MIME */ }, { key: "getMIME", value: function getMIME() { var mime = this._originalMime || Jimp.MIME_PNG; return mime; } /** * Returns the appropriate file extension for the original MIME of the image (default: "png") * @returns {string} the file extension */ }, { key: "getExtension", value: function getExtension() { var mime = this.getMIME(); return MIME.getExtension(mime); } /** * Writes the image to a file * @param {string} path a path to the destination file * @param {function(Error, Jimp)} cb (optional) a function to call when the image is saved to disk * @returns {Jimp} this for chaining of methods */ }, { key: "write", value: function write(path, cb) { var _this2 = this; if (!_fs["default"] || !_fs["default"].createWriteStream) { throw new Error('Cant access the filesystem. You can use the getBase64 method.'); } if (typeof path !== 'string') { return _utils.throwError.call(this, 'path must be a string', cb); } if (typeof cb === 'undefined') { cb = noop; } if (typeof cb !== 'function') { return _utils.throwError.call(this, 'cb must be a function', cb); } var mime = MIME.getType(path) || this.getMIME(); var pathObj = _path["default"].parse(path); if (pathObj.dir) { _mkdirp["default"].sync(pathObj.dir); } this.getBuffer(mime, function (err, buffer) { if (err) { return _utils.throwError.call(_this2, err, cb); } var stream = _fs["default"].createWriteStream(path); stream.on('open', function () { stream.write(buffer); stream.end(); }).on('error', function (err) { return _utils.throwError.call(_this2, err, cb); }); stream.on('finish', function () { cb.call(_this2, null, _this2); }); }); return this; } }, { key: "getBase64", /** * Converts the image to a base 64 string * @param {string} mime the mime type of the image data to be created * @param {function(Error, Jimp)} cb a Node-style function to call with the buffer as the second argument * @returns {Jimp} this for chaining of methods */ value: function getBase64(mime, cb) { if (mime === Jimp.AUTO) { // allow auto MIME detection mime = this.getMIME(); } if (typeof mime !== 'string') { return _utils.throwError.call(this, 'mime must be a string', cb); } if (typeof cb !== 'function') { return _utils.throwError.call(this, 'cb must be a function', cb); } this.getBuffer(mime, function (err, data) { if (err) { return _utils.throwError.call(this, err, cb); } var src = 'data:' + mime + ';base64,' + data.toString('base64'); cb.call(this, null, src); }); return this; } }, { key: "hash", /** * Generates a perceptual hash of the image . And pads the string. Can configure base. * @param {number} base (optional) a number between 2 and 64 representing the base for the hash (e.g. 2 is binary, 10 is decimal, 16 is hex, 64 is base 64). Defaults to 64. * @param {function(Error, Jimp)} cb (optional) a callback for when complete * @returns {string} a string representing the hash */ value: function hash(base, cb) { base = base || 64; if (typeof base === 'function') { cb = base; base = 64; } if (typeof base !== 'number') { return _utils.throwError.call(this, 'base must be a number', cb); } if (base < 2 || base > 64) { return _utils.throwError.call(this, 'base must be a number between 2 and 64', cb); } var hash = this.pHash(); hash = (0, _anyBase["default"])(_anyBase["default"].BIN, alphabet.slice(0, base))(hash); while (hash.length < maxHashLength[base]) { hash = '0' + hash; // pad out with leading zeros } if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, hash); } return hash; } /** * Calculates the perceptual hash * @returns {number} the perceptual hash */ }, { key: "pHash", value: function pHash() { var pHash = new _phash["default"](); return pHash.getHash(this); } /** * Calculates the hamming distance of the current image and a hash based on their perceptual hash * @param {hash} compareHash hash to compare to * @returns {number} a number ranging from 0 to 1, 0 means they are believed to be identical */ }, { key: "distanceFromHash", value: function distanceFromHash(compareHash) { var pHash = new _phash["default"](); var currentHash = pHash.getHash(this); return pHash.distance(currentHash, compareHash); } /** * Converts the image to a buffer * @param {string} mime the mime type of the image buffer to be created * @param {function(Error, Jimp)} cb a Node-style function to call with the buffer as the second argument * @returns {Jimp} this for chaining of methods */ }, { key: "getPixelIndex", /** * Returns the offset of a pixel in the bitmap buffer * @param {number} x the x coordinate * @param {number} y the y coordinate * @param {string} edgeHandling (optional) define how to sum pixels from outside the border * @param {number} cb (optional) a callback for when complete * @returns {number} the index of the pixel or -1 if not found */ value: function getPixelIndex(x, y, edgeHandling, cb) { var xi; var yi; if (typeof edgeHandling === 'function' && typeof cb === 'undefined') { cb = edgeHandling; edgeHandling = null; } if (!edgeHandling) { edgeHandling = Jimp.EDGE_EXTEND; } if (typeof x !== 'number' || typeof y !== 'number') { return _utils.throwError.call(this, 'x and y must be numbers', cb); } // round input x = Math.round(x); y = Math.round(y); xi = x; yi = y; if (edgeHandling === Jimp.EDGE_EXTEND) { if (x < 0) xi = 0; if (x >= this.bitmap.width) xi = this.bitmap.width - 1; if (y < 0) yi = 0; if (y >= this.bitmap.height) yi = this.bitmap.height - 1; } if (edgeHandling === Jimp.EDGE_WRAP) { if (x < 0) { xi = this.bitmap.width + x; } if (x >= this.bitmap.width) { xi = x % this.bitmap.width; } if (y < 0) { xi = this.bitmap.height + y; } if (y >= this.bitmap.height) { yi = y % this.bitmap.height; } } var i = this.bitmap.width * yi + xi << 2; // if out of bounds index is -1 if (xi < 0 || xi >= this.bitmap.width) { i = -1; } if (yi < 0 || yi >= this.bitmap.height) { i = -1; } if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, i); } return i; } /** * Returns the hex colour value of a pixel * @param {number} x the x coordinate * @param {number} y the y coordinate * @param {function(Error, Jimp)} cb (optional) a callback for when complete * @returns {number} the color of the pixel */ }, { key: "getPixelColor", value: function getPixelColor(x, y, cb) { if (typeof x !== 'number' || typeof y !== 'number') return _utils.throwError.call(this, 'x and y must be numbers', cb); // round input x = Math.round(x); y = Math.round(y); var idx = this.getPixelIndex(x, y); var hex = this.bitmap.data.readUInt32BE(idx); if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, hex); } return hex; } }, { key: "setPixelColor", /** * Returns the hex colour value of a pixel * @param {number} hex color to set * @param {number} x the x coordinate * @param {number} y the y coordinate * @param {function(Error, Jimp)} cb (optional) a callback for when complete * @returns {number} the index of the pixel or -1 if not found */ value: function setPixelColor(hex, x, y, cb) { if (typeof hex !== 'number' || typeof x !== 'number' || typeof y !== 'number') return _utils.throwError.call(this, 'hex, x and y must be numbers', cb); // round input x = Math.round(x); y = Math.round(y); var idx = this.getPixelIndex(x, y); this.bitmap.data.writeUInt32BE(hex, idx); if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, this); } return this; } }, { key: "hasAlpha", /** * Determine if the image contains opaque pixels. * @return {boolean} hasAlpha whether the image contains opaque pixels */ value: function hasAlpha() { for (var yIndex = 0; yIndex < this.bitmap.height; yIndex++) { for (var xIndex = 0; xIndex < this.bitmap.width; xIndex++) { var idx = this.bitmap.width * yIndex + xIndex << 2; var alpha = this.bitmap.data[idx + 3]; if (alpha !== 0xff) { return true; } } } return false; } /** * Iterate scan through a region of the bitmap * @param {number} x the x coordinate to begin the scan at * @param {number} y the y coordinate to begin the scan at * @param w the width of the scan region * @param h the height of the scan region * @returns {IterableIterator<{x: number, y: number, idx: number, image: Jimp}>} */ }, { key: "scanIterator", value: function scanIterator(x, y, w, h) { if (typeof x !== 'number' || typeof y !== 'number') { return _utils.throwError.call(this, 'x and y must be numbers'); } if (typeof w !== 'number' || typeof h !== 'number') { return _utils.throwError.call(this, 'w and h must be numbers'); } return (0, _utils.scanIterator)(this, x, y, w, h); } }]); return Jimp; }(_events["default"]); function addConstants(constants) { var jimpInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Jimp; Object.entries(constants).forEach(function (_ref) { var _ref2 = (0, _slicedToArray2["default"])(_ref, 2), name = _ref2[0], value = _ref2[1]; jimpInstance[name] = value; }); } function addJimpMethods(methods) { var jimpInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Jimp; Object.entries(methods).forEach(function (_ref3) { var _ref4 = (0, _slicedToArray2["default"])(_ref3, 2), name = _ref4[0], value = _ref4[1]; jimpInstance.prototype[name] = value; }); } addConstants(constants); addJimpMethods({ composite: _composite["default"] }); Jimp.__extraConstructors = []; /** * Allow client libs to add new ways to build a Jimp object. * @param {string} name identify the extra constructor. * @param {function} test a function that returns true when it accepts the arguments passed to the main constructor. * @param {function} run where the magic happens. */ Jimp.appendConstructorOption = function (name, test, run) { Jimp.__extraConstructors.push({ name: name, test: test, run: run }); }; /** * Read an image from a file or a Buffer. Takes the same args as the constructor * @returns {Promise} a promise */ Jimp.read = function () { for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } return new Promise(function (resolve, reject) { (0, _construct2["default"])(Jimp, args.concat([function (err, image) { if (err) reject(err);else resolve(image); }])); }); }; Jimp.create = Jimp.read; /** * A static helper method that converts RGBA values to a single integer value * @param {number} r the red value (0-255) * @param {number} g the green value (0-255) * @param {number} b the blue value (0-255) * @param {number} a the alpha value (0-255) * @param {function(Error, Jimp)} cb (optional) A callback for when complete * @returns {number} an single integer colour value */ Jimp.rgbaToInt = function (r, g, b, a, cb) { if (typeof r !== 'number' || typeof g !== 'number' || typeof b !== 'number' || typeof a !== 'number') { return _utils.throwError.call(this, 'r, g, b and a must be numbers', cb); } if (r < 0 || r > 255) { return _utils.throwError.call(this, 'r must be between 0 and 255', cb); } if (g < 0 || g > 255) { _utils.throwError.call(this, 'g must be between 0 and 255', cb); } if (b < 0 || b > 255) { return _utils.throwError.call(this, 'b must be between 0 and 255', cb); } if (a < 0 || a > 255) { return _utils.throwError.call(this, 'a must be between 0 and 255', cb); } r = Math.round(r); b = Math.round(b); g = Math.round(g); a = Math.round(a); var i = r * Math.pow(256, 3) + g * Math.pow(256, 2) + b * Math.pow(256, 1) + a * Math.pow(256, 0); if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, i); } return i; }; /** * A static helper method that converts RGBA values to a single integer value * @param {number} i a single integer value representing an RGBA colour (e.g. 0xFF0000FF for red) * @param {function(Error, Jimp)} cb (optional) A callback for when complete * @returns {object} an object with the properties r, g, b and a representing RGBA values */ Jimp.intToRGBA = function (i, cb) { if (typeof i !== 'number') { return _utils.throwError.call(this, 'i must be a number', cb); } var rgba = {}; rgba.r = Math.floor(i / Math.pow(256, 3)); rgba.g = Math.floor((i - rgba.r * Math.pow(256, 3)) / Math.pow(256, 2)); rgba.b = Math.floor((i - rgba.r * Math.pow(256, 3) - rgba.g * Math.pow(256, 2)) / Math.pow(256, 1)); rgba.a = Math.floor((i - rgba.r * Math.pow(256, 3) - rgba.g * Math.pow(256, 2) - rgba.b * Math.pow(256, 1)) / Math.pow(256, 0)); if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, rgba); } return rgba; }; /** * Converts a css color (Hex, 8-digit (RGBA) Hex, RGB, RGBA, HSL, HSLA, HSV, HSVA, Named) to a hex number * @param {string} cssColor a number * @returns {number} a hex number representing a color */ Jimp.cssColorToHex = function (cssColor) { cssColor = cssColor || 0; // 0, null, undefined, NaN if (typeof cssColor === 'number') return Number(cssColor); return parseInt((0, _tinycolor["default"])(cssColor).toHex8(), 16); }; /** * Limits a number to between 0 or 255 * @param {number} n a number * @returns {number} the number limited to between 0 or 255 */ Jimp.limit255 = function (n) { n = Math.max(n, 0); n = Math.min(n, 255); return n; }; /** * Diffs two images and returns * @param {Jimp} img1 a Jimp image to compare * @param {Jimp} img2 a Jimp image to compare * @param {number} threshold (optional) a number, 0 to 1, the smaller the value the more sensitive the comparison (default: 0.1) * @returns {object} an object { percent: percent similar, diff: a Jimp image highlighting differences } */ Jimp.diff = function (img1, img2) { var threshold = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.1; if (!(img1 instanceof Jimp) || !(img2 instanceof Jimp)) return _utils.throwError.call(this, 'img1 and img2 must be an Jimp images'); var bmp1 = img1.bitmap; var bmp2 = img2.bitmap; if (bmp1.width !== bmp2.width || bmp1.height !== bmp2.height) { if (bmp1.width * bmp1.height > bmp2.width * bmp2.height) { // img1 is bigger img1 = img1.cloneQuiet().resize(bmp2.width, bmp2.height); } else { // img2 is bigger (or they are the same in area) img2 = img2.cloneQuiet().resize(bmp1.width, bmp1.height); } } if (typeof threshold !== 'number' || threshold < 0 || threshold > 1) { return _utils.throwError.call(this, 'threshold must be a number between 0 and 1'); } var diff = new Jimp(bmp1.width, bmp1.height, 0xffffffff); var numDiffPixels = (0, _pixelmatch["default"])(bmp1.data, bmp2.data, diff.bitmap.data, diff.bitmap.width, diff.bitmap.height, { threshold: threshold }); return { percent: numDiffPixels / (diff.bitmap.width * diff.bitmap.height), image: diff }; }; /** * Calculates the hamming distance of two images based on their perceptual hash * @param {Jimp} img1 a Jimp image to compare * @param {Jimp} img2 a Jimp image to compare * @returns {number} a number ranging from 0 to 1, 0 means they are believed to be identical */ Jimp.distance = function (img1, img2) { var phash = new _phash["default"](); var hash1 = phash.getHash(img1); var hash2 = phash.getHash(img2); return phash.distance(hash1, hash2); }; /** * Calculates the hamming distance of two images based on their perceptual hash * @param {hash} hash1 a pHash * @param {hash} hash2 a pHash * @returns {number} a number ranging from 0 to 1, 0 means they are believed to be identical */ Jimp.compareHashes = function (hash1, hash2) { var phash = new _phash["default"](); return phash.distance(hash1, hash2); }; /** * Compute color difference * 0 means no difference, 1 means maximum difference. * @param {number} rgba1: first color to compare. * @param {number} rgba2: second color to compare. * Both parameters must be an color object {r:val, g:val, b:val, a:val} * Where `a` is optional and `val` is an integer between 0 and 255. * @returns {number} float between 0 and 1. */ Jimp.colorDiff = function (rgba1, rgba2) { var pow = function pow(n) { return Math.pow(n, 2); }; var max = Math.max; var maxVal = 255 * 255 * 3; if (rgba1.a !== 0 && !rgba1.a) { rgba1.a = 255; } if (rgba2.a !== 0 && !rgba2.a) { rgba2.a = 255; } return (max(pow(rgba1.r - rgba2.r), pow(rgba1.r - rgba2.r - rgba1.a + rgba2.a)) + max(pow(rgba1.g - rgba2.g), pow(rgba1.g - rgba2.g - rgba1.a + rgba2.a)) + max(pow(rgba1.b - rgba2.b), pow(rgba1.b - rgba2.b - rgba1.a + rgba2.a))) / maxVal; }; /** * Helper to create Jimp methods that emit events before and after its execution. * @param {string} methodName The name to be appended to Jimp prototype. * @param {string} evName The event name to be called. * It will be prefixed by `before-` and emitted when on method call. * It will be appended by `ed` and emitted after the method run. * @param {function} method A function implementing the method itself. * It will also create a quiet version that will not emit events, to not * mess the user code with many `changed` event calls. You can call with * `methodName + "Quiet"`. * * The emitted event comes with a object parameter to the listener with the * `methodName` as one attribute. */ function jimpEvMethod(methodName, evName, method) { var evNameBefore = 'before-' + evName; var evNameAfter = evName.replace(/e$/, '') + 'ed'; Jimp.prototype[methodName] = function () { var wrappedCb; for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } var cb = args[method.length - 1]; var jimpInstance = this; if (typeof cb === 'function') { wrappedCb = function wrappedCb() { for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args[_key5] = arguments[_key5]; } var err = args[0], data = args[1]; if (err) { jimpInstance.emitError(methodName, err); } else { jimpInstance.emitMulti(methodName, evNameAfter, (0, _defineProperty2["default"])({}, methodName, data)); } cb.apply(this, args); }; args[args.length - 1] = wrappedCb; } else { wrappedCb = false; } this.emitMulti(methodName, evNameBefore); var result; try { result = method.apply(this, args); if (!wrappedCb) { this.emitMulti(methodName, evNameAfter, (0, _defineProperty2["default"])({}, methodName, result)); } } catch (error) { error.methodName = methodName; this.emitError(methodName, error); } return result; }; Jimp.prototype[methodName + 'Quiet'] = method; } /** * Creates a new image that is a clone of this one. * @param {function(Error, Jimp)} cb (optional) A callback for when complete * @returns the new image */ jimpEvMethod('clone', 'clone', function (cb) { var clone = new Jimp(this); if ((0, _utils.isNodePattern)(cb)) { cb.call(clone, null, clone); } return clone; }); /** * Simplify jimpEvMethod call for the common `change` evName. * @param {string} methodName name of the method * @param {function} method to watch changes for */ function jimpEvChange(methodName, method) { jimpEvMethod(methodName, 'change', method); } /** * Sets the type of the image (RGB or RGBA) when saving as PNG format (default is RGBA) * @param b A Boolean, true to use RGBA or false to use RGB * @param {function(Error, Jimp)} cb (optional) a callback for when complete * @returns {Jimp} this for chaining of methods */ jimpEvChange('background', function (hex, cb) { if (typeof hex !== 'number') { return _utils.throwError.call(this, 'hex must be a hexadecimal rgba value', cb); } this._background = hex; if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, this); } return this; }); /** * Scans through a region of the bitmap, calling a function for each pixel. * @param {number} x the x coordinate to begin the scan at * @param {number} y the y coordinate to begin the scan at * @param w the width of the scan region * @param h the height of the scan region * @param f a function to call on even pixel; the (x, y) position of the pixel * and the index of the pixel in the bitmap buffer are passed to the function * @param {function(Error, Jimp)} cb (optional) a callback for when complete * @returns {Jimp} this for chaining of methods */ jimpEvChange('scan', function (x, y, w, h, f, cb) { if (typeof x !== 'number' || typeof y !== 'number') { return _utils.throwError.call(this, 'x and y must be numbers', cb); } if (typeof w !== 'number' || typeof h !== 'number') { return _utils.throwError.call(this, 'w and h must be numbers', cb); } if (typeof f !== 'function') { return _utils.throwError.call(this, 'f must be a function', cb); } var result = (0, _utils.scan)(this, x, y, w, h, f); if ((0, _utils.isNodePattern)(cb)) { cb.call(this, null, result); } return result; }); if (process.env.ENVIRONMENT === 'BROWSER') { // For use in a web browser or web worker /* global self */ var gl; if (typeof window !== 'undefined' && (typeof window === "undefined" ? "undefined" : (0, _typeof2["default"])(window)) === 'object') { gl = window; } if (typeof self !== 'undefined' && (typeof self === "undefined" ? "undefined" : (0, _typeof2["default"])(self)) === 'object') { gl = self; } gl.Jimp = Jimp; gl.Buffer = Buffer; } var _default = Jimp; exports["default"] = _default; //# sourceMappingURL=index.js.map