mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2315 lines
76 KiB
2315 lines
76 KiB
/*
|
|
Stencil Screenshot Pixel Match v4.38.0 | MIT Licensed | https://stenciljs.com
|
|
*/
|
|
"use strict";
|
|
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __commonJS = (cb, mod) => function __require() {
|
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
// file that has been converted to a CommonJS file using a Babel-
|
|
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
mod
|
|
));
|
|
|
|
// node_modules/pixelmatch/index.js
|
|
var require_pixelmatch = __commonJS({
|
|
"node_modules/pixelmatch/index.js"(exports2, module2) {
|
|
"use strict";
|
|
module2.exports = pixelmatch2;
|
|
var defaultOptions = {
|
|
threshold: 0.1,
|
|
// matching threshold (0 to 1); smaller is more sensitive
|
|
includeAA: false,
|
|
// whether to skip anti-aliasing detection
|
|
alpha: 0.1,
|
|
// opacity of original image in diff output
|
|
aaColor: [255, 255, 0],
|
|
// color of anti-aliased pixels in diff output
|
|
diffColor: [255, 0, 0],
|
|
// color of different pixels in diff output
|
|
diffColorAlt: null,
|
|
// whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two
|
|
diffMask: false
|
|
// draw the diff over a transparent background (a mask)
|
|
};
|
|
function pixelmatch2(img1, img2, output, width, height, options) {
|
|
if (!isPixelData(img1) || !isPixelData(img2) || output && !isPixelData(output))
|
|
throw new Error("Image data: Uint8Array, Uint8ClampedArray or Buffer expected.");
|
|
if (img1.length !== img2.length || output && output.length !== img1.length)
|
|
throw new Error("Image sizes do not match.");
|
|
if (img1.length !== width * height * 4) throw new Error("Image data size does not match width/height.");
|
|
options = Object.assign({}, defaultOptions, options);
|
|
const len = width * height;
|
|
const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);
|
|
const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);
|
|
let identical = true;
|
|
for (let i = 0; i < len; i++) {
|
|
if (a32[i] !== b32[i]) {
|
|
identical = false;
|
|
break;
|
|
}
|
|
}
|
|
if (identical) {
|
|
if (output && !options.diffMask) {
|
|
for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, options.alpha, output);
|
|
}
|
|
return 0;
|
|
}
|
|
const maxDelta = 35215 * options.threshold * options.threshold;
|
|
let diff = 0;
|
|
for (let y = 0; y < height; y++) {
|
|
for (let x = 0; x < width; x++) {
|
|
const pos = (y * width + x) * 4;
|
|
const delta = colorDelta(img1, img2, pos, pos);
|
|
if (Math.abs(delta) > maxDelta) {
|
|
if (!options.includeAA && (antialiased(img1, x, y, width, height, img2) || antialiased(img2, x, y, width, height, img1))) {
|
|
if (output && !options.diffMask) drawPixel(output, pos, ...options.aaColor);
|
|
} else {
|
|
if (output) {
|
|
drawPixel(output, pos, ...delta < 0 && options.diffColorAlt || options.diffColor);
|
|
}
|
|
diff++;
|
|
}
|
|
} else if (output) {
|
|
if (!options.diffMask) drawGrayPixel(img1, pos, options.alpha, output);
|
|
}
|
|
}
|
|
}
|
|
return diff;
|
|
}
|
|
function isPixelData(arr) {
|
|
return ArrayBuffer.isView(arr) && arr.constructor.BYTES_PER_ELEMENT === 1;
|
|
}
|
|
function antialiased(img, x1, y1, width, height, img2) {
|
|
const x0 = Math.max(x1 - 1, 0);
|
|
const y0 = Math.max(y1 - 1, 0);
|
|
const x2 = Math.min(x1 + 1, width - 1);
|
|
const y2 = Math.min(y1 + 1, height - 1);
|
|
const pos = (y1 * width + x1) * 4;
|
|
let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;
|
|
let min = 0;
|
|
let max = 0;
|
|
let minX, minY, maxX, maxY;
|
|
for (let x = x0; x <= x2; x++) {
|
|
for (let y = y0; y <= y2; y++) {
|
|
if (x === x1 && y === y1) continue;
|
|
const delta = colorDelta(img, img, pos, (y * width + x) * 4, true);
|
|
if (delta === 0) {
|
|
zeroes++;
|
|
if (zeroes > 2) return false;
|
|
} else if (delta < min) {
|
|
min = delta;
|
|
minX = x;
|
|
minY = y;
|
|
} else if (delta > max) {
|
|
max = delta;
|
|
maxX = x;
|
|
maxY = y;
|
|
}
|
|
}
|
|
}
|
|
if (min === 0 || max === 0) return false;
|
|
return hasManySiblings(img, minX, minY, width, height) && hasManySiblings(img2, minX, minY, width, height) || hasManySiblings(img, maxX, maxY, width, height) && hasManySiblings(img2, maxX, maxY, width, height);
|
|
}
|
|
function hasManySiblings(img, x1, y1, width, height) {
|
|
const x0 = Math.max(x1 - 1, 0);
|
|
const y0 = Math.max(y1 - 1, 0);
|
|
const x2 = Math.min(x1 + 1, width - 1);
|
|
const y2 = Math.min(y1 + 1, height - 1);
|
|
const pos = (y1 * width + x1) * 4;
|
|
let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;
|
|
for (let x = x0; x <= x2; x++) {
|
|
for (let y = y0; y <= y2; y++) {
|
|
if (x === x1 && y === y1) continue;
|
|
const pos2 = (y * width + x) * 4;
|
|
if (img[pos] === img[pos2] && img[pos + 1] === img[pos2 + 1] && img[pos + 2] === img[pos2 + 2] && img[pos + 3] === img[pos2 + 3]) zeroes++;
|
|
if (zeroes > 2) return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function colorDelta(img1, img2, k, m, yOnly) {
|
|
let r1 = img1[k + 0];
|
|
let g1 = img1[k + 1];
|
|
let b1 = img1[k + 2];
|
|
let a1 = img1[k + 3];
|
|
let r2 = img2[m + 0];
|
|
let g2 = img2[m + 1];
|
|
let b2 = img2[m + 2];
|
|
let a2 = img2[m + 3];
|
|
if (a1 === a2 && r1 === r2 && g1 === g2 && b1 === b2) return 0;
|
|
if (a1 < 255) {
|
|
a1 /= 255;
|
|
r1 = blend(r1, a1);
|
|
g1 = blend(g1, a1);
|
|
b1 = blend(b1, a1);
|
|
}
|
|
if (a2 < 255) {
|
|
a2 /= 255;
|
|
r2 = blend(r2, a2);
|
|
g2 = blend(g2, a2);
|
|
b2 = blend(b2, a2);
|
|
}
|
|
const y1 = rgb2y(r1, g1, b1);
|
|
const y2 = rgb2y(r2, g2, b2);
|
|
const y = y1 - y2;
|
|
if (yOnly) return y;
|
|
const i = rgb2i(r1, g1, b1) - rgb2i(r2, g2, b2);
|
|
const q = rgb2q(r1, g1, b1) - rgb2q(r2, g2, b2);
|
|
const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;
|
|
return y1 > y2 ? -delta : delta;
|
|
}
|
|
function rgb2y(r, g, b) {
|
|
return r * 0.29889531 + g * 0.58662247 + b * 0.11448223;
|
|
}
|
|
function rgb2i(r, g, b) {
|
|
return r * 0.59597799 - g * 0.2741761 - b * 0.32180189;
|
|
}
|
|
function rgb2q(r, g, b) {
|
|
return r * 0.21147017 - g * 0.52261711 + b * 0.31114694;
|
|
}
|
|
function blend(c, a) {
|
|
return 255 + (c - 255) * a;
|
|
}
|
|
function drawPixel(output, pos, r, g, b) {
|
|
output[pos + 0] = r;
|
|
output[pos + 1] = g;
|
|
output[pos + 2] = b;
|
|
output[pos + 3] = 255;
|
|
}
|
|
function drawGrayPixel(img, i, alpha, output) {
|
|
const r = img[i + 0];
|
|
const g = img[i + 1];
|
|
const b = img[i + 2];
|
|
const val = blend(rgb2y(r, g, b), alpha * img[i + 3] / 255);
|
|
drawPixel(output, i, val, val, val);
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/chunkstream.js
|
|
var require_chunkstream = __commonJS({
|
|
"node_modules/pngjs/lib/chunkstream.js"(exports2, module2) {
|
|
"use strict";
|
|
var util = require("util");
|
|
var Stream = require("stream");
|
|
var ChunkStream = module2.exports = function() {
|
|
Stream.call(this);
|
|
this._buffers = [];
|
|
this._buffered = 0;
|
|
this._reads = [];
|
|
this._paused = false;
|
|
this._encoding = "utf8";
|
|
this.writable = true;
|
|
};
|
|
util.inherits(ChunkStream, Stream);
|
|
ChunkStream.prototype.read = function(length, callback) {
|
|
this._reads.push({
|
|
length: Math.abs(length),
|
|
// if length < 0 then at most this length
|
|
allowLess: length < 0,
|
|
func: callback
|
|
});
|
|
process.nextTick(
|
|
(function() {
|
|
this._process();
|
|
if (this._paused && this._reads && this._reads.length > 0) {
|
|
this._paused = false;
|
|
this.emit("drain");
|
|
}
|
|
}).bind(this)
|
|
);
|
|
};
|
|
ChunkStream.prototype.write = function(data, encoding) {
|
|
if (!this.writable) {
|
|
this.emit("error", new Error("Stream not writable"));
|
|
return false;
|
|
}
|
|
let dataBuffer;
|
|
if (Buffer.isBuffer(data)) {
|
|
dataBuffer = data;
|
|
} else {
|
|
dataBuffer = Buffer.from(data, encoding || this._encoding);
|
|
}
|
|
this._buffers.push(dataBuffer);
|
|
this._buffered += dataBuffer.length;
|
|
this._process();
|
|
if (this._reads && this._reads.length === 0) {
|
|
this._paused = true;
|
|
}
|
|
return this.writable && !this._paused;
|
|
};
|
|
ChunkStream.prototype.end = function(data, encoding) {
|
|
if (data) {
|
|
this.write(data, encoding);
|
|
}
|
|
this.writable = false;
|
|
if (!this._buffers) {
|
|
return;
|
|
}
|
|
if (this._buffers.length === 0) {
|
|
this._end();
|
|
} else {
|
|
this._buffers.push(null);
|
|
this._process();
|
|
}
|
|
};
|
|
ChunkStream.prototype.destroySoon = ChunkStream.prototype.end;
|
|
ChunkStream.prototype._end = function() {
|
|
if (this._reads.length > 0) {
|
|
this.emit("error", new Error("Unexpected end of input"));
|
|
}
|
|
this.destroy();
|
|
};
|
|
ChunkStream.prototype.destroy = function() {
|
|
if (!this._buffers) {
|
|
return;
|
|
}
|
|
this.writable = false;
|
|
this._reads = null;
|
|
this._buffers = null;
|
|
this.emit("close");
|
|
};
|
|
ChunkStream.prototype._processReadAllowingLess = function(read) {
|
|
this._reads.shift();
|
|
let smallerBuf = this._buffers[0];
|
|
if (smallerBuf.length > read.length) {
|
|
this._buffered -= read.length;
|
|
this._buffers[0] = smallerBuf.slice(read.length);
|
|
read.func.call(this, smallerBuf.slice(0, read.length));
|
|
} else {
|
|
this._buffered -= smallerBuf.length;
|
|
this._buffers.shift();
|
|
read.func.call(this, smallerBuf);
|
|
}
|
|
};
|
|
ChunkStream.prototype._processRead = function(read) {
|
|
this._reads.shift();
|
|
let pos = 0;
|
|
let count = 0;
|
|
let data = Buffer.alloc(read.length);
|
|
while (pos < read.length) {
|
|
let buf = this._buffers[count++];
|
|
let len = Math.min(buf.length, read.length - pos);
|
|
buf.copy(data, pos, 0, len);
|
|
pos += len;
|
|
if (len !== buf.length) {
|
|
this._buffers[--count] = buf.slice(len);
|
|
}
|
|
}
|
|
if (count > 0) {
|
|
this._buffers.splice(0, count);
|
|
}
|
|
this._buffered -= read.length;
|
|
read.func.call(this, data);
|
|
};
|
|
ChunkStream.prototype._process = function() {
|
|
try {
|
|
while (this._buffered > 0 && this._reads && this._reads.length > 0) {
|
|
let read = this._reads[0];
|
|
if (read.allowLess) {
|
|
this._processReadAllowingLess(read);
|
|
} else if (this._buffered >= read.length) {
|
|
this._processRead(read);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (this._buffers && !this.writable) {
|
|
this._end();
|
|
}
|
|
} catch (ex) {
|
|
this.emit("error", ex);
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/interlace.js
|
|
var require_interlace = __commonJS({
|
|
"node_modules/pngjs/lib/interlace.js"(exports2) {
|
|
"use strict";
|
|
var imagePasses = [
|
|
{
|
|
// pass 1 - 1px
|
|
x: [0],
|
|
y: [0]
|
|
},
|
|
{
|
|
// pass 2 - 1px
|
|
x: [4],
|
|
y: [0]
|
|
},
|
|
{
|
|
// pass 3 - 2px
|
|
x: [0, 4],
|
|
y: [4]
|
|
},
|
|
{
|
|
// pass 4 - 4px
|
|
x: [2, 6],
|
|
y: [0, 4]
|
|
},
|
|
{
|
|
// pass 5 - 8px
|
|
x: [0, 2, 4, 6],
|
|
y: [2, 6]
|
|
},
|
|
{
|
|
// pass 6 - 16px
|
|
x: [1, 3, 5, 7],
|
|
y: [0, 2, 4, 6]
|
|
},
|
|
{
|
|
// pass 7 - 32px
|
|
x: [0, 1, 2, 3, 4, 5, 6, 7],
|
|
y: [1, 3, 5, 7]
|
|
}
|
|
];
|
|
exports2.getImagePasses = function(width, height) {
|
|
let images = [];
|
|
let xLeftOver = width % 8;
|
|
let yLeftOver = height % 8;
|
|
let xRepeats = (width - xLeftOver) / 8;
|
|
let yRepeats = (height - yLeftOver) / 8;
|
|
for (let i = 0; i < imagePasses.length; i++) {
|
|
let pass = imagePasses[i];
|
|
let passWidth = xRepeats * pass.x.length;
|
|
let passHeight = yRepeats * pass.y.length;
|
|
for (let j = 0; j < pass.x.length; j++) {
|
|
if (pass.x[j] < xLeftOver) {
|
|
passWidth++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
for (let j = 0; j < pass.y.length; j++) {
|
|
if (pass.y[j] < yLeftOver) {
|
|
passHeight++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (passWidth > 0 && passHeight > 0) {
|
|
images.push({ width: passWidth, height: passHeight, index: i });
|
|
}
|
|
}
|
|
return images;
|
|
};
|
|
exports2.getInterlaceIterator = function(width) {
|
|
return function(x, y, pass) {
|
|
let outerXLeftOver = x % imagePasses[pass].x.length;
|
|
let outerX = (x - outerXLeftOver) / imagePasses[pass].x.length * 8 + imagePasses[pass].x[outerXLeftOver];
|
|
let outerYLeftOver = y % imagePasses[pass].y.length;
|
|
let outerY = (y - outerYLeftOver) / imagePasses[pass].y.length * 8 + imagePasses[pass].y[outerYLeftOver];
|
|
return outerX * 4 + outerY * width * 4;
|
|
};
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/paeth-predictor.js
|
|
var require_paeth_predictor = __commonJS({
|
|
"node_modules/pngjs/lib/paeth-predictor.js"(exports2, module2) {
|
|
"use strict";
|
|
module2.exports = function paethPredictor(left, above, upLeft) {
|
|
let paeth = left + above - upLeft;
|
|
let pLeft = Math.abs(paeth - left);
|
|
let pAbove = Math.abs(paeth - above);
|
|
let pUpLeft = Math.abs(paeth - upLeft);
|
|
if (pLeft <= pAbove && pLeft <= pUpLeft) {
|
|
return left;
|
|
}
|
|
if (pAbove <= pUpLeft) {
|
|
return above;
|
|
}
|
|
return upLeft;
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/filter-parse.js
|
|
var require_filter_parse = __commonJS({
|
|
"node_modules/pngjs/lib/filter-parse.js"(exports2, module2) {
|
|
"use strict";
|
|
var interlaceUtils = require_interlace();
|
|
var paethPredictor = require_paeth_predictor();
|
|
function getByteWidth(width, bpp, depth) {
|
|
let byteWidth = width * bpp;
|
|
if (depth !== 8) {
|
|
byteWidth = Math.ceil(byteWidth / (8 / depth));
|
|
}
|
|
return byteWidth;
|
|
}
|
|
var Filter = module2.exports = function(bitmapInfo, dependencies) {
|
|
let width = bitmapInfo.width;
|
|
let height = bitmapInfo.height;
|
|
let interlace = bitmapInfo.interlace;
|
|
let bpp = bitmapInfo.bpp;
|
|
let depth = bitmapInfo.depth;
|
|
this.read = dependencies.read;
|
|
this.write = dependencies.write;
|
|
this.complete = dependencies.complete;
|
|
this._imageIndex = 0;
|
|
this._images = [];
|
|
if (interlace) {
|
|
let passes = interlaceUtils.getImagePasses(width, height);
|
|
for (let i = 0; i < passes.length; i++) {
|
|
this._images.push({
|
|
byteWidth: getByteWidth(passes[i].width, bpp, depth),
|
|
height: passes[i].height,
|
|
lineIndex: 0
|
|
});
|
|
}
|
|
} else {
|
|
this._images.push({
|
|
byteWidth: getByteWidth(width, bpp, depth),
|
|
height,
|
|
lineIndex: 0
|
|
});
|
|
}
|
|
if (depth === 8) {
|
|
this._xComparison = bpp;
|
|
} else if (depth === 16) {
|
|
this._xComparison = bpp * 2;
|
|
} else {
|
|
this._xComparison = 1;
|
|
}
|
|
};
|
|
Filter.prototype.start = function() {
|
|
this.read(
|
|
this._images[this._imageIndex].byteWidth + 1,
|
|
this._reverseFilterLine.bind(this)
|
|
);
|
|
};
|
|
Filter.prototype._unFilterType1 = function(rawData, unfilteredLine, byteWidth) {
|
|
let xComparison = this._xComparison;
|
|
let xBiggerThan = xComparison - 1;
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let rawByte = rawData[1 + x];
|
|
let f1Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
|
|
unfilteredLine[x] = rawByte + f1Left;
|
|
}
|
|
};
|
|
Filter.prototype._unFilterType2 = function(rawData, unfilteredLine, byteWidth) {
|
|
let lastLine = this._lastLine;
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let rawByte = rawData[1 + x];
|
|
let f2Up = lastLine ? lastLine[x] : 0;
|
|
unfilteredLine[x] = rawByte + f2Up;
|
|
}
|
|
};
|
|
Filter.prototype._unFilterType3 = function(rawData, unfilteredLine, byteWidth) {
|
|
let xComparison = this._xComparison;
|
|
let xBiggerThan = xComparison - 1;
|
|
let lastLine = this._lastLine;
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let rawByte = rawData[1 + x];
|
|
let f3Up = lastLine ? lastLine[x] : 0;
|
|
let f3Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
|
|
let f3Add = Math.floor((f3Left + f3Up) / 2);
|
|
unfilteredLine[x] = rawByte + f3Add;
|
|
}
|
|
};
|
|
Filter.prototype._unFilterType4 = function(rawData, unfilteredLine, byteWidth) {
|
|
let xComparison = this._xComparison;
|
|
let xBiggerThan = xComparison - 1;
|
|
let lastLine = this._lastLine;
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let rawByte = rawData[1 + x];
|
|
let f4Up = lastLine ? lastLine[x] : 0;
|
|
let f4Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
|
|
let f4UpLeft = x > xBiggerThan && lastLine ? lastLine[x - xComparison] : 0;
|
|
let f4Add = paethPredictor(f4Left, f4Up, f4UpLeft);
|
|
unfilteredLine[x] = rawByte + f4Add;
|
|
}
|
|
};
|
|
Filter.prototype._reverseFilterLine = function(rawData) {
|
|
let filter = rawData[0];
|
|
let unfilteredLine;
|
|
let currentImage = this._images[this._imageIndex];
|
|
let byteWidth = currentImage.byteWidth;
|
|
if (filter === 0) {
|
|
unfilteredLine = rawData.slice(1, byteWidth + 1);
|
|
} else {
|
|
unfilteredLine = Buffer.alloc(byteWidth);
|
|
switch (filter) {
|
|
case 1:
|
|
this._unFilterType1(rawData, unfilteredLine, byteWidth);
|
|
break;
|
|
case 2:
|
|
this._unFilterType2(rawData, unfilteredLine, byteWidth);
|
|
break;
|
|
case 3:
|
|
this._unFilterType3(rawData, unfilteredLine, byteWidth);
|
|
break;
|
|
case 4:
|
|
this._unFilterType4(rawData, unfilteredLine, byteWidth);
|
|
break;
|
|
default:
|
|
throw new Error("Unrecognised filter type - " + filter);
|
|
}
|
|
}
|
|
this.write(unfilteredLine);
|
|
currentImage.lineIndex++;
|
|
if (currentImage.lineIndex >= currentImage.height) {
|
|
this._lastLine = null;
|
|
this._imageIndex++;
|
|
currentImage = this._images[this._imageIndex];
|
|
} else {
|
|
this._lastLine = unfilteredLine;
|
|
}
|
|
if (currentImage) {
|
|
this.read(currentImage.byteWidth + 1, this._reverseFilterLine.bind(this));
|
|
} else {
|
|
this._lastLine = null;
|
|
this.complete();
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/filter-parse-async.js
|
|
var require_filter_parse_async = __commonJS({
|
|
"node_modules/pngjs/lib/filter-parse-async.js"(exports2, module2) {
|
|
"use strict";
|
|
var util = require("util");
|
|
var ChunkStream = require_chunkstream();
|
|
var Filter = require_filter_parse();
|
|
var FilterAsync = module2.exports = function(bitmapInfo) {
|
|
ChunkStream.call(this);
|
|
let buffers = [];
|
|
let that = this;
|
|
this._filter = new Filter(bitmapInfo, {
|
|
read: this.read.bind(this),
|
|
write: function(buffer) {
|
|
buffers.push(buffer);
|
|
},
|
|
complete: function() {
|
|
that.emit("complete", Buffer.concat(buffers));
|
|
}
|
|
});
|
|
this._filter.start();
|
|
};
|
|
util.inherits(FilterAsync, ChunkStream);
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/constants.js
|
|
var require_constants = __commonJS({
|
|
"node_modules/pngjs/lib/constants.js"(exports2, module2) {
|
|
"use strict";
|
|
module2.exports = {
|
|
PNG_SIGNATURE: [137, 80, 78, 71, 13, 10, 26, 10],
|
|
TYPE_IHDR: 1229472850,
|
|
TYPE_IEND: 1229278788,
|
|
TYPE_IDAT: 1229209940,
|
|
TYPE_PLTE: 1347179589,
|
|
TYPE_tRNS: 1951551059,
|
|
// eslint-disable-line camelcase
|
|
TYPE_gAMA: 1732332865,
|
|
// eslint-disable-line camelcase
|
|
// color-type bits
|
|
COLORTYPE_GRAYSCALE: 0,
|
|
COLORTYPE_PALETTE: 1,
|
|
COLORTYPE_COLOR: 2,
|
|
COLORTYPE_ALPHA: 4,
|
|
// e.g. grayscale and alpha
|
|
// color-type combinations
|
|
COLORTYPE_PALETTE_COLOR: 3,
|
|
COLORTYPE_COLOR_ALPHA: 6,
|
|
COLORTYPE_TO_BPP_MAP: {
|
|
0: 1,
|
|
2: 3,
|
|
3: 1,
|
|
4: 2,
|
|
6: 4
|
|
},
|
|
GAMMA_DIVISION: 1e5
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/crc.js
|
|
var require_crc = __commonJS({
|
|
"node_modules/pngjs/lib/crc.js"(exports2, module2) {
|
|
"use strict";
|
|
var crcTable = [];
|
|
(function() {
|
|
for (let i = 0; i < 256; i++) {
|
|
let currentCrc = i;
|
|
for (let j = 0; j < 8; j++) {
|
|
if (currentCrc & 1) {
|
|
currentCrc = 3988292384 ^ currentCrc >>> 1;
|
|
} else {
|
|
currentCrc = currentCrc >>> 1;
|
|
}
|
|
}
|
|
crcTable[i] = currentCrc;
|
|
}
|
|
})();
|
|
var CrcCalculator = module2.exports = function() {
|
|
this._crc = -1;
|
|
};
|
|
CrcCalculator.prototype.write = function(data) {
|
|
for (let i = 0; i < data.length; i++) {
|
|
this._crc = crcTable[(this._crc ^ data[i]) & 255] ^ this._crc >>> 8;
|
|
}
|
|
return true;
|
|
};
|
|
CrcCalculator.prototype.crc32 = function() {
|
|
return this._crc ^ -1;
|
|
};
|
|
CrcCalculator.crc32 = function(buf) {
|
|
let crc = -1;
|
|
for (let i = 0; i < buf.length; i++) {
|
|
crc = crcTable[(crc ^ buf[i]) & 255] ^ crc >>> 8;
|
|
}
|
|
return crc ^ -1;
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/parser.js
|
|
var require_parser = __commonJS({
|
|
"node_modules/pngjs/lib/parser.js"(exports2, module2) {
|
|
"use strict";
|
|
var constants = require_constants();
|
|
var CrcCalculator = require_crc();
|
|
var Parser = module2.exports = function(options, dependencies) {
|
|
this._options = options;
|
|
options.checkCRC = options.checkCRC !== false;
|
|
this._hasIHDR = false;
|
|
this._hasIEND = false;
|
|
this._emittedHeadersFinished = false;
|
|
this._palette = [];
|
|
this._colorType = 0;
|
|
this._chunks = {};
|
|
this._chunks[constants.TYPE_IHDR] = this._handleIHDR.bind(this);
|
|
this._chunks[constants.TYPE_IEND] = this._handleIEND.bind(this);
|
|
this._chunks[constants.TYPE_IDAT] = this._handleIDAT.bind(this);
|
|
this._chunks[constants.TYPE_PLTE] = this._handlePLTE.bind(this);
|
|
this._chunks[constants.TYPE_tRNS] = this._handleTRNS.bind(this);
|
|
this._chunks[constants.TYPE_gAMA] = this._handleGAMA.bind(this);
|
|
this.read = dependencies.read;
|
|
this.error = dependencies.error;
|
|
this.metadata = dependencies.metadata;
|
|
this.gamma = dependencies.gamma;
|
|
this.transColor = dependencies.transColor;
|
|
this.palette = dependencies.palette;
|
|
this.parsed = dependencies.parsed;
|
|
this.inflateData = dependencies.inflateData;
|
|
this.finished = dependencies.finished;
|
|
this.simpleTransparency = dependencies.simpleTransparency;
|
|
this.headersFinished = dependencies.headersFinished || function() {
|
|
};
|
|
};
|
|
Parser.prototype.start = function() {
|
|
this.read(constants.PNG_SIGNATURE.length, this._parseSignature.bind(this));
|
|
};
|
|
Parser.prototype._parseSignature = function(data) {
|
|
let signature = constants.PNG_SIGNATURE;
|
|
for (let i = 0; i < signature.length; i++) {
|
|
if (data[i] !== signature[i]) {
|
|
this.error(new Error("Invalid file signature"));
|
|
return;
|
|
}
|
|
}
|
|
this.read(8, this._parseChunkBegin.bind(this));
|
|
};
|
|
Parser.prototype._parseChunkBegin = function(data) {
|
|
let length = data.readUInt32BE(0);
|
|
let type = data.readUInt32BE(4);
|
|
let name = "";
|
|
for (let i = 4; i < 8; i++) {
|
|
name += String.fromCharCode(data[i]);
|
|
}
|
|
let ancillary = Boolean(data[4] & 32);
|
|
if (!this._hasIHDR && type !== constants.TYPE_IHDR) {
|
|
this.error(new Error("Expected IHDR on beggining"));
|
|
return;
|
|
}
|
|
this._crc = new CrcCalculator();
|
|
this._crc.write(Buffer.from(name));
|
|
if (this._chunks[type]) {
|
|
return this._chunks[type](length);
|
|
}
|
|
if (!ancillary) {
|
|
this.error(new Error("Unsupported critical chunk type " + name));
|
|
return;
|
|
}
|
|
this.read(length + 4, this._skipChunk.bind(this));
|
|
};
|
|
Parser.prototype._skipChunk = function() {
|
|
this.read(8, this._parseChunkBegin.bind(this));
|
|
};
|
|
Parser.prototype._handleChunkEnd = function() {
|
|
this.read(4, this._parseChunkEnd.bind(this));
|
|
};
|
|
Parser.prototype._parseChunkEnd = function(data) {
|
|
let fileCrc = data.readInt32BE(0);
|
|
let calcCrc = this._crc.crc32();
|
|
if (this._options.checkCRC && calcCrc !== fileCrc) {
|
|
this.error(new Error("Crc error - " + fileCrc + " - " + calcCrc));
|
|
return;
|
|
}
|
|
if (!this._hasIEND) {
|
|
this.read(8, this._parseChunkBegin.bind(this));
|
|
}
|
|
};
|
|
Parser.prototype._handleIHDR = function(length) {
|
|
this.read(length, this._parseIHDR.bind(this));
|
|
};
|
|
Parser.prototype._parseIHDR = function(data) {
|
|
this._crc.write(data);
|
|
let width = data.readUInt32BE(0);
|
|
let height = data.readUInt32BE(4);
|
|
let depth = data[8];
|
|
let colorType = data[9];
|
|
let compr = data[10];
|
|
let filter = data[11];
|
|
let interlace = data[12];
|
|
if (depth !== 8 && depth !== 4 && depth !== 2 && depth !== 1 && depth !== 16) {
|
|
this.error(new Error("Unsupported bit depth " + depth));
|
|
return;
|
|
}
|
|
if (!(colorType in constants.COLORTYPE_TO_BPP_MAP)) {
|
|
this.error(new Error("Unsupported color type"));
|
|
return;
|
|
}
|
|
if (compr !== 0) {
|
|
this.error(new Error("Unsupported compression method"));
|
|
return;
|
|
}
|
|
if (filter !== 0) {
|
|
this.error(new Error("Unsupported filter method"));
|
|
return;
|
|
}
|
|
if (interlace !== 0 && interlace !== 1) {
|
|
this.error(new Error("Unsupported interlace method"));
|
|
return;
|
|
}
|
|
this._colorType = colorType;
|
|
let bpp = constants.COLORTYPE_TO_BPP_MAP[this._colorType];
|
|
this._hasIHDR = true;
|
|
this.metadata({
|
|
width,
|
|
height,
|
|
depth,
|
|
interlace: Boolean(interlace),
|
|
palette: Boolean(colorType & constants.COLORTYPE_PALETTE),
|
|
color: Boolean(colorType & constants.COLORTYPE_COLOR),
|
|
alpha: Boolean(colorType & constants.COLORTYPE_ALPHA),
|
|
bpp,
|
|
colorType
|
|
});
|
|
this._handleChunkEnd();
|
|
};
|
|
Parser.prototype._handlePLTE = function(length) {
|
|
this.read(length, this._parsePLTE.bind(this));
|
|
};
|
|
Parser.prototype._parsePLTE = function(data) {
|
|
this._crc.write(data);
|
|
let entries = Math.floor(data.length / 3);
|
|
for (let i = 0; i < entries; i++) {
|
|
this._palette.push([data[i * 3], data[i * 3 + 1], data[i * 3 + 2], 255]);
|
|
}
|
|
this.palette(this._palette);
|
|
this._handleChunkEnd();
|
|
};
|
|
Parser.prototype._handleTRNS = function(length) {
|
|
this.simpleTransparency();
|
|
this.read(length, this._parseTRNS.bind(this));
|
|
};
|
|
Parser.prototype._parseTRNS = function(data) {
|
|
this._crc.write(data);
|
|
if (this._colorType === constants.COLORTYPE_PALETTE_COLOR) {
|
|
if (this._palette.length === 0) {
|
|
this.error(new Error("Transparency chunk must be after palette"));
|
|
return;
|
|
}
|
|
if (data.length > this._palette.length) {
|
|
this.error(new Error("More transparent colors than palette size"));
|
|
return;
|
|
}
|
|
for (let i = 0; i < data.length; i++) {
|
|
this._palette[i][3] = data[i];
|
|
}
|
|
this.palette(this._palette);
|
|
}
|
|
if (this._colorType === constants.COLORTYPE_GRAYSCALE) {
|
|
this.transColor([data.readUInt16BE(0)]);
|
|
}
|
|
if (this._colorType === constants.COLORTYPE_COLOR) {
|
|
this.transColor([
|
|
data.readUInt16BE(0),
|
|
data.readUInt16BE(2),
|
|
data.readUInt16BE(4)
|
|
]);
|
|
}
|
|
this._handleChunkEnd();
|
|
};
|
|
Parser.prototype._handleGAMA = function(length) {
|
|
this.read(length, this._parseGAMA.bind(this));
|
|
};
|
|
Parser.prototype._parseGAMA = function(data) {
|
|
this._crc.write(data);
|
|
this.gamma(data.readUInt32BE(0) / constants.GAMMA_DIVISION);
|
|
this._handleChunkEnd();
|
|
};
|
|
Parser.prototype._handleIDAT = function(length) {
|
|
if (!this._emittedHeadersFinished) {
|
|
this._emittedHeadersFinished = true;
|
|
this.headersFinished();
|
|
}
|
|
this.read(-length, this._parseIDAT.bind(this, length));
|
|
};
|
|
Parser.prototype._parseIDAT = function(length, data) {
|
|
this._crc.write(data);
|
|
if (this._colorType === constants.COLORTYPE_PALETTE_COLOR && this._palette.length === 0) {
|
|
throw new Error("Expected palette not found");
|
|
}
|
|
this.inflateData(data);
|
|
let leftOverLength = length - data.length;
|
|
if (leftOverLength > 0) {
|
|
this._handleIDAT(leftOverLength);
|
|
} else {
|
|
this._handleChunkEnd();
|
|
}
|
|
};
|
|
Parser.prototype._handleIEND = function(length) {
|
|
this.read(length, this._parseIEND.bind(this));
|
|
};
|
|
Parser.prototype._parseIEND = function(data) {
|
|
this._crc.write(data);
|
|
this._hasIEND = true;
|
|
this._handleChunkEnd();
|
|
if (this.finished) {
|
|
this.finished();
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/bitmapper.js
|
|
var require_bitmapper = __commonJS({
|
|
"node_modules/pngjs/lib/bitmapper.js"(exports2) {
|
|
"use strict";
|
|
var interlaceUtils = require_interlace();
|
|
var pixelBppMapper = [
|
|
// 0 - dummy entry
|
|
function() {
|
|
},
|
|
// 1 - L
|
|
// 0: 0, 1: 0, 2: 0, 3: 0xff
|
|
function(pxData, data, pxPos, rawPos) {
|
|
if (rawPos === data.length) {
|
|
throw new Error("Ran out of data");
|
|
}
|
|
let pixel = data[rawPos];
|
|
pxData[pxPos] = pixel;
|
|
pxData[pxPos + 1] = pixel;
|
|
pxData[pxPos + 2] = pixel;
|
|
pxData[pxPos + 3] = 255;
|
|
},
|
|
// 2 - LA
|
|
// 0: 0, 1: 0, 2: 0, 3: 1
|
|
function(pxData, data, pxPos, rawPos) {
|
|
if (rawPos + 1 >= data.length) {
|
|
throw new Error("Ran out of data");
|
|
}
|
|
let pixel = data[rawPos];
|
|
pxData[pxPos] = pixel;
|
|
pxData[pxPos + 1] = pixel;
|
|
pxData[pxPos + 2] = pixel;
|
|
pxData[pxPos + 3] = data[rawPos + 1];
|
|
},
|
|
// 3 - RGB
|
|
// 0: 0, 1: 1, 2: 2, 3: 0xff
|
|
function(pxData, data, pxPos, rawPos) {
|
|
if (rawPos + 2 >= data.length) {
|
|
throw new Error("Ran out of data");
|
|
}
|
|
pxData[pxPos] = data[rawPos];
|
|
pxData[pxPos + 1] = data[rawPos + 1];
|
|
pxData[pxPos + 2] = data[rawPos + 2];
|
|
pxData[pxPos + 3] = 255;
|
|
},
|
|
// 4 - RGBA
|
|
// 0: 0, 1: 1, 2: 2, 3: 3
|
|
function(pxData, data, pxPos, rawPos) {
|
|
if (rawPos + 3 >= data.length) {
|
|
throw new Error("Ran out of data");
|
|
}
|
|
pxData[pxPos] = data[rawPos];
|
|
pxData[pxPos + 1] = data[rawPos + 1];
|
|
pxData[pxPos + 2] = data[rawPos + 2];
|
|
pxData[pxPos + 3] = data[rawPos + 3];
|
|
}
|
|
];
|
|
var pixelBppCustomMapper = [
|
|
// 0 - dummy entry
|
|
function() {
|
|
},
|
|
// 1 - L
|
|
// 0: 0, 1: 0, 2: 0, 3: 0xff
|
|
function(pxData, pixelData, pxPos, maxBit) {
|
|
let pixel = pixelData[0];
|
|
pxData[pxPos] = pixel;
|
|
pxData[pxPos + 1] = pixel;
|
|
pxData[pxPos + 2] = pixel;
|
|
pxData[pxPos + 3] = maxBit;
|
|
},
|
|
// 2 - LA
|
|
// 0: 0, 1: 0, 2: 0, 3: 1
|
|
function(pxData, pixelData, pxPos) {
|
|
let pixel = pixelData[0];
|
|
pxData[pxPos] = pixel;
|
|
pxData[pxPos + 1] = pixel;
|
|
pxData[pxPos + 2] = pixel;
|
|
pxData[pxPos + 3] = pixelData[1];
|
|
},
|
|
// 3 - RGB
|
|
// 0: 0, 1: 1, 2: 2, 3: 0xff
|
|
function(pxData, pixelData, pxPos, maxBit) {
|
|
pxData[pxPos] = pixelData[0];
|
|
pxData[pxPos + 1] = pixelData[1];
|
|
pxData[pxPos + 2] = pixelData[2];
|
|
pxData[pxPos + 3] = maxBit;
|
|
},
|
|
// 4 - RGBA
|
|
// 0: 0, 1: 1, 2: 2, 3: 3
|
|
function(pxData, pixelData, pxPos) {
|
|
pxData[pxPos] = pixelData[0];
|
|
pxData[pxPos + 1] = pixelData[1];
|
|
pxData[pxPos + 2] = pixelData[2];
|
|
pxData[pxPos + 3] = pixelData[3];
|
|
}
|
|
];
|
|
function bitRetriever(data, depth) {
|
|
let leftOver = [];
|
|
let i = 0;
|
|
function split() {
|
|
if (i === data.length) {
|
|
throw new Error("Ran out of data");
|
|
}
|
|
let byte = data[i];
|
|
i++;
|
|
let byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1;
|
|
switch (depth) {
|
|
default:
|
|
throw new Error("unrecognised depth");
|
|
case 16:
|
|
byte2 = data[i];
|
|
i++;
|
|
leftOver.push((byte << 8) + byte2);
|
|
break;
|
|
case 4:
|
|
byte2 = byte & 15;
|
|
byte1 = byte >> 4;
|
|
leftOver.push(byte1, byte2);
|
|
break;
|
|
case 2:
|
|
byte4 = byte & 3;
|
|
byte3 = byte >> 2 & 3;
|
|
byte2 = byte >> 4 & 3;
|
|
byte1 = byte >> 6 & 3;
|
|
leftOver.push(byte1, byte2, byte3, byte4);
|
|
break;
|
|
case 1:
|
|
byte8 = byte & 1;
|
|
byte7 = byte >> 1 & 1;
|
|
byte6 = byte >> 2 & 1;
|
|
byte5 = byte >> 3 & 1;
|
|
byte4 = byte >> 4 & 1;
|
|
byte3 = byte >> 5 & 1;
|
|
byte2 = byte >> 6 & 1;
|
|
byte1 = byte >> 7 & 1;
|
|
leftOver.push(byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8);
|
|
break;
|
|
}
|
|
}
|
|
return {
|
|
get: function(count) {
|
|
while (leftOver.length < count) {
|
|
split();
|
|
}
|
|
let returner = leftOver.slice(0, count);
|
|
leftOver = leftOver.slice(count);
|
|
return returner;
|
|
},
|
|
resetAfterLine: function() {
|
|
leftOver.length = 0;
|
|
},
|
|
end: function() {
|
|
if (i !== data.length) {
|
|
throw new Error("extra data found");
|
|
}
|
|
}
|
|
};
|
|
}
|
|
function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) {
|
|
let imageWidth = image.width;
|
|
let imageHeight = image.height;
|
|
let imagePass = image.index;
|
|
for (let y = 0; y < imageHeight; y++) {
|
|
for (let x = 0; x < imageWidth; x++) {
|
|
let pxPos = getPxPos(x, y, imagePass);
|
|
pixelBppMapper[bpp](pxData, data, pxPos, rawPos);
|
|
rawPos += bpp;
|
|
}
|
|
}
|
|
return rawPos;
|
|
}
|
|
function mapImageCustomBit(image, pxData, getPxPos, bpp, bits, maxBit) {
|
|
let imageWidth = image.width;
|
|
let imageHeight = image.height;
|
|
let imagePass = image.index;
|
|
for (let y = 0; y < imageHeight; y++) {
|
|
for (let x = 0; x < imageWidth; x++) {
|
|
let pixelData = bits.get(bpp);
|
|
let pxPos = getPxPos(x, y, imagePass);
|
|
pixelBppCustomMapper[bpp](pxData, pixelData, pxPos, maxBit);
|
|
}
|
|
bits.resetAfterLine();
|
|
}
|
|
}
|
|
exports2.dataToBitMap = function(data, bitmapInfo) {
|
|
let width = bitmapInfo.width;
|
|
let height = bitmapInfo.height;
|
|
let depth = bitmapInfo.depth;
|
|
let bpp = bitmapInfo.bpp;
|
|
let interlace = bitmapInfo.interlace;
|
|
let bits;
|
|
if (depth !== 8) {
|
|
bits = bitRetriever(data, depth);
|
|
}
|
|
let pxData;
|
|
if (depth <= 8) {
|
|
pxData = Buffer.alloc(width * height * 4);
|
|
} else {
|
|
pxData = new Uint16Array(width * height * 4);
|
|
}
|
|
let maxBit = Math.pow(2, depth) - 1;
|
|
let rawPos = 0;
|
|
let images;
|
|
let getPxPos;
|
|
if (interlace) {
|
|
images = interlaceUtils.getImagePasses(width, height);
|
|
getPxPos = interlaceUtils.getInterlaceIterator(width, height);
|
|
} else {
|
|
let nonInterlacedPxPos = 0;
|
|
getPxPos = function() {
|
|
let returner = nonInterlacedPxPos;
|
|
nonInterlacedPxPos += 4;
|
|
return returner;
|
|
};
|
|
images = [{ width, height }];
|
|
}
|
|
for (let imageIndex = 0; imageIndex < images.length; imageIndex++) {
|
|
if (depth === 8) {
|
|
rawPos = mapImage8Bit(
|
|
images[imageIndex],
|
|
pxData,
|
|
getPxPos,
|
|
bpp,
|
|
data,
|
|
rawPos
|
|
);
|
|
} else {
|
|
mapImageCustomBit(
|
|
images[imageIndex],
|
|
pxData,
|
|
getPxPos,
|
|
bpp,
|
|
bits,
|
|
maxBit
|
|
);
|
|
}
|
|
}
|
|
if (depth === 8) {
|
|
if (rawPos !== data.length) {
|
|
throw new Error("extra data found");
|
|
}
|
|
} else {
|
|
bits.end();
|
|
}
|
|
return pxData;
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/format-normaliser.js
|
|
var require_format_normaliser = __commonJS({
|
|
"node_modules/pngjs/lib/format-normaliser.js"(exports2, module2) {
|
|
"use strict";
|
|
function dePalette(indata, outdata, width, height, palette) {
|
|
let pxPos = 0;
|
|
for (let y = 0; y < height; y++) {
|
|
for (let x = 0; x < width; x++) {
|
|
let color = palette[indata[pxPos]];
|
|
if (!color) {
|
|
throw new Error("index " + indata[pxPos] + " not in palette");
|
|
}
|
|
for (let i = 0; i < 4; i++) {
|
|
outdata[pxPos + i] = color[i];
|
|
}
|
|
pxPos += 4;
|
|
}
|
|
}
|
|
}
|
|
function replaceTransparentColor(indata, outdata, width, height, transColor) {
|
|
let pxPos = 0;
|
|
for (let y = 0; y < height; y++) {
|
|
for (let x = 0; x < width; x++) {
|
|
let makeTrans = false;
|
|
if (transColor.length === 1) {
|
|
if (transColor[0] === indata[pxPos]) {
|
|
makeTrans = true;
|
|
}
|
|
} else if (transColor[0] === indata[pxPos] && transColor[1] === indata[pxPos + 1] && transColor[2] === indata[pxPos + 2]) {
|
|
makeTrans = true;
|
|
}
|
|
if (makeTrans) {
|
|
for (let i = 0; i < 4; i++) {
|
|
outdata[pxPos + i] = 0;
|
|
}
|
|
}
|
|
pxPos += 4;
|
|
}
|
|
}
|
|
}
|
|
function scaleDepth(indata, outdata, width, height, depth) {
|
|
let maxOutSample = 255;
|
|
let maxInSample = Math.pow(2, depth) - 1;
|
|
let pxPos = 0;
|
|
for (let y = 0; y < height; y++) {
|
|
for (let x = 0; x < width; x++) {
|
|
for (let i = 0; i < 4; i++) {
|
|
outdata[pxPos + i] = Math.floor(
|
|
indata[pxPos + i] * maxOutSample / maxInSample + 0.5
|
|
);
|
|
}
|
|
pxPos += 4;
|
|
}
|
|
}
|
|
}
|
|
module2.exports = function(indata, imageData, skipRescale = false) {
|
|
let depth = imageData.depth;
|
|
let width = imageData.width;
|
|
let height = imageData.height;
|
|
let colorType = imageData.colorType;
|
|
let transColor = imageData.transColor;
|
|
let palette = imageData.palette;
|
|
let outdata = indata;
|
|
if (colorType === 3) {
|
|
dePalette(indata, outdata, width, height, palette);
|
|
} else {
|
|
if (transColor) {
|
|
replaceTransparentColor(indata, outdata, width, height, transColor);
|
|
}
|
|
if (depth !== 8 && !skipRescale) {
|
|
if (depth === 16) {
|
|
outdata = Buffer.alloc(width * height * 4);
|
|
}
|
|
scaleDepth(indata, outdata, width, height, depth);
|
|
}
|
|
}
|
|
return outdata;
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/parser-async.js
|
|
var require_parser_async = __commonJS({
|
|
"node_modules/pngjs/lib/parser-async.js"(exports2, module2) {
|
|
"use strict";
|
|
var util = require("util");
|
|
var zlib = require("zlib");
|
|
var ChunkStream = require_chunkstream();
|
|
var FilterAsync = require_filter_parse_async();
|
|
var Parser = require_parser();
|
|
var bitmapper = require_bitmapper();
|
|
var formatNormaliser = require_format_normaliser();
|
|
var ParserAsync = module2.exports = function(options) {
|
|
ChunkStream.call(this);
|
|
this._parser = new Parser(options, {
|
|
read: this.read.bind(this),
|
|
error: this._handleError.bind(this),
|
|
metadata: this._handleMetaData.bind(this),
|
|
gamma: this.emit.bind(this, "gamma"),
|
|
palette: this._handlePalette.bind(this),
|
|
transColor: this._handleTransColor.bind(this),
|
|
finished: this._finished.bind(this),
|
|
inflateData: this._inflateData.bind(this),
|
|
simpleTransparency: this._simpleTransparency.bind(this),
|
|
headersFinished: this._headersFinished.bind(this)
|
|
});
|
|
this._options = options;
|
|
this.writable = true;
|
|
this._parser.start();
|
|
};
|
|
util.inherits(ParserAsync, ChunkStream);
|
|
ParserAsync.prototype._handleError = function(err) {
|
|
this.emit("error", err);
|
|
this.writable = false;
|
|
this.destroy();
|
|
if (this._inflate && this._inflate.destroy) {
|
|
this._inflate.destroy();
|
|
}
|
|
if (this._filter) {
|
|
this._filter.destroy();
|
|
this._filter.on("error", function() {
|
|
});
|
|
}
|
|
this.errord = true;
|
|
};
|
|
ParserAsync.prototype._inflateData = function(data) {
|
|
if (!this._inflate) {
|
|
if (this._bitmapInfo.interlace) {
|
|
this._inflate = zlib.createInflate();
|
|
this._inflate.on("error", this.emit.bind(this, "error"));
|
|
this._filter.on("complete", this._complete.bind(this));
|
|
this._inflate.pipe(this._filter);
|
|
} else {
|
|
let rowSize = (this._bitmapInfo.width * this._bitmapInfo.bpp * this._bitmapInfo.depth + 7 >> 3) + 1;
|
|
let imageSize = rowSize * this._bitmapInfo.height;
|
|
let chunkSize = Math.max(imageSize, zlib.Z_MIN_CHUNK);
|
|
this._inflate = zlib.createInflate({ chunkSize });
|
|
let leftToInflate = imageSize;
|
|
let emitError = this.emit.bind(this, "error");
|
|
this._inflate.on("error", function(err) {
|
|
if (!leftToInflate) {
|
|
return;
|
|
}
|
|
emitError(err);
|
|
});
|
|
this._filter.on("complete", this._complete.bind(this));
|
|
let filterWrite = this._filter.write.bind(this._filter);
|
|
this._inflate.on("data", function(chunk) {
|
|
if (!leftToInflate) {
|
|
return;
|
|
}
|
|
if (chunk.length > leftToInflate) {
|
|
chunk = chunk.slice(0, leftToInflate);
|
|
}
|
|
leftToInflate -= chunk.length;
|
|
filterWrite(chunk);
|
|
});
|
|
this._inflate.on("end", this._filter.end.bind(this._filter));
|
|
}
|
|
}
|
|
this._inflate.write(data);
|
|
};
|
|
ParserAsync.prototype._handleMetaData = function(metaData) {
|
|
this._metaData = metaData;
|
|
this._bitmapInfo = Object.create(metaData);
|
|
this._filter = new FilterAsync(this._bitmapInfo);
|
|
};
|
|
ParserAsync.prototype._handleTransColor = function(transColor) {
|
|
this._bitmapInfo.transColor = transColor;
|
|
};
|
|
ParserAsync.prototype._handlePalette = function(palette) {
|
|
this._bitmapInfo.palette = palette;
|
|
};
|
|
ParserAsync.prototype._simpleTransparency = function() {
|
|
this._metaData.alpha = true;
|
|
};
|
|
ParserAsync.prototype._headersFinished = function() {
|
|
this.emit("metadata", this._metaData);
|
|
};
|
|
ParserAsync.prototype._finished = function() {
|
|
if (this.errord) {
|
|
return;
|
|
}
|
|
if (!this._inflate) {
|
|
this.emit("error", "No Inflate block");
|
|
} else {
|
|
this._inflate.end();
|
|
}
|
|
};
|
|
ParserAsync.prototype._complete = function(filteredData) {
|
|
if (this.errord) {
|
|
return;
|
|
}
|
|
let normalisedBitmapData;
|
|
try {
|
|
let bitmapData = bitmapper.dataToBitMap(filteredData, this._bitmapInfo);
|
|
normalisedBitmapData = formatNormaliser(
|
|
bitmapData,
|
|
this._bitmapInfo,
|
|
this._options.skipRescale
|
|
);
|
|
bitmapData = null;
|
|
} catch (ex) {
|
|
this._handleError(ex);
|
|
return;
|
|
}
|
|
this.emit("parsed", normalisedBitmapData);
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/bitpacker.js
|
|
var require_bitpacker = __commonJS({
|
|
"node_modules/pngjs/lib/bitpacker.js"(exports2, module2) {
|
|
"use strict";
|
|
var constants = require_constants();
|
|
module2.exports = function(dataIn, width, height, options) {
|
|
let outHasAlpha = [constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf(
|
|
options.colorType
|
|
) !== -1;
|
|
if (options.colorType === options.inputColorType) {
|
|
let bigEndian = function() {
|
|
let buffer = new ArrayBuffer(2);
|
|
new DataView(buffer).setInt16(
|
|
0,
|
|
256,
|
|
true
|
|
/* littleEndian */
|
|
);
|
|
return new Int16Array(buffer)[0] !== 256;
|
|
}();
|
|
if (options.bitDepth === 8 || options.bitDepth === 16 && bigEndian) {
|
|
return dataIn;
|
|
}
|
|
}
|
|
let data = options.bitDepth !== 16 ? dataIn : new Uint16Array(dataIn.buffer);
|
|
let maxValue = 255;
|
|
let inBpp = constants.COLORTYPE_TO_BPP_MAP[options.inputColorType];
|
|
if (inBpp === 4 && !options.inputHasAlpha) {
|
|
inBpp = 3;
|
|
}
|
|
let outBpp = constants.COLORTYPE_TO_BPP_MAP[options.colorType];
|
|
if (options.bitDepth === 16) {
|
|
maxValue = 65535;
|
|
outBpp *= 2;
|
|
}
|
|
let outData = Buffer.alloc(width * height * outBpp);
|
|
let inIndex = 0;
|
|
let outIndex = 0;
|
|
let bgColor = options.bgColor || {};
|
|
if (bgColor.red === void 0) {
|
|
bgColor.red = maxValue;
|
|
}
|
|
if (bgColor.green === void 0) {
|
|
bgColor.green = maxValue;
|
|
}
|
|
if (bgColor.blue === void 0) {
|
|
bgColor.blue = maxValue;
|
|
}
|
|
function getRGBA() {
|
|
let red;
|
|
let green;
|
|
let blue;
|
|
let alpha = maxValue;
|
|
switch (options.inputColorType) {
|
|
case constants.COLORTYPE_COLOR_ALPHA:
|
|
alpha = data[inIndex + 3];
|
|
red = data[inIndex];
|
|
green = data[inIndex + 1];
|
|
blue = data[inIndex + 2];
|
|
break;
|
|
case constants.COLORTYPE_COLOR:
|
|
red = data[inIndex];
|
|
green = data[inIndex + 1];
|
|
blue = data[inIndex + 2];
|
|
break;
|
|
case constants.COLORTYPE_ALPHA:
|
|
alpha = data[inIndex + 1];
|
|
red = data[inIndex];
|
|
green = red;
|
|
blue = red;
|
|
break;
|
|
case constants.COLORTYPE_GRAYSCALE:
|
|
red = data[inIndex];
|
|
green = red;
|
|
blue = red;
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
"input color type:" + options.inputColorType + " is not supported at present"
|
|
);
|
|
}
|
|
if (options.inputHasAlpha) {
|
|
if (!outHasAlpha) {
|
|
alpha /= maxValue;
|
|
red = Math.min(
|
|
Math.max(Math.round((1 - alpha) * bgColor.red + alpha * red), 0),
|
|
maxValue
|
|
);
|
|
green = Math.min(
|
|
Math.max(Math.round((1 - alpha) * bgColor.green + alpha * green), 0),
|
|
maxValue
|
|
);
|
|
blue = Math.min(
|
|
Math.max(Math.round((1 - alpha) * bgColor.blue + alpha * blue), 0),
|
|
maxValue
|
|
);
|
|
}
|
|
}
|
|
return { red, green, blue, alpha };
|
|
}
|
|
for (let y = 0; y < height; y++) {
|
|
for (let x = 0; x < width; x++) {
|
|
let rgba = getRGBA(data, inIndex);
|
|
switch (options.colorType) {
|
|
case constants.COLORTYPE_COLOR_ALPHA:
|
|
case constants.COLORTYPE_COLOR:
|
|
if (options.bitDepth === 8) {
|
|
outData[outIndex] = rgba.red;
|
|
outData[outIndex + 1] = rgba.green;
|
|
outData[outIndex + 2] = rgba.blue;
|
|
if (outHasAlpha) {
|
|
outData[outIndex + 3] = rgba.alpha;
|
|
}
|
|
} else {
|
|
outData.writeUInt16BE(rgba.red, outIndex);
|
|
outData.writeUInt16BE(rgba.green, outIndex + 2);
|
|
outData.writeUInt16BE(rgba.blue, outIndex + 4);
|
|
if (outHasAlpha) {
|
|
outData.writeUInt16BE(rgba.alpha, outIndex + 6);
|
|
}
|
|
}
|
|
break;
|
|
case constants.COLORTYPE_ALPHA:
|
|
case constants.COLORTYPE_GRAYSCALE: {
|
|
let grayscale = (rgba.red + rgba.green + rgba.blue) / 3;
|
|
if (options.bitDepth === 8) {
|
|
outData[outIndex] = grayscale;
|
|
if (outHasAlpha) {
|
|
outData[outIndex + 1] = rgba.alpha;
|
|
}
|
|
} else {
|
|
outData.writeUInt16BE(grayscale, outIndex);
|
|
if (outHasAlpha) {
|
|
outData.writeUInt16BE(rgba.alpha, outIndex + 2);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
throw new Error("unrecognised color Type " + options.colorType);
|
|
}
|
|
inIndex += inBpp;
|
|
outIndex += outBpp;
|
|
}
|
|
}
|
|
return outData;
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/filter-pack.js
|
|
var require_filter_pack = __commonJS({
|
|
"node_modules/pngjs/lib/filter-pack.js"(exports2, module2) {
|
|
"use strict";
|
|
var paethPredictor = require_paeth_predictor();
|
|
function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
rawData[rawPos + x] = pxData[pxPos + x];
|
|
}
|
|
}
|
|
function filterSumNone(pxData, pxPos, byteWidth) {
|
|
let sum = 0;
|
|
let length = pxPos + byteWidth;
|
|
for (let i = pxPos; i < length; i++) {
|
|
sum += Math.abs(pxData[i]);
|
|
}
|
|
return sum;
|
|
}
|
|
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
|
|
let val = pxData[pxPos + x] - left;
|
|
rawData[rawPos + x] = val;
|
|
}
|
|
}
|
|
function filterSumSub(pxData, pxPos, byteWidth, bpp) {
|
|
let sum = 0;
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
|
|
let val = pxData[pxPos + x] - left;
|
|
sum += Math.abs(val);
|
|
}
|
|
return sum;
|
|
}
|
|
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) {
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
|
let val = pxData[pxPos + x] - up;
|
|
rawData[rawPos + x] = val;
|
|
}
|
|
}
|
|
function filterSumUp(pxData, pxPos, byteWidth) {
|
|
let sum = 0;
|
|
let length = pxPos + byteWidth;
|
|
for (let x = pxPos; x < length; x++) {
|
|
let up = pxPos > 0 ? pxData[x - byteWidth] : 0;
|
|
let val = pxData[x] - up;
|
|
sum += Math.abs(val);
|
|
}
|
|
return sum;
|
|
}
|
|
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
|
|
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
|
let val = pxData[pxPos + x] - (left + up >> 1);
|
|
rawData[rawPos + x] = val;
|
|
}
|
|
}
|
|
function filterSumAvg(pxData, pxPos, byteWidth, bpp) {
|
|
let sum = 0;
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
|
|
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
|
let val = pxData[pxPos + x] - (left + up >> 1);
|
|
sum += Math.abs(val);
|
|
}
|
|
return sum;
|
|
}
|
|
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
|
|
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
|
let upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
|
|
let val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
|
|
rawData[rawPos + x] = val;
|
|
}
|
|
}
|
|
function filterSumPaeth(pxData, pxPos, byteWidth, bpp) {
|
|
let sum = 0;
|
|
for (let x = 0; x < byteWidth; x++) {
|
|
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
|
|
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
|
let upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
|
|
let val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
|
|
sum += Math.abs(val);
|
|
}
|
|
return sum;
|
|
}
|
|
var filters = {
|
|
0: filterNone,
|
|
1: filterSub,
|
|
2: filterUp,
|
|
3: filterAvg,
|
|
4: filterPaeth
|
|
};
|
|
var filterSums = {
|
|
0: filterSumNone,
|
|
1: filterSumSub,
|
|
2: filterSumUp,
|
|
3: filterSumAvg,
|
|
4: filterSumPaeth
|
|
};
|
|
module2.exports = function(pxData, width, height, options, bpp) {
|
|
let filterTypes;
|
|
if (!("filterType" in options) || options.filterType === -1) {
|
|
filterTypes = [0, 1, 2, 3, 4];
|
|
} else if (typeof options.filterType === "number") {
|
|
filterTypes = [options.filterType];
|
|
} else {
|
|
throw new Error("unrecognised filter types");
|
|
}
|
|
if (options.bitDepth === 16) {
|
|
bpp *= 2;
|
|
}
|
|
let byteWidth = width * bpp;
|
|
let rawPos = 0;
|
|
let pxPos = 0;
|
|
let rawData = Buffer.alloc((byteWidth + 1) * height);
|
|
let sel = filterTypes[0];
|
|
for (let y = 0; y < height; y++) {
|
|
if (filterTypes.length > 1) {
|
|
let min = Infinity;
|
|
for (let i = 0; i < filterTypes.length; i++) {
|
|
let sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp);
|
|
if (sum < min) {
|
|
sel = filterTypes[i];
|
|
min = sum;
|
|
}
|
|
}
|
|
}
|
|
rawData[rawPos] = sel;
|
|
rawPos++;
|
|
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos, bpp);
|
|
rawPos += byteWidth;
|
|
pxPos += byteWidth;
|
|
}
|
|
return rawData;
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/packer.js
|
|
var require_packer = __commonJS({
|
|
"node_modules/pngjs/lib/packer.js"(exports2, module2) {
|
|
"use strict";
|
|
var constants = require_constants();
|
|
var CrcStream = require_crc();
|
|
var bitPacker = require_bitpacker();
|
|
var filter = require_filter_pack();
|
|
var zlib = require("zlib");
|
|
var Packer = module2.exports = function(options) {
|
|
this._options = options;
|
|
options.deflateChunkSize = options.deflateChunkSize || 32 * 1024;
|
|
options.deflateLevel = options.deflateLevel != null ? options.deflateLevel : 9;
|
|
options.deflateStrategy = options.deflateStrategy != null ? options.deflateStrategy : 3;
|
|
options.inputHasAlpha = options.inputHasAlpha != null ? options.inputHasAlpha : true;
|
|
options.deflateFactory = options.deflateFactory || zlib.createDeflate;
|
|
options.bitDepth = options.bitDepth || 8;
|
|
options.colorType = typeof options.colorType === "number" ? options.colorType : constants.COLORTYPE_COLOR_ALPHA;
|
|
options.inputColorType = typeof options.inputColorType === "number" ? options.inputColorType : constants.COLORTYPE_COLOR_ALPHA;
|
|
if ([
|
|
constants.COLORTYPE_GRAYSCALE,
|
|
constants.COLORTYPE_COLOR,
|
|
constants.COLORTYPE_COLOR_ALPHA,
|
|
constants.COLORTYPE_ALPHA
|
|
].indexOf(options.colorType) === -1) {
|
|
throw new Error(
|
|
"option color type:" + options.colorType + " is not supported at present"
|
|
);
|
|
}
|
|
if ([
|
|
constants.COLORTYPE_GRAYSCALE,
|
|
constants.COLORTYPE_COLOR,
|
|
constants.COLORTYPE_COLOR_ALPHA,
|
|
constants.COLORTYPE_ALPHA
|
|
].indexOf(options.inputColorType) === -1) {
|
|
throw new Error(
|
|
"option input color type:" + options.inputColorType + " is not supported at present"
|
|
);
|
|
}
|
|
if (options.bitDepth !== 8 && options.bitDepth !== 16) {
|
|
throw new Error(
|
|
"option bit depth:" + options.bitDepth + " is not supported at present"
|
|
);
|
|
}
|
|
};
|
|
Packer.prototype.getDeflateOptions = function() {
|
|
return {
|
|
chunkSize: this._options.deflateChunkSize,
|
|
level: this._options.deflateLevel,
|
|
strategy: this._options.deflateStrategy
|
|
};
|
|
};
|
|
Packer.prototype.createDeflate = function() {
|
|
return this._options.deflateFactory(this.getDeflateOptions());
|
|
};
|
|
Packer.prototype.filterData = function(data, width, height) {
|
|
let packedData = bitPacker(data, width, height, this._options);
|
|
let bpp = constants.COLORTYPE_TO_BPP_MAP[this._options.colorType];
|
|
let filteredData = filter(packedData, width, height, this._options, bpp);
|
|
return filteredData;
|
|
};
|
|
Packer.prototype._packChunk = function(type, data) {
|
|
let len = data ? data.length : 0;
|
|
let buf = Buffer.alloc(len + 12);
|
|
buf.writeUInt32BE(len, 0);
|
|
buf.writeUInt32BE(type, 4);
|
|
if (data) {
|
|
data.copy(buf, 8);
|
|
}
|
|
buf.writeInt32BE(
|
|
CrcStream.crc32(buf.slice(4, buf.length - 4)),
|
|
buf.length - 4
|
|
);
|
|
return buf;
|
|
};
|
|
Packer.prototype.packGAMA = function(gamma) {
|
|
let buf = Buffer.alloc(4);
|
|
buf.writeUInt32BE(Math.floor(gamma * constants.GAMMA_DIVISION), 0);
|
|
return this._packChunk(constants.TYPE_gAMA, buf);
|
|
};
|
|
Packer.prototype.packIHDR = function(width, height) {
|
|
let buf = Buffer.alloc(13);
|
|
buf.writeUInt32BE(width, 0);
|
|
buf.writeUInt32BE(height, 4);
|
|
buf[8] = this._options.bitDepth;
|
|
buf[9] = this._options.colorType;
|
|
buf[10] = 0;
|
|
buf[11] = 0;
|
|
buf[12] = 0;
|
|
return this._packChunk(constants.TYPE_IHDR, buf);
|
|
};
|
|
Packer.prototype.packIDAT = function(data) {
|
|
return this._packChunk(constants.TYPE_IDAT, data);
|
|
};
|
|
Packer.prototype.packIEND = function() {
|
|
return this._packChunk(constants.TYPE_IEND, null);
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/packer-async.js
|
|
var require_packer_async = __commonJS({
|
|
"node_modules/pngjs/lib/packer-async.js"(exports2, module2) {
|
|
"use strict";
|
|
var util = require("util");
|
|
var Stream = require("stream");
|
|
var constants = require_constants();
|
|
var Packer = require_packer();
|
|
var PackerAsync = module2.exports = function(opt) {
|
|
Stream.call(this);
|
|
let options = opt || {};
|
|
this._packer = new Packer(options);
|
|
this._deflate = this._packer.createDeflate();
|
|
this.readable = true;
|
|
};
|
|
util.inherits(PackerAsync, Stream);
|
|
PackerAsync.prototype.pack = function(data, width, height, gamma) {
|
|
this.emit("data", Buffer.from(constants.PNG_SIGNATURE));
|
|
this.emit("data", this._packer.packIHDR(width, height));
|
|
if (gamma) {
|
|
this.emit("data", this._packer.packGAMA(gamma));
|
|
}
|
|
let filteredData = this._packer.filterData(data, width, height);
|
|
this._deflate.on("error", this.emit.bind(this, "error"));
|
|
this._deflate.on(
|
|
"data",
|
|
(function(compressedData) {
|
|
this.emit("data", this._packer.packIDAT(compressedData));
|
|
}).bind(this)
|
|
);
|
|
this._deflate.on(
|
|
"end",
|
|
(function() {
|
|
this.emit("data", this._packer.packIEND());
|
|
this.emit("end");
|
|
}).bind(this)
|
|
);
|
|
this._deflate.end(filteredData);
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/sync-inflate.js
|
|
var require_sync_inflate = __commonJS({
|
|
"node_modules/pngjs/lib/sync-inflate.js"(exports2, module2) {
|
|
"use strict";
|
|
var assert = require("assert").ok;
|
|
var zlib = require("zlib");
|
|
var util = require("util");
|
|
var kMaxLength = require("buffer").kMaxLength;
|
|
function Inflate(opts) {
|
|
if (!(this instanceof Inflate)) {
|
|
return new Inflate(opts);
|
|
}
|
|
if (opts && opts.chunkSize < zlib.Z_MIN_CHUNK) {
|
|
opts.chunkSize = zlib.Z_MIN_CHUNK;
|
|
}
|
|
zlib.Inflate.call(this, opts);
|
|
this._offset = this._offset === void 0 ? this._outOffset : this._offset;
|
|
this._buffer = this._buffer || this._outBuffer;
|
|
if (opts && opts.maxLength != null) {
|
|
this._maxLength = opts.maxLength;
|
|
}
|
|
}
|
|
function createInflate(opts) {
|
|
return new Inflate(opts);
|
|
}
|
|
function _close(engine, callback) {
|
|
if (callback) {
|
|
process.nextTick(callback);
|
|
}
|
|
if (!engine._handle) {
|
|
return;
|
|
}
|
|
engine._handle.close();
|
|
engine._handle = null;
|
|
}
|
|
Inflate.prototype._processChunk = function(chunk, flushFlag, asyncCb) {
|
|
if (typeof asyncCb === "function") {
|
|
return zlib.Inflate._processChunk.call(this, chunk, flushFlag, asyncCb);
|
|
}
|
|
let self = this;
|
|
let availInBefore = chunk && chunk.length;
|
|
let availOutBefore = this._chunkSize - this._offset;
|
|
let leftToInflate = this._maxLength;
|
|
let inOff = 0;
|
|
let buffers = [];
|
|
let nread = 0;
|
|
let error;
|
|
this.on("error", function(err) {
|
|
error = err;
|
|
});
|
|
function handleChunk(availInAfter, availOutAfter) {
|
|
if (self._hadError) {
|
|
return;
|
|
}
|
|
let have = availOutBefore - availOutAfter;
|
|
assert(have >= 0, "have should not go down");
|
|
if (have > 0) {
|
|
let out = self._buffer.slice(self._offset, self._offset + have);
|
|
self._offset += have;
|
|
if (out.length > leftToInflate) {
|
|
out = out.slice(0, leftToInflate);
|
|
}
|
|
buffers.push(out);
|
|
nread += out.length;
|
|
leftToInflate -= out.length;
|
|
if (leftToInflate === 0) {
|
|
return false;
|
|
}
|
|
}
|
|
if (availOutAfter === 0 || self._offset >= self._chunkSize) {
|
|
availOutBefore = self._chunkSize;
|
|
self._offset = 0;
|
|
self._buffer = Buffer.allocUnsafe(self._chunkSize);
|
|
}
|
|
if (availOutAfter === 0) {
|
|
inOff += availInBefore - availInAfter;
|
|
availInBefore = availInAfter;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
assert(this._handle, "zlib binding closed");
|
|
let res;
|
|
do {
|
|
res = this._handle.writeSync(
|
|
flushFlag,
|
|
chunk,
|
|
// in
|
|
inOff,
|
|
// in_off
|
|
availInBefore,
|
|
// in_len
|
|
this._buffer,
|
|
// out
|
|
this._offset,
|
|
//out_off
|
|
availOutBefore
|
|
);
|
|
res = res || this._writeState;
|
|
} while (!this._hadError && handleChunk(res[0], res[1]));
|
|
if (this._hadError) {
|
|
throw error;
|
|
}
|
|
if (nread >= kMaxLength) {
|
|
_close(this);
|
|
throw new RangeError(
|
|
"Cannot create final Buffer. It would be larger than 0x" + kMaxLength.toString(16) + " bytes"
|
|
);
|
|
}
|
|
let buf = Buffer.concat(buffers, nread);
|
|
_close(this);
|
|
return buf;
|
|
};
|
|
util.inherits(Inflate, zlib.Inflate);
|
|
function zlibBufferSync(engine, buffer) {
|
|
if (typeof buffer === "string") {
|
|
buffer = Buffer.from(buffer);
|
|
}
|
|
if (!(buffer instanceof Buffer)) {
|
|
throw new TypeError("Not a string or buffer");
|
|
}
|
|
let flushFlag = engine._finishFlushFlag;
|
|
if (flushFlag == null) {
|
|
flushFlag = zlib.Z_FINISH;
|
|
}
|
|
return engine._processChunk(buffer, flushFlag);
|
|
}
|
|
function inflateSync(buffer, opts) {
|
|
return zlibBufferSync(new Inflate(opts), buffer);
|
|
}
|
|
module2.exports = exports2 = inflateSync;
|
|
exports2.Inflate = Inflate;
|
|
exports2.createInflate = createInflate;
|
|
exports2.inflateSync = inflateSync;
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/sync-reader.js
|
|
var require_sync_reader = __commonJS({
|
|
"node_modules/pngjs/lib/sync-reader.js"(exports2, module2) {
|
|
"use strict";
|
|
var SyncReader = module2.exports = function(buffer) {
|
|
this._buffer = buffer;
|
|
this._reads = [];
|
|
};
|
|
SyncReader.prototype.read = function(length, callback) {
|
|
this._reads.push({
|
|
length: Math.abs(length),
|
|
// if length < 0 then at most this length
|
|
allowLess: length < 0,
|
|
func: callback
|
|
});
|
|
};
|
|
SyncReader.prototype.process = function() {
|
|
while (this._reads.length > 0 && this._buffer.length) {
|
|
let read = this._reads[0];
|
|
if (this._buffer.length && (this._buffer.length >= read.length || read.allowLess)) {
|
|
this._reads.shift();
|
|
let buf = this._buffer;
|
|
this._buffer = buf.slice(read.length);
|
|
read.func.call(this, buf.slice(0, read.length));
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (this._reads.length > 0) {
|
|
throw new Error("There are some read requests waitng on finished stream");
|
|
}
|
|
if (this._buffer.length > 0) {
|
|
throw new Error("unrecognised content at end of stream");
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/filter-parse-sync.js
|
|
var require_filter_parse_sync = __commonJS({
|
|
"node_modules/pngjs/lib/filter-parse-sync.js"(exports2) {
|
|
"use strict";
|
|
var SyncReader = require_sync_reader();
|
|
var Filter = require_filter_parse();
|
|
exports2.process = function(inBuffer, bitmapInfo) {
|
|
let outBuffers = [];
|
|
let reader = new SyncReader(inBuffer);
|
|
let filter = new Filter(bitmapInfo, {
|
|
read: reader.read.bind(reader),
|
|
write: function(bufferPart) {
|
|
outBuffers.push(bufferPart);
|
|
},
|
|
complete: function() {
|
|
}
|
|
});
|
|
filter.start();
|
|
reader.process();
|
|
return Buffer.concat(outBuffers);
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/parser-sync.js
|
|
var require_parser_sync = __commonJS({
|
|
"node_modules/pngjs/lib/parser-sync.js"(exports2, module2) {
|
|
"use strict";
|
|
var hasSyncZlib = true;
|
|
var zlib = require("zlib");
|
|
var inflateSync = require_sync_inflate();
|
|
if (!zlib.deflateSync) {
|
|
hasSyncZlib = false;
|
|
}
|
|
var SyncReader = require_sync_reader();
|
|
var FilterSync = require_filter_parse_sync();
|
|
var Parser = require_parser();
|
|
var bitmapper = require_bitmapper();
|
|
var formatNormaliser = require_format_normaliser();
|
|
module2.exports = function(buffer, options) {
|
|
if (!hasSyncZlib) {
|
|
throw new Error(
|
|
"To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0"
|
|
);
|
|
}
|
|
let err;
|
|
function handleError(_err_) {
|
|
err = _err_;
|
|
}
|
|
let metaData;
|
|
function handleMetaData(_metaData_) {
|
|
metaData = _metaData_;
|
|
}
|
|
function handleTransColor(transColor) {
|
|
metaData.transColor = transColor;
|
|
}
|
|
function handlePalette(palette) {
|
|
metaData.palette = palette;
|
|
}
|
|
function handleSimpleTransparency() {
|
|
metaData.alpha = true;
|
|
}
|
|
let gamma;
|
|
function handleGamma(_gamma_) {
|
|
gamma = _gamma_;
|
|
}
|
|
let inflateDataList = [];
|
|
function handleInflateData(inflatedData2) {
|
|
inflateDataList.push(inflatedData2);
|
|
}
|
|
let reader = new SyncReader(buffer);
|
|
let parser = new Parser(options, {
|
|
read: reader.read.bind(reader),
|
|
error: handleError,
|
|
metadata: handleMetaData,
|
|
gamma: handleGamma,
|
|
palette: handlePalette,
|
|
transColor: handleTransColor,
|
|
inflateData: handleInflateData,
|
|
simpleTransparency: handleSimpleTransparency
|
|
});
|
|
parser.start();
|
|
reader.process();
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
let inflateData = Buffer.concat(inflateDataList);
|
|
inflateDataList.length = 0;
|
|
let inflatedData;
|
|
if (metaData.interlace) {
|
|
inflatedData = zlib.inflateSync(inflateData);
|
|
} else {
|
|
let rowSize = (metaData.width * metaData.bpp * metaData.depth + 7 >> 3) + 1;
|
|
let imageSize = rowSize * metaData.height;
|
|
inflatedData = inflateSync(inflateData, {
|
|
chunkSize: imageSize,
|
|
maxLength: imageSize
|
|
});
|
|
}
|
|
inflateData = null;
|
|
if (!inflatedData || !inflatedData.length) {
|
|
throw new Error("bad png - invalid inflate data response");
|
|
}
|
|
let unfilteredData = FilterSync.process(inflatedData, metaData);
|
|
inflateData = null;
|
|
let bitmapData = bitmapper.dataToBitMap(unfilteredData, metaData);
|
|
unfilteredData = null;
|
|
let normalisedBitmapData = formatNormaliser(
|
|
bitmapData,
|
|
metaData,
|
|
options.skipRescale
|
|
);
|
|
metaData.data = normalisedBitmapData;
|
|
metaData.gamma = gamma || 0;
|
|
return metaData;
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/packer-sync.js
|
|
var require_packer_sync = __commonJS({
|
|
"node_modules/pngjs/lib/packer-sync.js"(exports2, module2) {
|
|
"use strict";
|
|
var hasSyncZlib = true;
|
|
var zlib = require("zlib");
|
|
if (!zlib.deflateSync) {
|
|
hasSyncZlib = false;
|
|
}
|
|
var constants = require_constants();
|
|
var Packer = require_packer();
|
|
module2.exports = function(metaData, opt) {
|
|
if (!hasSyncZlib) {
|
|
throw new Error(
|
|
"To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0"
|
|
);
|
|
}
|
|
let options = opt || {};
|
|
let packer = new Packer(options);
|
|
let chunks = [];
|
|
chunks.push(Buffer.from(constants.PNG_SIGNATURE));
|
|
chunks.push(packer.packIHDR(metaData.width, metaData.height));
|
|
if (metaData.gamma) {
|
|
chunks.push(packer.packGAMA(metaData.gamma));
|
|
}
|
|
let filteredData = packer.filterData(
|
|
metaData.data,
|
|
metaData.width,
|
|
metaData.height
|
|
);
|
|
let compressedData = zlib.deflateSync(
|
|
filteredData,
|
|
packer.getDeflateOptions()
|
|
);
|
|
filteredData = null;
|
|
if (!compressedData || !compressedData.length) {
|
|
throw new Error("bad png - invalid compressed data response");
|
|
}
|
|
chunks.push(packer.packIDAT(compressedData));
|
|
chunks.push(packer.packIEND());
|
|
return Buffer.concat(chunks);
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/png-sync.js
|
|
var require_png_sync = __commonJS({
|
|
"node_modules/pngjs/lib/png-sync.js"(exports2) {
|
|
"use strict";
|
|
var parse = require_parser_sync();
|
|
var pack = require_packer_sync();
|
|
exports2.read = function(buffer, options) {
|
|
return parse(buffer, options || {});
|
|
};
|
|
exports2.write = function(png, options) {
|
|
return pack(png, options);
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/pngjs/lib/png.js
|
|
var require_png = __commonJS({
|
|
"node_modules/pngjs/lib/png.js"(exports2) {
|
|
"use strict";
|
|
var util = require("util");
|
|
var Stream = require("stream");
|
|
var Parser = require_parser_async();
|
|
var Packer = require_packer_async();
|
|
var PNGSync = require_png_sync();
|
|
var PNG2 = exports2.PNG = function(options) {
|
|
Stream.call(this);
|
|
options = options || {};
|
|
this.width = options.width | 0;
|
|
this.height = options.height | 0;
|
|
this.data = this.width > 0 && this.height > 0 ? Buffer.alloc(4 * this.width * this.height) : null;
|
|
if (options.fill && this.data) {
|
|
this.data.fill(0);
|
|
}
|
|
this.gamma = 0;
|
|
this.readable = this.writable = true;
|
|
this._parser = new Parser(options);
|
|
this._parser.on("error", this.emit.bind(this, "error"));
|
|
this._parser.on("close", this._handleClose.bind(this));
|
|
this._parser.on("metadata", this._metadata.bind(this));
|
|
this._parser.on("gamma", this._gamma.bind(this));
|
|
this._parser.on(
|
|
"parsed",
|
|
(function(data) {
|
|
this.data = data;
|
|
this.emit("parsed", data);
|
|
}).bind(this)
|
|
);
|
|
this._packer = new Packer(options);
|
|
this._packer.on("data", this.emit.bind(this, "data"));
|
|
this._packer.on("end", this.emit.bind(this, "end"));
|
|
this._parser.on("close", this._handleClose.bind(this));
|
|
this._packer.on("error", this.emit.bind(this, "error"));
|
|
};
|
|
util.inherits(PNG2, Stream);
|
|
PNG2.sync = PNGSync;
|
|
PNG2.prototype.pack = function() {
|
|
if (!this.data || !this.data.length) {
|
|
this.emit("error", "No data provided");
|
|
return this;
|
|
}
|
|
process.nextTick(
|
|
(function() {
|
|
this._packer.pack(this.data, this.width, this.height, this.gamma);
|
|
}).bind(this)
|
|
);
|
|
return this;
|
|
};
|
|
PNG2.prototype.parse = function(data, callback) {
|
|
if (callback) {
|
|
let onParsed, onError;
|
|
onParsed = (function(parsedData) {
|
|
this.removeListener("error", onError);
|
|
this.data = parsedData;
|
|
callback(null, this);
|
|
}).bind(this);
|
|
onError = (function(err) {
|
|
this.removeListener("parsed", onParsed);
|
|
callback(err, null);
|
|
}).bind(this);
|
|
this.once("parsed", onParsed);
|
|
this.once("error", onError);
|
|
}
|
|
this.end(data);
|
|
return this;
|
|
};
|
|
PNG2.prototype.write = function(data) {
|
|
this._parser.write(data);
|
|
return true;
|
|
};
|
|
PNG2.prototype.end = function(data) {
|
|
this._parser.end(data);
|
|
};
|
|
PNG2.prototype._metadata = function(metadata) {
|
|
this.width = metadata.width;
|
|
this.height = metadata.height;
|
|
this.emit("metadata", metadata);
|
|
};
|
|
PNG2.prototype._gamma = function(gamma) {
|
|
this.gamma = gamma;
|
|
};
|
|
PNG2.prototype._handleClose = function() {
|
|
if (!this._parser.writable && !this._packer.readable) {
|
|
this.emit("close");
|
|
}
|
|
};
|
|
PNG2.bitblt = function(src, dst, srcX, srcY, width, height, deltaX, deltaY) {
|
|
srcX |= 0;
|
|
srcY |= 0;
|
|
width |= 0;
|
|
height |= 0;
|
|
deltaX |= 0;
|
|
deltaY |= 0;
|
|
if (srcX > src.width || srcY > src.height || srcX + width > src.width || srcY + height > src.height) {
|
|
throw new Error("bitblt reading outside image");
|
|
}
|
|
if (deltaX > dst.width || deltaY > dst.height || deltaX + width > dst.width || deltaY + height > dst.height) {
|
|
throw new Error("bitblt writing outside image");
|
|
}
|
|
for (let y = 0; y < height; y++) {
|
|
src.data.copy(
|
|
dst.data,
|
|
(deltaY + y) * dst.width + deltaX << 2,
|
|
(srcY + y) * src.width + srcX << 2,
|
|
(srcY + y) * src.width + srcX + width << 2
|
|
);
|
|
}
|
|
};
|
|
PNG2.prototype.bitblt = function(dst, srcX, srcY, width, height, deltaX, deltaY) {
|
|
PNG2.bitblt(this, dst, srcX, srcY, width, height, deltaX, deltaY);
|
|
return this;
|
|
};
|
|
PNG2.adjustGamma = function(src) {
|
|
if (src.gamma) {
|
|
for (let y = 0; y < src.height; y++) {
|
|
for (let x = 0; x < src.width; x++) {
|
|
let idx = src.width * y + x << 2;
|
|
for (let i = 0; i < 3; i++) {
|
|
let sample = src.data[idx + i] / 255;
|
|
sample = Math.pow(sample, 1 / 2.2 / src.gamma);
|
|
src.data[idx + i] = Math.round(sample * 255);
|
|
}
|
|
}
|
|
}
|
|
src.gamma = 0;
|
|
}
|
|
};
|
|
PNG2.prototype.adjustGamma = function() {
|
|
PNG2.adjustGamma(this);
|
|
};
|
|
}
|
|
});
|
|
|
|
// src/screenshot/pixel-match.ts
|
|
var import_fs = __toESM(require("fs"));
|
|
var import_pixelmatch = __toESM(require_pixelmatch());
|
|
var import_pngjs = __toESM(require_png());
|
|
function getMismatchedPixels(pixelMatchInput) {
|
|
const imgA = import_fs.default.createReadStream(pixelMatchInput.imageAPath).pipe(new import_pngjs.PNG()).on("parsed", doneReading);
|
|
const imgB = import_fs.default.createReadStream(pixelMatchInput.imageBPath).pipe(new import_pngjs.PNG()).on("parsed", doneReading);
|
|
let filesRead = 0;
|
|
function doneReading() {
|
|
if (++filesRead < 2) return;
|
|
const mismatchedPixels = (0, import_pixelmatch.default)(imgA.data, imgB.data, null, pixelMatchInput.width, pixelMatchInput.height, {
|
|
threshold: pixelMatchInput.pixelmatchThreshold,
|
|
includeAA: false
|
|
});
|
|
if (typeof process.send !== "function") {
|
|
throw new Error("`getMismatchedPixels` must be run in a child process.");
|
|
}
|
|
process.send(mismatchedPixels);
|
|
}
|
|
}
|
|
process.on("message", getMismatchedPixels);
|
|
|