@wdio/image-comparison-core 1.3.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -3
- package/dist/base.interfaces.d.ts +2 -2
- package/dist/helpers/constants.js +1 -1
- package/dist/helpers/options.d.ts +1 -4
- package/dist/helpers/options.d.ts.map +1 -1
- package/dist/helpers/options.interfaces.d.ts +4 -2
- package/dist/helpers/options.interfaces.d.ts.map +1 -1
- package/dist/helpers/options.js +2 -11
- package/dist/helpers/options.test.js +16 -1
- package/dist/methods/compareReport.interfaces.d.ts +1 -1
- package/dist/methods/compareReport.interfaces.d.ts.map +1 -1
- package/dist/methods/createCompareReport.test.js +4 -2
- package/dist/methods/images.d.ts +2 -1
- package/dist/methods/images.d.ts.map +1 -1
- package/dist/methods/images.executeImageCompare.test.js +60 -44
- package/dist/methods/images.js +31 -31
- package/dist/methods/images.test.js +80 -220
- package/dist/methods/processDiffPixels.d.ts +1 -1
- package/dist/methods/processDiffPixels.d.ts.map +1 -1
- package/dist/methods/processDiffPixels.js +11 -2
- package/dist/methods/rectangles.d.ts.map +1 -1
- package/dist/methods/rectangles.interfaces.d.ts +1 -1
- package/dist/methods/rectangles.interfaces.d.ts.map +1 -1
- package/dist/methods/rectangles.js +12 -9
- package/dist/pixelmatch/compare.interfaces.d.ts +43 -0
- package/dist/pixelmatch/compare.interfaces.d.ts.map +1 -0
- package/dist/pixelmatch/compareImages.d.ts.map +1 -0
- package/dist/pixelmatch/compareImages.js +178 -0
- package/dist/pixelmatch/compareImages.test.d.ts +2 -0
- package/dist/pixelmatch/compareImages.test.d.ts.map +1 -0
- package/dist/pixelmatch/compareImages.test.js +267 -0
- package/dist/utils/imageUtils.d.ts +17 -0
- package/dist/utils/imageUtils.d.ts.map +1 -0
- package/dist/utils/imageUtils.js +189 -0
- package/dist/utils/imageUtils.test.d.ts +2 -0
- package/dist/utils/imageUtils.test.d.ts.map +1 -0
- package/dist/utils/imageUtils.test.js +277 -0
- package/package.json +3 -2
- package/dist/resemble/compare.interfaces.d.ts +0 -136
- package/dist/resemble/compare.interfaces.d.ts.map +0 -1
- package/dist/resemble/compareImages.d.ts.map +0 -1
- package/dist/resemble/compareImages.js +0 -21
- package/dist/resemble/resemble.jimp.cjs +0 -981
- package/dist/resemble/resemble.jimp.d.cts +0 -46
- package/dist/resemble/resemble.jimp.d.cts.map +0 -1
- /package/dist/{resemble → pixelmatch}/compare.interfaces.js +0 -0
- /package/dist/{resemble → pixelmatch}/compareImages.d.ts +0 -0
|
@@ -1,981 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
James Cryer / Huddle
|
|
4
|
-
URL: https://github.com/Huddle/Resemble.js
|
|
5
|
-
Modified by: @wswebcreation
|
|
6
|
-
Reason: The node-canvas library was producing a lot of issues due to system dependency errors.
|
|
7
|
-
The Jimp library is a pure JavaScript image processing library that can be used in a Node.js environment.
|
|
8
|
-
The browser is not needed anymore, so the API is deliberately broken to only work in a Node.js environment.
|
|
9
|
-
The old code is still in the file, but commented out. This way, the code can easily be compared when needed with
|
|
10
|
-
the original resemble.js file.
|
|
11
|
-
*/
|
|
12
|
-
const { Jimp, JimpMime } = require('jimp');
|
|
13
|
-
const naiveFallback = function () {
|
|
14
|
-
// ISC (c) 2011-2019 https://github.com/medikoo/es5-ext/blob/master/global.js
|
|
15
|
-
if (typeof self === 'object' && self) {
|
|
16
|
-
return self;
|
|
17
|
-
}
|
|
18
|
-
if (typeof window === 'object' && window) {
|
|
19
|
-
return window;
|
|
20
|
-
}
|
|
21
|
-
throw new Error('Unable to resolve global `this`');
|
|
22
|
-
};
|
|
23
|
-
const getGlobalThis = function () {
|
|
24
|
-
// ISC (c) 2011-2019 https://github.com/medikoo/es5-ext/blob/master/global.js
|
|
25
|
-
// Fallback to standard globalThis if available
|
|
26
|
-
if (typeof globalThis === 'object' && globalThis) {
|
|
27
|
-
return globalThis;
|
|
28
|
-
}
|
|
29
|
-
try {
|
|
30
|
-
Object.defineProperty(Object.prototype, '__global__', {
|
|
31
|
-
get: function () {
|
|
32
|
-
return this;
|
|
33
|
-
},
|
|
34
|
-
configurable: true,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
return naiveFallback();
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
// eslint-disable-next-line no-undef
|
|
42
|
-
if (!__global__) {
|
|
43
|
-
return naiveFallback();
|
|
44
|
-
}
|
|
45
|
-
return __global__; // eslint-disable-line no-undef
|
|
46
|
-
}
|
|
47
|
-
finally {
|
|
48
|
-
delete Object.prototype.__global__;
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
const isNode = function () {
|
|
52
|
-
const globalPolyfill = getGlobalThis();
|
|
53
|
-
return (typeof globalPolyfill.process !== 'undefined' &&
|
|
54
|
-
globalPolyfill.process.versions &&
|
|
55
|
-
globalPolyfill.process.versions.node);
|
|
56
|
-
};
|
|
57
|
-
(function (root, factory) {
|
|
58
|
-
'use strict';
|
|
59
|
-
if (typeof define === 'function' && define.amd) {
|
|
60
|
-
define([], factory);
|
|
61
|
-
}
|
|
62
|
-
else if (typeof module === 'object' && module.exports) {
|
|
63
|
-
module.exports = factory();
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
root.resemble = factory();
|
|
67
|
-
}
|
|
68
|
-
})(this /* eslint-disable-line no-invalid-this*/, function () {
|
|
69
|
-
'use strict';
|
|
70
|
-
let Img;
|
|
71
|
-
// var Canvas;
|
|
72
|
-
// var loadNodeCanvasImage;
|
|
73
|
-
// if (isNode()) {
|
|
74
|
-
// Canvas = require("canvas"); // eslint-disable-line global-require
|
|
75
|
-
// Img = Canvas.Image;
|
|
76
|
-
// loadNodeCanvasImage = Canvas.loadImage;
|
|
77
|
-
// } else {
|
|
78
|
-
// Img = Image;
|
|
79
|
-
// }
|
|
80
|
-
function createCanvas(width, height) {
|
|
81
|
-
// if (isNode()) {
|
|
82
|
-
// return Canvas.createCanvas(width, height);
|
|
83
|
-
// }
|
|
84
|
-
// var cnvs = document.createElement("canvas");
|
|
85
|
-
// cnvs.width = width;
|
|
86
|
-
// cnvs.height = height;
|
|
87
|
-
// return cnvs;
|
|
88
|
-
return new Jimp({ width, height });
|
|
89
|
-
}
|
|
90
|
-
const oldGlobalSettings = {};
|
|
91
|
-
let globalOutputSettings = oldGlobalSettings;
|
|
92
|
-
const resemble = function (fileData) {
|
|
93
|
-
let pixelTransparency = 1;
|
|
94
|
-
const errorPixelColor = {
|
|
95
|
-
// Color for Error Pixels. Between 0 and 255.
|
|
96
|
-
red: 255,
|
|
97
|
-
green: 0,
|
|
98
|
-
blue: 255,
|
|
99
|
-
alpha: 255,
|
|
100
|
-
};
|
|
101
|
-
const targetPix = { r: 0, g: 0, b: 0, a: 0 }; // isAntialiased
|
|
102
|
-
const errorPixelTransform = {
|
|
103
|
-
flat: function (px, offset) {
|
|
104
|
-
px[offset] = errorPixelColor.red;
|
|
105
|
-
px[offset + 1] = errorPixelColor.green;
|
|
106
|
-
px[offset + 2] = errorPixelColor.blue;
|
|
107
|
-
px[offset + 3] = errorPixelColor.alpha;
|
|
108
|
-
},
|
|
109
|
-
movement: function (px, offset, d1, d2) {
|
|
110
|
-
px[offset] = (d2.r * (errorPixelColor.red / 255) + errorPixelColor.red) / 2;
|
|
111
|
-
px[offset + 1] = (d2.g * (errorPixelColor.green / 255) + errorPixelColor.green) / 2;
|
|
112
|
-
px[offset + 2] = (d2.b * (errorPixelColor.blue / 255) + errorPixelColor.blue) / 2;
|
|
113
|
-
px[offset + 3] = d2.a;
|
|
114
|
-
},
|
|
115
|
-
flatDifferenceIntensity: function (px, offset, d1, d2) {
|
|
116
|
-
px[offset] = errorPixelColor.red;
|
|
117
|
-
px[offset + 1] = errorPixelColor.green;
|
|
118
|
-
px[offset + 2] = errorPixelColor.blue;
|
|
119
|
-
px[offset + 3] = colorsDistance(d1, d2);
|
|
120
|
-
},
|
|
121
|
-
movementDifferenceIntensity: function (px, offset, d1, d2) {
|
|
122
|
-
const ratio = (colorsDistance(d1, d2) / 255) * 0.8;
|
|
123
|
-
px[offset] =
|
|
124
|
-
(1 - ratio) * (d2.r * (errorPixelColor.red / 255)) +
|
|
125
|
-
ratio * errorPixelColor.red;
|
|
126
|
-
px[offset + 1] =
|
|
127
|
-
(1 - ratio) * (d2.g * (errorPixelColor.green / 255)) +
|
|
128
|
-
ratio * errorPixelColor.green;
|
|
129
|
-
px[offset + 2] =
|
|
130
|
-
(1 - ratio) * (d2.b * (errorPixelColor.blue / 255)) +
|
|
131
|
-
ratio * errorPixelColor.blue;
|
|
132
|
-
px[offset + 3] = d2.a;
|
|
133
|
-
},
|
|
134
|
-
diffOnly: function (px, offset, d1, d2) {
|
|
135
|
-
px[offset] = d2.r;
|
|
136
|
-
px[offset + 1] = d2.g;
|
|
137
|
-
px[offset + 2] = d2.b;
|
|
138
|
-
px[offset + 3] = d2.a;
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
let errorPixel = errorPixelTransform.flat;
|
|
142
|
-
let errorType;
|
|
143
|
-
let boundingBoxes;
|
|
144
|
-
let ignoredBoxes;
|
|
145
|
-
let ignoreAreasColoredWith;
|
|
146
|
-
let largeImageThreshold = 1200;
|
|
147
|
-
let useCrossOrigin = true;
|
|
148
|
-
let data = {};
|
|
149
|
-
let images = [];
|
|
150
|
-
const updateCallbackArray = [];
|
|
151
|
-
const tolerance = {
|
|
152
|
-
// between 0 and 255
|
|
153
|
-
red: 16,
|
|
154
|
-
green: 16,
|
|
155
|
-
blue: 16,
|
|
156
|
-
alpha: 16,
|
|
157
|
-
minBrightness: 16,
|
|
158
|
-
maxBrightness: 240,
|
|
159
|
-
};
|
|
160
|
-
let ignoreAntialiasing = false;
|
|
161
|
-
let ignoreColors = false;
|
|
162
|
-
let scaleToSameSize = false;
|
|
163
|
-
let compareOnly = false;
|
|
164
|
-
let returnEarlyThreshold;
|
|
165
|
-
function colorsDistance(c1, c2) {
|
|
166
|
-
return ((Math.abs(c1.r - c2.r) + Math.abs(c1.g - c2.g) + Math.abs(c1.b - c2.b)) / 3);
|
|
167
|
-
}
|
|
168
|
-
function withinBoundingBox(x, y, width, height, box) {
|
|
169
|
-
return (x >= (box.left || 0) &&
|
|
170
|
-
x <= (box.right || width) &&
|
|
171
|
-
y >= (box.top || 0) &&
|
|
172
|
-
y <= (box.bottom || height));
|
|
173
|
-
}
|
|
174
|
-
function withinComparedArea(x, y, width, height, pixel2) {
|
|
175
|
-
let isIncluded = true;
|
|
176
|
-
let i;
|
|
177
|
-
let boundingBox;
|
|
178
|
-
let ignoredBox;
|
|
179
|
-
let selected;
|
|
180
|
-
let ignored;
|
|
181
|
-
if (boundingBoxes instanceof Array) {
|
|
182
|
-
selected = false;
|
|
183
|
-
for (i = 0; i < boundingBoxes.length; i++) {
|
|
184
|
-
boundingBox = boundingBoxes[i];
|
|
185
|
-
if (withinBoundingBox(x, y, width, height, boundingBox)) {
|
|
186
|
-
selected = true;
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
if (ignoredBoxes instanceof Array) {
|
|
192
|
-
ignored = true;
|
|
193
|
-
for (i = 0; i < ignoredBoxes.length; i++) {
|
|
194
|
-
ignoredBox = ignoredBoxes[i];
|
|
195
|
-
if (withinBoundingBox(x, y, width, height, ignoredBox)) {
|
|
196
|
-
ignored = false;
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
if (ignoreAreasColoredWith) {
|
|
202
|
-
return colorsDistance(pixel2, ignoreAreasColoredWith) !== 0;
|
|
203
|
-
}
|
|
204
|
-
if (selected === undefined && ignored === undefined) {
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
|
-
if (selected === false && ignored === true) {
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
if (selected === true || ignored === true) {
|
|
211
|
-
isIncluded = true;
|
|
212
|
-
}
|
|
213
|
-
if (selected === false || ignored === false) {
|
|
214
|
-
isIncluded = false;
|
|
215
|
-
}
|
|
216
|
-
return isIncluded;
|
|
217
|
-
}
|
|
218
|
-
function triggerDataUpdate() {
|
|
219
|
-
const len = updateCallbackArray.length;
|
|
220
|
-
let i;
|
|
221
|
-
for (i = 0; i < len; i++) {
|
|
222
|
-
if (typeof updateCallbackArray[i] === 'function') {
|
|
223
|
-
updateCallbackArray[i](data);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
function loop(w, h, callback) {
|
|
228
|
-
let x;
|
|
229
|
-
let y;
|
|
230
|
-
for (x = 0; x < w; x++) {
|
|
231
|
-
for (y = 0; y < h; y++) {
|
|
232
|
-
callback(x, y);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
function parseImage(sourceImageData, width, height) {
|
|
237
|
-
let pixelCount = 0;
|
|
238
|
-
let redTotal = 0;
|
|
239
|
-
let greenTotal = 0;
|
|
240
|
-
let blueTotal = 0;
|
|
241
|
-
let alphaTotal = 0;
|
|
242
|
-
let brightnessTotal = 0;
|
|
243
|
-
let whiteTotal = 0;
|
|
244
|
-
let blackTotal = 0;
|
|
245
|
-
loop(width, height, function (horizontalPos, verticalPos) {
|
|
246
|
-
const offset = (verticalPos * width + horizontalPos) * 4;
|
|
247
|
-
const red = sourceImageData[offset];
|
|
248
|
-
const green = sourceImageData[offset + 1];
|
|
249
|
-
const blue = sourceImageData[offset + 2];
|
|
250
|
-
const alpha = sourceImageData[offset + 3];
|
|
251
|
-
const brightness = getBrightness(red, green, blue);
|
|
252
|
-
if (red === green && red === blue && alpha) {
|
|
253
|
-
if (red === 0) {
|
|
254
|
-
blackTotal++;
|
|
255
|
-
}
|
|
256
|
-
else if (red === 255) {
|
|
257
|
-
whiteTotal++;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
pixelCount++;
|
|
261
|
-
redTotal += (red / 255) * 100;
|
|
262
|
-
greenTotal += (green / 255) * 100;
|
|
263
|
-
blueTotal += (blue / 255) * 100;
|
|
264
|
-
alphaTotal += ((255 - alpha) / 255) * 100;
|
|
265
|
-
brightnessTotal += (brightness / 255) * 100;
|
|
266
|
-
});
|
|
267
|
-
data.red = Math.floor(redTotal / pixelCount);
|
|
268
|
-
data.green = Math.floor(greenTotal / pixelCount);
|
|
269
|
-
data.blue = Math.floor(blueTotal / pixelCount);
|
|
270
|
-
data.alpha = Math.floor(alphaTotal / pixelCount);
|
|
271
|
-
data.brightness = Math.floor(brightnessTotal / pixelCount);
|
|
272
|
-
data.white = Math.floor((whiteTotal / pixelCount) * 100);
|
|
273
|
-
data.black = Math.floor((blackTotal / pixelCount) * 100);
|
|
274
|
-
triggerDataUpdate();
|
|
275
|
-
}
|
|
276
|
-
function onLoadImage(hiddenImage, callback) {
|
|
277
|
-
// don't assign to hiddenImage, see https://github.com/Huddle/Resemble.js/pull/87/commits/300d43352a2845aad289b254bfbdc7cd6a37e2d7
|
|
278
|
-
let width = hiddenImage.bitmap.width;
|
|
279
|
-
let height = hiddenImage.bitmap.height;
|
|
280
|
-
if (scaleToSameSize && images.length === 1) {
|
|
281
|
-
width = images[0].bitmap.width;
|
|
282
|
-
height = images[0].bitmap.height;
|
|
283
|
-
}
|
|
284
|
-
// var hiddenCanvas = createCanvas(width, height);
|
|
285
|
-
// var imageData;
|
|
286
|
-
// hiddenCanvas.getContext("2d").drawImage(hiddenImage, 0, 0, width, height);
|
|
287
|
-
// imageData = hiddenCanvas
|
|
288
|
-
// .getContext("2d")
|
|
289
|
-
// .getImageData(0, 0, width, height);
|
|
290
|
-
// images.push(imageData);
|
|
291
|
-
images.push(hiddenImage);
|
|
292
|
-
callback(hiddenImage, width, height);
|
|
293
|
-
}
|
|
294
|
-
function loadImageData(fileDataForImage, callback) {
|
|
295
|
-
// var fileReader;
|
|
296
|
-
// var hiddenImage = new Img();
|
|
297
|
-
// if (!hiddenImage.setAttribute) {
|
|
298
|
-
// hiddenImage.setAttribute = function setAttribute() {};
|
|
299
|
-
// }
|
|
300
|
-
// if (useCrossOrigin) {
|
|
301
|
-
// hiddenImage.setAttribute("crossorigin", "anonymous");
|
|
302
|
-
// }
|
|
303
|
-
// hiddenImage.onerror = function (event) {
|
|
304
|
-
// hiddenImage.onload = null;
|
|
305
|
-
// hiddenImage.onerror = null; // fixes pollution between calls
|
|
306
|
-
// const error = event ? event + "" : "Unknown error";
|
|
307
|
-
// images.push({
|
|
308
|
-
// error: `Failed to load image '${fileDataForImage}'. ${error}`,
|
|
309
|
-
// });
|
|
310
|
-
// callback();
|
|
311
|
-
// };
|
|
312
|
-
// hiddenImage.onload = function () {
|
|
313
|
-
// hiddenImage.onload = null; // fixes pollution between calls
|
|
314
|
-
// hiddenImage.onerror = null;
|
|
315
|
-
// onLoadImage(hiddenImage, callback);
|
|
316
|
-
// };
|
|
317
|
-
// if (typeof fileDataForImage === "string") {
|
|
318
|
-
// hiddenImage.src = fileDataForImage;
|
|
319
|
-
// if (!isNode() && hiddenImage.complete && hiddenImage.naturalWidth > 0) {
|
|
320
|
-
// hiddenImage.onload();
|
|
321
|
-
// }
|
|
322
|
-
// } else if (
|
|
323
|
-
// typeof fileDataForImage.data !== "undefined" &&
|
|
324
|
-
// typeof fileDataForImage.width === "number" &&
|
|
325
|
-
// typeof fileDataForImage.height === "number"
|
|
326
|
-
// ) {
|
|
327
|
-
// images.push(fileDataForImage);
|
|
328
|
-
// callback(
|
|
329
|
-
// fileDataForImage,
|
|
330
|
-
// fileDataForImage.width,
|
|
331
|
-
// fileDataForImage.height
|
|
332
|
-
// );
|
|
333
|
-
// } else if (
|
|
334
|
-
// typeof Buffer !== "undefined" &&
|
|
335
|
-
// fileDataForImage instanceof Buffer
|
|
336
|
-
// ) {
|
|
337
|
-
// // If we have Buffer, assume we're on Node+Canvas and its supported
|
|
338
|
-
// // hiddenImage.src = fileDataForImage;
|
|
339
|
-
// loadNodeCanvasImage(fileDataForImage)
|
|
340
|
-
// .then(function (image) {
|
|
341
|
-
// hiddenImage.onload = null; // fixes pollution between calls
|
|
342
|
-
// hiddenImage.onerror = null;
|
|
343
|
-
// onLoadImage(image, callback);
|
|
344
|
-
// })
|
|
345
|
-
// .catch(function (err) {
|
|
346
|
-
// images.push({
|
|
347
|
-
// error: err ? err + "" : "Image load error.",
|
|
348
|
-
// });
|
|
349
|
-
// callback();
|
|
350
|
-
// });
|
|
351
|
-
// } else {
|
|
352
|
-
// fileReader = new FileReader();
|
|
353
|
-
// fileReader.onload = function (event) {
|
|
354
|
-
// hiddenImage.src = event.target.result;
|
|
355
|
-
// };
|
|
356
|
-
// fileReader.readAsDataURL(fileDataForImage);
|
|
357
|
-
// }
|
|
358
|
-
Jimp.read(fileDataForImage)
|
|
359
|
-
.then((image) => {
|
|
360
|
-
onLoadImage(image, callback);
|
|
361
|
-
})
|
|
362
|
-
.catch((err) => {
|
|
363
|
-
images.push({
|
|
364
|
-
error: `Failed to load image '${fileDataForImage}'. ${err}`,
|
|
365
|
-
});
|
|
366
|
-
callback();
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
function isColorSimilar(a, b, color) {
|
|
370
|
-
const absDiff = Math.abs(a - b);
|
|
371
|
-
if (typeof a === 'undefined') {
|
|
372
|
-
return false;
|
|
373
|
-
}
|
|
374
|
-
if (typeof b === 'undefined') {
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
if (a === b) {
|
|
378
|
-
return true;
|
|
379
|
-
}
|
|
380
|
-
else if (absDiff < tolerance[color]) {
|
|
381
|
-
return true;
|
|
382
|
-
}
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
function isPixelBrightnessSimilar(d1, d2) {
|
|
386
|
-
const alpha = isColorSimilar(d1.a, d2.a, 'alpha');
|
|
387
|
-
const brightness = isColorSimilar(d1.brightness, d2.brightness, 'minBrightness');
|
|
388
|
-
return brightness && alpha;
|
|
389
|
-
}
|
|
390
|
-
function getBrightness(r, g, b) {
|
|
391
|
-
return 0.3 * r + 0.59 * g + 0.11 * b;
|
|
392
|
-
}
|
|
393
|
-
function isRGBSame(d1, d2) {
|
|
394
|
-
const red = d1.r === d2.r;
|
|
395
|
-
const green = d1.g === d2.g;
|
|
396
|
-
const blue = d1.b === d2.b;
|
|
397
|
-
return red && green && blue;
|
|
398
|
-
}
|
|
399
|
-
function isRGBSimilar(d1, d2) {
|
|
400
|
-
const red = isColorSimilar(d1.r, d2.r, 'red');
|
|
401
|
-
const green = isColorSimilar(d1.g, d2.g, 'green');
|
|
402
|
-
const blue = isColorSimilar(d1.b, d2.b, 'blue');
|
|
403
|
-
const alpha = isColorSimilar(d1.a, d2.a, 'alpha');
|
|
404
|
-
return red && green && blue && alpha;
|
|
405
|
-
}
|
|
406
|
-
function isContrasting(d1, d2) {
|
|
407
|
-
return Math.abs(d1.brightness - d2.brightness) > tolerance.maxBrightness;
|
|
408
|
-
}
|
|
409
|
-
function getHue(red, green, blue) {
|
|
410
|
-
const r = red / 255;
|
|
411
|
-
const g = green / 255;
|
|
412
|
-
const b = blue / 255;
|
|
413
|
-
const max = Math.max(r, g, b);
|
|
414
|
-
const min = Math.min(r, g, b);
|
|
415
|
-
let h;
|
|
416
|
-
let d;
|
|
417
|
-
if (max === min) {
|
|
418
|
-
h = 0; // achromatic
|
|
419
|
-
}
|
|
420
|
-
else {
|
|
421
|
-
d = max - min;
|
|
422
|
-
switch (max) {
|
|
423
|
-
case r:
|
|
424
|
-
h = (g - b) / d + (g < b ? 6 : 0);
|
|
425
|
-
break;
|
|
426
|
-
case g:
|
|
427
|
-
h = (b - r) / d + 2;
|
|
428
|
-
break;
|
|
429
|
-
case b:
|
|
430
|
-
h = (r - g) / d + 4;
|
|
431
|
-
break;
|
|
432
|
-
default:
|
|
433
|
-
h /= 6;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
return h;
|
|
437
|
-
}
|
|
438
|
-
function isAntialiased(sourcePix, pix, cacheSet, verticalPos, horizontalPos, width) {
|
|
439
|
-
let offset;
|
|
440
|
-
const distance = 1;
|
|
441
|
-
let i;
|
|
442
|
-
let j;
|
|
443
|
-
let hasHighContrastSibling = 0;
|
|
444
|
-
let hasSiblingWithDifferentHue = 0;
|
|
445
|
-
let hasEquivalentSibling = 0;
|
|
446
|
-
addHueInfo(sourcePix);
|
|
447
|
-
for (i = distance * -1; i <= distance; i++) {
|
|
448
|
-
for (j = distance * -1; j <= distance; j++) {
|
|
449
|
-
if (i === 0 && j === 0) {
|
|
450
|
-
// ignore source pixel
|
|
451
|
-
continue;
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
offset = ((verticalPos + j) * width + (horizontalPos + i)) * 4;
|
|
455
|
-
if (!getPixelInfo(targetPix, pix, offset, cacheSet)) {
|
|
456
|
-
continue;
|
|
457
|
-
}
|
|
458
|
-
addBrightnessInfo(targetPix);
|
|
459
|
-
addHueInfo(targetPix);
|
|
460
|
-
if (isContrasting(sourcePix, targetPix)) {
|
|
461
|
-
hasHighContrastSibling++;
|
|
462
|
-
}
|
|
463
|
-
if (isRGBSame(sourcePix, targetPix)) {
|
|
464
|
-
hasEquivalentSibling++;
|
|
465
|
-
}
|
|
466
|
-
if (Math.abs(targetPix.h - sourcePix.h) > 0.3) {
|
|
467
|
-
hasSiblingWithDifferentHue++;
|
|
468
|
-
}
|
|
469
|
-
if (hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1) {
|
|
470
|
-
return true;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
if (hasEquivalentSibling < 2) {
|
|
476
|
-
return true;
|
|
477
|
-
}
|
|
478
|
-
return false;
|
|
479
|
-
}
|
|
480
|
-
function copyPixel(px, offset, pix) {
|
|
481
|
-
if (errorType === 'diffOnly') {
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
px[offset] = pix.r; // r
|
|
485
|
-
px[offset + 1] = pix.g; // g
|
|
486
|
-
px[offset + 2] = pix.b; // b
|
|
487
|
-
px[offset + 3] = pix.a * pixelTransparency; // a
|
|
488
|
-
}
|
|
489
|
-
function copyGrayScalePixel(px, offset, pix) {
|
|
490
|
-
if (errorType === 'diffOnly') {
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
px[offset] = pix.brightness; // r
|
|
494
|
-
px[offset + 1] = pix.brightness; // g
|
|
495
|
-
px[offset + 2] = pix.brightness; // b
|
|
496
|
-
px[offset + 3] = pix.a * pixelTransparency; // a
|
|
497
|
-
}
|
|
498
|
-
function getPixelInfo(dst, pix, offset) {
|
|
499
|
-
if (pix.length > offset) {
|
|
500
|
-
dst.r = pix[offset];
|
|
501
|
-
dst.g = pix[offset + 1];
|
|
502
|
-
dst.b = pix[offset + 2];
|
|
503
|
-
dst.a = pix[offset + 3];
|
|
504
|
-
return true;
|
|
505
|
-
}
|
|
506
|
-
return false;
|
|
507
|
-
}
|
|
508
|
-
function addBrightnessInfo(pix) {
|
|
509
|
-
pix.brightness = getBrightness(pix.r, pix.g, pix.b); // 'corrected' lightness
|
|
510
|
-
}
|
|
511
|
-
function addHueInfo(pix) {
|
|
512
|
-
pix.h = getHue(pix.r, pix.g, pix.b);
|
|
513
|
-
}
|
|
514
|
-
function analyseImages(img1, img2, width, height) {
|
|
515
|
-
const data1 = img1.bitmap.data;
|
|
516
|
-
const data2 = img2.bitmap.data;
|
|
517
|
-
let hiddenCanvas;
|
|
518
|
-
// var context;
|
|
519
|
-
// var imgd;
|
|
520
|
-
let pix;
|
|
521
|
-
if (!compareOnly) {
|
|
522
|
-
hiddenCanvas = createCanvas(width, height);
|
|
523
|
-
// context = hiddenCanvas.getContext("2d");
|
|
524
|
-
// imgd = context.createImageData(width, height);
|
|
525
|
-
pix = hiddenCanvas.bitmap.data;
|
|
526
|
-
}
|
|
527
|
-
let mismatchCount = 0;
|
|
528
|
-
const diffBounds = {
|
|
529
|
-
top: height,
|
|
530
|
-
left: width,
|
|
531
|
-
bottom: 0,
|
|
532
|
-
right: 0,
|
|
533
|
-
};
|
|
534
|
-
const diffPixels = [];
|
|
535
|
-
const updateBounds = function (x, y) {
|
|
536
|
-
// Update the big box
|
|
537
|
-
diffBounds.left = Math.min(x, diffBounds.left);
|
|
538
|
-
diffBounds.right = Math.max(x, diffBounds.right);
|
|
539
|
-
diffBounds.top = Math.min(y, diffBounds.top);
|
|
540
|
-
diffBounds.bottom = Math.max(y, diffBounds.bottom);
|
|
541
|
-
// Update the diffPixels array
|
|
542
|
-
diffPixels.push({ x, y });
|
|
543
|
-
};
|
|
544
|
-
const time = Date.now();
|
|
545
|
-
let skip;
|
|
546
|
-
if (!!largeImageThreshold &&
|
|
547
|
-
ignoreAntialiasing &&
|
|
548
|
-
(width > largeImageThreshold || height > largeImageThreshold)) {
|
|
549
|
-
skip = 6;
|
|
550
|
-
}
|
|
551
|
-
const pixel1 = { r: 0, g: 0, b: 0, a: 0 };
|
|
552
|
-
const pixel2 = { r: 0, g: 0, b: 0, a: 0 };
|
|
553
|
-
let skipTheRest = false;
|
|
554
|
-
loop(width, height, function (horizontalPos, verticalPos) {
|
|
555
|
-
if (skipTheRest) {
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
if (skip) {
|
|
559
|
-
// only skip if the image isn't small
|
|
560
|
-
if (verticalPos % skip === 0 || horizontalPos % skip === 0) {
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
const offset = (verticalPos * width + horizontalPos) * 4;
|
|
565
|
-
if (!getPixelInfo(pixel1, data1, offset, 1) ||
|
|
566
|
-
!getPixelInfo(pixel2, data2, offset, 2)) {
|
|
567
|
-
return;
|
|
568
|
-
}
|
|
569
|
-
const isWithinComparedArea = withinComparedArea(horizontalPos, verticalPos, width, height, pixel2);
|
|
570
|
-
if (ignoreColors) {
|
|
571
|
-
addBrightnessInfo(pixel1);
|
|
572
|
-
addBrightnessInfo(pixel2);
|
|
573
|
-
if (isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinComparedArea) {
|
|
574
|
-
if (!compareOnly) {
|
|
575
|
-
copyGrayScalePixel(pix, offset, pixel2);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
else {
|
|
579
|
-
if (!compareOnly) {
|
|
580
|
-
errorPixel(pix, offset, pixel1, pixel2);
|
|
581
|
-
}
|
|
582
|
-
mismatchCount++;
|
|
583
|
-
updateBounds(horizontalPos, verticalPos);
|
|
584
|
-
}
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
if (isRGBSimilar(pixel1, pixel2) || !isWithinComparedArea) {
|
|
588
|
-
if (!compareOnly) {
|
|
589
|
-
copyPixel(pix, offset, pixel1);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
else if (ignoreAntialiasing &&
|
|
593
|
-
(addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
|
|
594
|
-
addBrightnessInfo(pixel2),
|
|
595
|
-
isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
|
|
596
|
-
isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width))) {
|
|
597
|
-
if (isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinComparedArea) {
|
|
598
|
-
if (!compareOnly) {
|
|
599
|
-
copyGrayScalePixel(pix, offset, pixel2);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
if (!compareOnly) {
|
|
604
|
-
errorPixel(pix, offset, pixel1, pixel2);
|
|
605
|
-
}
|
|
606
|
-
mismatchCount++;
|
|
607
|
-
updateBounds(horizontalPos, verticalPos);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
else {
|
|
611
|
-
if (!compareOnly) {
|
|
612
|
-
errorPixel(pix, offset, pixel1, pixel2);
|
|
613
|
-
}
|
|
614
|
-
mismatchCount++;
|
|
615
|
-
updateBounds(horizontalPos, verticalPos);
|
|
616
|
-
}
|
|
617
|
-
if (compareOnly) {
|
|
618
|
-
const currentMisMatchPercent = (mismatchCount / (height * width)) * 100;
|
|
619
|
-
if (currentMisMatchPercent > returnEarlyThreshold) {
|
|
620
|
-
skipTheRest = true;
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
});
|
|
624
|
-
data.rawMisMatchPercentage = (mismatchCount / (height * width)) * 100;
|
|
625
|
-
data.misMatchPercentage = data.rawMisMatchPercentage.toFixed(2);
|
|
626
|
-
data.diffBounds = diffBounds;
|
|
627
|
-
data.analysisTime = Date.now() - time;
|
|
628
|
-
// Add diffPixels array to the data object
|
|
629
|
-
data.diffPixels = diffPixels;
|
|
630
|
-
data.getImageDataUrl = function (text) {
|
|
631
|
-
if (compareOnly) {
|
|
632
|
-
throw Error('No diff image available - ran in compareOnly mode');
|
|
633
|
-
}
|
|
634
|
-
let barHeight = 0;
|
|
635
|
-
if (text) {
|
|
636
|
-
barHeight = addLabel(text, hiddenCanvas);
|
|
637
|
-
}
|
|
638
|
-
// context.putImageData(imgd, 0, barHeight);
|
|
639
|
-
return hiddenCanvas.getBase64(JimpMime.png);
|
|
640
|
-
};
|
|
641
|
-
if (!compareOnly) {
|
|
642
|
-
data.getBuffer = function (includeOriginal) {
|
|
643
|
-
if (includeOriginal) {
|
|
644
|
-
const imageWidth = hiddenCanvas.bitmap.width + 2;
|
|
645
|
-
hiddenCanvas.resize(imageWidth * 3, hiddenCanvas.bitmap.height);
|
|
646
|
-
hiddenCanvas.composite(img1, 0, 0);
|
|
647
|
-
hiddenCanvas.composite(img2, imageWidth, 0);
|
|
648
|
-
hiddenCanvas.composite(hiddenCanvas, imageWidth * 2, 0);
|
|
649
|
-
}
|
|
650
|
-
return hiddenCanvas.getBuffer(JimpMime.png);
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
function addLabel(text, hiddenCanvas) {
|
|
655
|
-
const textPadding = 2;
|
|
656
|
-
// context.font = "12px sans-serif";
|
|
657
|
-
// var textWidth = context.measureText(text).width + textPadding * 2;
|
|
658
|
-
// var barHeight = 22;
|
|
659
|
-
// if (textWidth > hiddenCanvas.width) {
|
|
660
|
-
// hiddenCanvas.width = textWidth;
|
|
661
|
-
// }
|
|
662
|
-
// hiddenCanvas.height += barHeight;
|
|
663
|
-
// context.fillStyle = "#666";
|
|
664
|
-
// context.fillRect(0, 0, hiddenCanvas.width, barHeight - 4);
|
|
665
|
-
// context.fillStyle = "#fff";
|
|
666
|
-
// context.fillRect(0, barHeight - 4, hiddenCanvas.width, 4);
|
|
667
|
-
// context.fillStyle = "#fff";
|
|
668
|
-
// context.textBaseline = "top";
|
|
669
|
-
// context.font = "12px sans-serif";
|
|
670
|
-
// context.fillText(text, textPadding, 1);
|
|
671
|
-
// return barHeight;
|
|
672
|
-
return Jimp.loadFont(Jimp.FONT_SANS_12_WHITE).then((font) => {
|
|
673
|
-
const textWidth = Jimp.measureText(font, text) + textPadding * 2;
|
|
674
|
-
const barHeight = 22;
|
|
675
|
-
if (textWidth > hiddenCanvas.bitmap.width) {
|
|
676
|
-
hiddenCanvas.resize(textWidth, hiddenCanvas.bitmap.height);
|
|
677
|
-
}
|
|
678
|
-
const context = hiddenCanvas.clone();
|
|
679
|
-
context.print(font, textPadding, 1, text);
|
|
680
|
-
return barHeight;
|
|
681
|
-
});
|
|
682
|
-
}
|
|
683
|
-
function normalise(img, w, h) {
|
|
684
|
-
// var c;
|
|
685
|
-
// var context;
|
|
686
|
-
if (img.bitmap.height < h || img.bitmap.width < w) {
|
|
687
|
-
// c = createCanvas(w, h);
|
|
688
|
-
// context = c.getContext("2d");
|
|
689
|
-
// context.putImageData(img, 0, 0);
|
|
690
|
-
return img.contain({ w, h });
|
|
691
|
-
}
|
|
692
|
-
return img;
|
|
693
|
-
}
|
|
694
|
-
function outputSettings(options) {
|
|
695
|
-
let key;
|
|
696
|
-
if (options.errorColor) {
|
|
697
|
-
for (key in options.errorColor) {
|
|
698
|
-
if (options.errorColor.hasOwnProperty(key)) {
|
|
699
|
-
errorPixelColor[key] = options.errorColor[key] === void 0
|
|
700
|
-
? errorPixelColor[key]
|
|
701
|
-
: options.errorColor[key];
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
if (options.errorType && errorPixelTransform[options.errorType]) {
|
|
706
|
-
errorPixel = errorPixelTransform[options.errorType];
|
|
707
|
-
errorType = options.errorType;
|
|
708
|
-
}
|
|
709
|
-
if (options.errorPixel && typeof options.errorPixel === 'function') {
|
|
710
|
-
errorPixel = options.errorPixel;
|
|
711
|
-
}
|
|
712
|
-
pixelTransparency = isNaN(Number(options.transparency))
|
|
713
|
-
? pixelTransparency
|
|
714
|
-
: options.transparency;
|
|
715
|
-
if (options.largeImageThreshold !== undefined) {
|
|
716
|
-
largeImageThreshold = options.largeImageThreshold;
|
|
717
|
-
}
|
|
718
|
-
if (options.useCrossOrigin !== undefined) {
|
|
719
|
-
useCrossOrigin = options.useCrossOrigin;
|
|
720
|
-
}
|
|
721
|
-
if (options.boundingBox !== undefined) {
|
|
722
|
-
boundingBoxes = [options.boundingBox];
|
|
723
|
-
}
|
|
724
|
-
if (options.ignoredBox !== undefined) {
|
|
725
|
-
ignoredBoxes = [options.ignoredBox];
|
|
726
|
-
}
|
|
727
|
-
if (options.boundingBoxes !== undefined) {
|
|
728
|
-
boundingBoxes = options.boundingBoxes;
|
|
729
|
-
}
|
|
730
|
-
if (options.ignoredBoxes !== undefined) {
|
|
731
|
-
ignoredBoxes = options.ignoredBoxes;
|
|
732
|
-
}
|
|
733
|
-
if (options.ignoreAreasColoredWith !== undefined) {
|
|
734
|
-
ignoreAreasColoredWith = options.ignoreAreasColoredWith;
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
function compare(one, two) {
|
|
738
|
-
if (globalOutputSettings !== oldGlobalSettings) {
|
|
739
|
-
outputSettings(globalOutputSettings);
|
|
740
|
-
}
|
|
741
|
-
function onceWeHaveBoth() {
|
|
742
|
-
let width;
|
|
743
|
-
let height;
|
|
744
|
-
if (images.length === 2) {
|
|
745
|
-
if (images[0].error || images[1].error) {
|
|
746
|
-
data = {};
|
|
747
|
-
data.error = images[0].error ? images[0].error : images[1].error;
|
|
748
|
-
triggerDataUpdate();
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
width = images[0].bitmap.width > images[1].bitmap.width
|
|
752
|
-
? images[0].bitmap.width
|
|
753
|
-
: images[1].bitmap.width;
|
|
754
|
-
height = images[0].bitmap.height > images[1].bitmap.height
|
|
755
|
-
? images[0].bitmap.height
|
|
756
|
-
: images[1].bitmap.height;
|
|
757
|
-
data.isSameDimensions = images[0].bitmap.width === images[1].bitmap.width &&
|
|
758
|
-
images[0].bitmap.height === images[1].bitmap.height ? true : false;
|
|
759
|
-
data.dimensionDifference = {
|
|
760
|
-
width: images[0].bitmap.width - images[1].bitmap.width,
|
|
761
|
-
height: images[0].bitmap.height - images[1].bitmap.height,
|
|
762
|
-
};
|
|
763
|
-
analyseImages(normalise(images[0], width, height), normalise(images[1], width, height), width, height);
|
|
764
|
-
triggerDataUpdate();
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
images = [];
|
|
768
|
-
loadImageData(one, onceWeHaveBoth);
|
|
769
|
-
loadImageData(two, onceWeHaveBoth);
|
|
770
|
-
}
|
|
771
|
-
function getCompareApi(param) {
|
|
772
|
-
let secondFileData;
|
|
773
|
-
const hasMethod = typeof param === 'function';
|
|
774
|
-
if (!hasMethod) {
|
|
775
|
-
// assume it's file data
|
|
776
|
-
secondFileData = param;
|
|
777
|
-
}
|
|
778
|
-
var self = {
|
|
779
|
-
setReturnEarlyThreshold: function (threshold) {
|
|
780
|
-
if (threshold) {
|
|
781
|
-
compareOnly = true;
|
|
782
|
-
returnEarlyThreshold = threshold;
|
|
783
|
-
}
|
|
784
|
-
return self;
|
|
785
|
-
},
|
|
786
|
-
scaleToSameSize: function () {
|
|
787
|
-
scaleToSameSize = true;
|
|
788
|
-
if (hasMethod) {
|
|
789
|
-
param();
|
|
790
|
-
}
|
|
791
|
-
return self;
|
|
792
|
-
},
|
|
793
|
-
useOriginalSize: function () {
|
|
794
|
-
scaleToSameSize = false;
|
|
795
|
-
if (hasMethod) {
|
|
796
|
-
param();
|
|
797
|
-
}
|
|
798
|
-
return self;
|
|
799
|
-
},
|
|
800
|
-
ignoreNothing: function () {
|
|
801
|
-
tolerance.red = 0;
|
|
802
|
-
tolerance.green = 0;
|
|
803
|
-
tolerance.blue = 0;
|
|
804
|
-
tolerance.alpha = 0;
|
|
805
|
-
tolerance.minBrightness = 0;
|
|
806
|
-
tolerance.maxBrightness = 255;
|
|
807
|
-
ignoreAntialiasing = false;
|
|
808
|
-
ignoreColors = false;
|
|
809
|
-
if (hasMethod) {
|
|
810
|
-
param();
|
|
811
|
-
}
|
|
812
|
-
return self;
|
|
813
|
-
},
|
|
814
|
-
ignoreLess: function () {
|
|
815
|
-
tolerance.red = 16;
|
|
816
|
-
tolerance.green = 16;
|
|
817
|
-
tolerance.blue = 16;
|
|
818
|
-
tolerance.alpha = 16;
|
|
819
|
-
tolerance.minBrightness = 16;
|
|
820
|
-
tolerance.maxBrightness = 240;
|
|
821
|
-
ignoreAntialiasing = false;
|
|
822
|
-
ignoreColors = false;
|
|
823
|
-
if (hasMethod) {
|
|
824
|
-
param();
|
|
825
|
-
}
|
|
826
|
-
return self;
|
|
827
|
-
},
|
|
828
|
-
ignoreAntialiasing: function () {
|
|
829
|
-
tolerance.red = 32;
|
|
830
|
-
tolerance.green = 32;
|
|
831
|
-
tolerance.blue = 32;
|
|
832
|
-
tolerance.alpha = 32;
|
|
833
|
-
tolerance.minBrightness = 64;
|
|
834
|
-
tolerance.maxBrightness = 96;
|
|
835
|
-
ignoreAntialiasing = true;
|
|
836
|
-
ignoreColors = false;
|
|
837
|
-
if (hasMethod) {
|
|
838
|
-
param();
|
|
839
|
-
}
|
|
840
|
-
return self;
|
|
841
|
-
},
|
|
842
|
-
ignoreColors: function () {
|
|
843
|
-
tolerance.alpha = 16;
|
|
844
|
-
tolerance.minBrightness = 16;
|
|
845
|
-
tolerance.maxBrightness = 240;
|
|
846
|
-
ignoreAntialiasing = false;
|
|
847
|
-
ignoreColors = true;
|
|
848
|
-
if (hasMethod) {
|
|
849
|
-
param();
|
|
850
|
-
}
|
|
851
|
-
return self;
|
|
852
|
-
},
|
|
853
|
-
ignoreAlpha: function () {
|
|
854
|
-
tolerance.red = 16;
|
|
855
|
-
tolerance.green = 16;
|
|
856
|
-
tolerance.blue = 16;
|
|
857
|
-
tolerance.alpha = 255;
|
|
858
|
-
tolerance.minBrightness = 16;
|
|
859
|
-
tolerance.maxBrightness = 240;
|
|
860
|
-
ignoreAntialiasing = false;
|
|
861
|
-
ignoreColors = false;
|
|
862
|
-
if (hasMethod) {
|
|
863
|
-
param();
|
|
864
|
-
}
|
|
865
|
-
return self;
|
|
866
|
-
},
|
|
867
|
-
repaint: function () {
|
|
868
|
-
if (hasMethod) {
|
|
869
|
-
param();
|
|
870
|
-
}
|
|
871
|
-
return self;
|
|
872
|
-
},
|
|
873
|
-
outputSettings: function (options) {
|
|
874
|
-
outputSettings(options);
|
|
875
|
-
return self;
|
|
876
|
-
},
|
|
877
|
-
onComplete: function (callback) {
|
|
878
|
-
updateCallbackArray.push(callback);
|
|
879
|
-
const wrapper = function () {
|
|
880
|
-
compare(fileData, secondFileData);
|
|
881
|
-
};
|
|
882
|
-
wrapper();
|
|
883
|
-
return getCompareApi(wrapper);
|
|
884
|
-
},
|
|
885
|
-
setupCustomTolerance: function (customSettings) {
|
|
886
|
-
for (const property in tolerance) {
|
|
887
|
-
if (!customSettings.hasOwnProperty(property)) {
|
|
888
|
-
continue;
|
|
889
|
-
}
|
|
890
|
-
tolerance[property] = customSettings[property];
|
|
891
|
-
}
|
|
892
|
-
},
|
|
893
|
-
};
|
|
894
|
-
return self;
|
|
895
|
-
}
|
|
896
|
-
var rootSelf = {
|
|
897
|
-
onComplete: function (callback) {
|
|
898
|
-
updateCallbackArray.push(callback);
|
|
899
|
-
loadImageData(fileData, function (imageData, width, height) {
|
|
900
|
-
parseImage(imageData, width, height);
|
|
901
|
-
});
|
|
902
|
-
},
|
|
903
|
-
compareTo: function (secondFileData) {
|
|
904
|
-
return getCompareApi(secondFileData);
|
|
905
|
-
},
|
|
906
|
-
outputSettings: function (options) {
|
|
907
|
-
outputSettings(options);
|
|
908
|
-
return rootSelf;
|
|
909
|
-
},
|
|
910
|
-
};
|
|
911
|
-
return rootSelf;
|
|
912
|
-
};
|
|
913
|
-
function setGlobalOutputSettings(settings) {
|
|
914
|
-
globalOutputSettings = settings;
|
|
915
|
-
return resemble;
|
|
916
|
-
}
|
|
917
|
-
function applyIgnore(api, ignore, customTolerance) {
|
|
918
|
-
switch (ignore) {
|
|
919
|
-
case 'nothing':
|
|
920
|
-
api.ignoreNothing();
|
|
921
|
-
break;
|
|
922
|
-
case 'less':
|
|
923
|
-
api.ignoreLess();
|
|
924
|
-
break;
|
|
925
|
-
case 'antialiasing':
|
|
926
|
-
api.ignoreAntialiasing();
|
|
927
|
-
break;
|
|
928
|
-
case 'colors':
|
|
929
|
-
api.ignoreColors();
|
|
930
|
-
break;
|
|
931
|
-
case 'alpha':
|
|
932
|
-
api.ignoreAlpha();
|
|
933
|
-
break;
|
|
934
|
-
default:
|
|
935
|
-
throw new Error('Invalid ignore: ' + ignore);
|
|
936
|
-
}
|
|
937
|
-
api.setupCustomTolerance(customTolerance);
|
|
938
|
-
}
|
|
939
|
-
resemble.compare = function (image1, image2, options) {
|
|
940
|
-
return new Promise((resolve, reject) => {
|
|
941
|
-
let opt;
|
|
942
|
-
if (typeof options !== 'object') {
|
|
943
|
-
opt = {};
|
|
944
|
-
}
|
|
945
|
-
else {
|
|
946
|
-
opt = options;
|
|
947
|
-
}
|
|
948
|
-
const res = resemble(image1);
|
|
949
|
-
let compare;
|
|
950
|
-
if (opt.output) {
|
|
951
|
-
res.outputSettings(opt.output);
|
|
952
|
-
}
|
|
953
|
-
compare = res.compareTo(image2);
|
|
954
|
-
if (opt.returnEarlyThreshold) {
|
|
955
|
-
compare.setReturnEarlyThreshold(opt.returnEarlyThreshold);
|
|
956
|
-
}
|
|
957
|
-
if (opt.scaleToSameSize) {
|
|
958
|
-
compare.scaleToSameSize();
|
|
959
|
-
}
|
|
960
|
-
const toleranceSettings = opt.tolerance || {};
|
|
961
|
-
if (typeof opt.ignore === 'string') {
|
|
962
|
-
applyIgnore(compare, opt.ignore, toleranceSettings);
|
|
963
|
-
}
|
|
964
|
-
else if (opt.ignore && opt.ignore.forEach) {
|
|
965
|
-
opt.ignore.forEach(function (v) {
|
|
966
|
-
applyIgnore(compare, v, toleranceSettings);
|
|
967
|
-
});
|
|
968
|
-
}
|
|
969
|
-
compare.onComplete(function (data) {
|
|
970
|
-
if (data.error) {
|
|
971
|
-
reject(data.error);
|
|
972
|
-
}
|
|
973
|
-
else {
|
|
974
|
-
resolve(data);
|
|
975
|
-
}
|
|
976
|
-
});
|
|
977
|
-
});
|
|
978
|
-
};
|
|
979
|
-
resemble.outputSettings = setGlobalOutputSettings;
|
|
980
|
-
return resemble;
|
|
981
|
-
});
|