????
Current Path : C:/inetpub/vhost/invest.gdtsolutions.vn/api/node_modules/@jimp/core/es/ |
Current File : C:/inetpub/vhost/invest.gdtsolutions.vn/api/node_modules/@jimp/core/es/index.js |
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } import fs from "fs"; import Path from "path"; import EventEmitter from "events"; import { isNodePattern, throwError, scan, scanIterator } from "@jimp/utils"; import anyBase from "any-base"; import pixelMatch from "pixelmatch"; import tinyColor from "tinycolor2"; import ImagePHash from "./modules/phash"; import request from "./request"; import composite from "./composite"; import promisify from "./utils/promisify"; import * as MIME from "./utils/mime"; import { parseBitmap, getBuffer, getBufferAsync } from "./utils/image-bitmap"; import * as constants from "./constants"; const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_"; // an array storing the maximum string length of hashes at various bases // 0 and 1 do not exist as possible hash lengths const maxHashLength = [NaN, NaN]; for (let i = 2; i < 65; i++) { const maxHash = anyBase(anyBase.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) { const buffer = Buffer.alloc(arrayBuffer.byteLength); const view = new Uint8Array(arrayBuffer); for (let i = 0; i < buffer.length; ++i) { buffer[i] = view[i]; } return buffer; } function loadFromURL(options, cb) { request(options, (err, data) => { if (err) { return cb(err); } if (typeof data === "object" && Buffer.isBuffer(data)) { return cb(null, data); } if (typeof data === "object" && isArrayBuffer(data)) { return cb(null, bufferFromArrayBuffer(data)); } return new Error(`Could not load Buffer from <${options.url}>`); }); } function loadBufferFromPath(src, cb) { if (fs && typeof fs.readFile === "function" && !src.match(/^(http|ftp)s?:\/\/./)) { fs.readFile(src, cb); } else { loadFromURL({ url: src }, cb); } } function isRawRGBAData(obj) { return obj && typeof 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"); } const rgbaBuffer = Buffer.allocUnsafe(buffer.length / 3 * 4); let j = 0; for (let i = 0; i < buffer.length; i++) { rgbaBuffer[j] = buffer[i]; if ((i + 1) % 3 === 0) { rgbaBuffer[++j] = 255; } j++; } return rgbaBuffer; } const 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 */ class Jimp extends 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 constructor() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } super(); _defineProperty(this, "bitmap", emptyBitmap); _defineProperty(this, "_background", 0x00000000); _defineProperty(this, "_originalMime", Jimp.MIME_PNG); _defineProperty(this, "_exif", null); _defineProperty(this, "_rgba", true); _defineProperty(this, "writeAsync", path => promisify(this.write, this, path)); _defineProperty(this, "getBase64Async", mime => promisify(this.getBase64, this, mime)); _defineProperty(this, "getBuffer", getBuffer); _defineProperty(this, "getBufferAsync", getBufferAsync); _defineProperty(this, "getPixelColour", this.getPixelColor); _defineProperty(this, "setPixelColour", this.setPixelColor); const jimpInstance = this; let 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]; } const [err] = args; const evData = err || {}; evData.methodName = "constructor"; setTimeout(() => { // run on next tick. if (err && cb === noop) { jimpInstance.emitError("constructor", err); } else if (!err) { jimpInstance.emitMulti("constructor", "initialized"); } cb.call(jimpInstance, ...args); }, 1); } if (typeof args[0] === "number" && typeof args[1] === "number" || parseInt(args[0], 10) && parseInt(args[1], 10)) { // create a new image const w = parseInt(args[0], 10); const 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 throwError.call(this, "cb must be a function", finish); } this.bitmap = { data: Buffer.alloc(w * h * 4), width: w, height: h }; for (let i = 0; i < this.bitmap.data.length; i += 4) { this.bitmap.data.writeUInt32BE(this._background, i); } finish(null, this); } else if (typeof args[0] === "object" && args[0].url) { cb = args[1] || noop; if (typeof cb !== "function") { return throwError.call(this, "cb must be a function", finish); } loadFromURL(args[0], (err, data) => { if (err) { return throwError.call(this, err, finish); } this.parseBitmap(data, args[0].url, finish); }); } else if (args[0] instanceof Jimp) { // clone an existing Jimp const [original] = args; cb = args[1]; if (typeof cb === "undefined") { cb = noop; } if (typeof cb !== "function") { return throwError.call(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, this); } else if (isRawRGBAData(args[0])) { const [imageData] = args; cb = args[1] || noop; const isRGBA = imageData.width * imageData.height * 4 === imageData.data.length; const buffer = isRGBA ? Buffer.from(imageData.data) : makeRGBABufferFromRGB(imageData.data); this.bitmap = { data: buffer, width: imageData.width, height: imageData.height }; finish(null, this); } else if (typeof args[0] === "string") { // read from a path const path = args[0]; cb = args[1]; if (typeof cb === "undefined") { cb = noop; } if (typeof cb !== "function") { return throwError.call(this, "cb must be a function", finish); } loadBufferFromPath(path, (err, data) => { if (err) { return throwError.call(this, err, finish); } this.parseBitmap(data, path, finish); }); } else if (typeof args[0] === "object" && Buffer.isBuffer(args[0])) { // read from a buffer const data = args[0]; cb = args[1]; if (typeof cb !== "function") { return throwError.call(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; } } const extraConstructor = Jimp.__extraConstructors.find(c => c.test(...args)); if (extraConstructor) { new Promise((resolve, reject) => { extraConstructor.run.call(this, resolve, reject, ...args); }).then(() => finish(null, this)).catch(finish); } else { return throwError.call(this, "No matching constructor overloading was found. " + "Please see the docs for how to call the Jimp constructor.", finish); } } } /** * 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 */ parseBitmap(data, path, finish) { 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 */ rgba(bool, cb) { if (typeof bool !== "boolean") { return throwError.call(this, "bool must be a boolean, true for RGBA or false for RGB", cb); } this._rgba = bool; if (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 */ emitMulti(methodName, eventName) { let data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; data = Object.assign(data, { methodName, eventName }); this.emit("any", data); if (methodName) { this.emit(methodName, data); } this.emit(eventName, data); } emitError(methodName, err) { this.emitMulti(methodName, "error", err); } /** * Get the current height of the image * @return {number} height of the image */ getHeight() { return this.bitmap.height; } /** * Get the current width of the image * @return {number} width of the image */ getWidth() { return this.bitmap.width; } /** * Nicely format Jimp object when sent to the console e.g. console.log(image) * @returns {string} pretty printed */ inspect() { return "<Jimp " + (this.bitmap === emptyBitmap ? "pending..." : this.bitmap.width + "x" + this.bitmap.height) + ">"; } /** * Nicely format Jimp object when converted to a string * @returns {string} pretty printed */ toString() { return "[object Jimp]"; } /** * Returns the original MIME of the image (default: "image/png") * @returns {string} the MIME */ getMIME() { const 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 */ getExtension() { const 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 */ write(path, cb) { if (!fs || !fs.createWriteStream) { throw new Error("Cant access the filesystem. You can use the getBase64 method."); } if (typeof path !== "string") { return throwError.call(this, "path must be a string", cb); } if (typeof cb === "undefined") { cb = noop; } if (typeof cb !== "function") { return throwError.call(this, "cb must be a function", cb); } const mime = MIME.getType(path) || this.getMIME(); const pathObj = Path.parse(path); if (pathObj.dir) { fs.mkdirSync(pathObj.dir, { recursive: true }); } this.getBuffer(mime, (err, buffer) => { if (err) { return throwError.call(this, err, cb); } const stream = fs.createWriteStream(path); stream.on("open", () => { stream.write(buffer); stream.end(); }).on("error", err => { return throwError.call(this, err, cb); }); stream.on("finish", () => { cb.call(this, null, this); }); }); return this; } /** * 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 */ getBase64(mime, cb) { if (mime === Jimp.AUTO) { // allow auto MIME detection mime = this.getMIME(); } if (typeof mime !== "string") { return throwError.call(this, "mime must be a string", cb); } if (typeof cb !== "function") { return throwError.call(this, "cb must be a function", cb); } this.getBuffer(mime, function (err, data) { if (err) { return throwError.call(this, err, cb); } const src = "data:" + mime + ";base64," + data.toString("base64"); cb.call(this, null, src); }); return this; } /** * Generates a perceptual hash of the image <https://en.wikipedia.org/wiki/Perceptual_hashing>. 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 */ hash(base, cb) { base = base || 64; if (typeof base === "function") { cb = base; base = 64; } if (typeof base !== "number") { return throwError.call(this, "base must be a number", cb); } if (base < 2 || base > 64) { return throwError.call(this, "base must be a number between 2 and 64", cb); } let hash = this.pHash(); hash = anyBase(anyBase.BIN, alphabet.slice(0, base))(hash); while (hash.length < maxHashLength[base]) { hash = "0" + hash; // pad out with leading zeros } if (isNodePattern(cb)) { cb.call(this, null, hash); } return hash; } /** * Calculates the perceptual hash * @returns {number} the perceptual hash */ pHash() { const pHash = new ImagePHash(); 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 */ distanceFromHash(compareHash) { const pHash = new ImagePHash(); const 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 */ /** * Returns the offset of a pixel in the bitmap buffer * @param {number} x the x coordinate * @param {number} y the y coordinate * @param {number} 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 */ getPixelIndex(x, y, edgeHandling, cb) { let xi; let 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 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) { yi = this.bitmap.height + y; } if (y >= this.bitmap.height) { yi = y % this.bitmap.height; } } let 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 (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 */ getPixelColor(x, y, cb) { if (typeof x !== "number" || typeof y !== "number") return throwError.call(this, "x and y must be numbers", cb); // round input x = Math.round(x); y = Math.round(y); const idx = this.getPixelIndex(x, y); const hex = this.bitmap.data.readUInt32BE(idx); if (isNodePattern(cb)) { cb.call(this, null, hex); } return hex; } /** * 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 */ setPixelColor(hex, x, y, cb) { if (typeof hex !== "number" || typeof x !== "number" || typeof y !== "number") return throwError.call(this, "hex, x and y must be numbers", cb); // round input x = Math.round(x); y = Math.round(y); const idx = this.getPixelIndex(x, y); this.bitmap.data.writeUInt32BE(hex, idx); if (isNodePattern(cb)) { cb.call(this, null, this); } return this; } /** * Determine if the image contains opaque pixels. * @return {boolean} hasAlpha whether the image contains opaque pixels */ hasAlpha() { for (let yIndex = 0; yIndex < this.bitmap.height; yIndex++) { for (let xIndex = 0; xIndex < this.bitmap.width; xIndex++) { const idx = this.bitmap.width * yIndex + xIndex << 2; const 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}>} */ scanIterator(x, y, w, h) { if (typeof x !== "number" || typeof y !== "number") { return throwError.call(this, "x and y must be numbers"); } if (typeof w !== "number" || typeof h !== "number") { return throwError.call(this, "w and h must be numbers"); } return scanIterator(this, x, y, w, h); } } export function addConstants(constants) { let jimpInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Jimp; Object.entries(constants).forEach(_ref => { let [name, value] = _ref; jimpInstance[name] = value; }); } export function addJimpMethods(methods) { let jimpInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Jimp; Object.entries(methods).forEach(_ref2 => { let [name, value] = _ref2; jimpInstance.prototype[name] = value; }); } addConstants(constants); addJimpMethods({ composite }); 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, test, 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((resolve, reject) => { // eslint-disable-next-line no-new new Jimp(...args, (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 throwError.call(this, "r, g, b and a must be numbers", cb); } if (r < 0 || r > 255) { return throwError.call(this, "r must be between 0 and 255", cb); } if (g < 0 || g > 255) { throwError.call(this, "g must be between 0 and 255", cb); } if (b < 0 || b > 255) { return throwError.call(this, "b must be between 0 and 255", cb); } if (a < 0 || a > 255) { return 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); const i = r * Math.pow(256, 3) + g * Math.pow(256, 2) + b * Math.pow(256, 1) + a * Math.pow(256, 0); if (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 throwError.call(this, "i must be a number", cb); } const 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 (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(tinyColor(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) { let threshold = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.1; if (!(img1 instanceof Jimp) || !(img2 instanceof Jimp)) return throwError.call(this, "img1 and img2 must be an Jimp images"); const bmp1 = img1.bitmap; const 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 throwError.call(this, "threshold must be a number between 0 and 1"); } const diff = new Jimp(bmp1.width, bmp1.height, 0xffffffff); const numDiffPixels = pixelMatch(bmp1.data, bmp2.data, diff.bitmap.data, diff.bitmap.width, diff.bitmap.height, { 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) { const phash = new ImagePHash(); const hash1 = phash.getHash(img1); const 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) { const phash = new ImagePHash(); 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) { const pow = n => Math.pow(n, 2); const { max } = Math; const 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. */ export function jimpEvMethod(methodName, evName, method) { const evNameBefore = "before-" + evName; const evNameAfter = evName.replace(/e$/, "") + "ed"; Jimp.prototype[methodName] = function () { let wrappedCb; for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } const cb = args[method.length - 1]; const jimpInstance = this; if (typeof cb === "function") { wrappedCb = function () { for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args[_key5] = arguments[_key5]; } const [err, data] = args; if (err) { jimpInstance.emitError(methodName, err); } else { jimpInstance.emitMulti(methodName, evNameAfter, { [methodName]: data }); } cb.apply(this, args); }; args[args.length - 1] = wrappedCb; } else { wrappedCb = false; } this.emitMulti(methodName, evNameBefore); let result; try { result = method.apply(this, args); if (!wrappedCb) { this.emitMulti(methodName, evNameAfter, { [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) { const clone = new Jimp(this); if (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 */ export 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 throwError.call(this, "hex must be a hexadecimal rgba value", cb); } this._background = hex; if (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 throwError.call(this, "x and y must be numbers", cb); } if (typeof w !== "number" || typeof h !== "number") { return throwError.call(this, "w and h must be numbers", cb); } if (typeof f !== "function") { return throwError.call(this, "f must be a function", cb); } const result = scan(this, x, y, w, h, f); if (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 */ let gl; if (typeof window !== "undefined" && typeof window === "object") { gl = window; } if (typeof self !== "undefined" && typeof self === "object") { gl = self; } gl.Jimp = Jimp; gl.Buffer = Buffer; } export { addType } from "./utils/mime"; export default Jimp; //# sourceMappingURL=index.js.map