@syngrisi/node-resemble.js 2.1.33-alpha.0 → 2.1.36-alpha.0

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/resemble.js +584 -565
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syngrisi/node-resemble.js",
3
- "version": "2.1.33-alpha.0",
3
+ "version": "2.1.36-alpha.0",
4
4
  "description": "Image analysis and comparison for nodejs",
5
5
  "main": "resemble.js",
6
6
  "scripts": {
@@ -39,5 +39,5 @@
39
39
  "gulp-jasmine": "4.0.0",
40
40
  "gulp-util": "3.0.7"
41
41
  },
42
- "gitHead": "9798c5c0f4b9859fbf48c738b3c9a13aac9b117a"
42
+ "gitHead": "df73b8517e1c68872f05a655e315524d6eb34eb7"
43
43
  }
package/resemble.js CHANGED
@@ -12,608 +12,627 @@ var sharp = require('sharp');
12
12
  //keeping wrong indentation and '_this' for better diff with origin resemble.js
13
13
  var _this = {};
14
14
 
15
- var pixelTransparency = 1;
16
-
17
- var errorPixelColor = { // Color for Error Pixels. Between 0 and 255.
18
- red: 255,
19
- green: 0,
20
- blue: 255,
21
- alpha: 255
22
- };
23
-
24
- var errorPixelTransform = {
25
- flat : function (d1, d2){
26
- return {
27
- r: errorPixelColor.red,
28
- g: errorPixelColor.green,
29
- b: errorPixelColor.blue,
30
- a: errorPixelColor.alpha
31
- }
32
- },
33
- movement: function (d1, d2){
34
- return {
35
- r: ((d2.r*(errorPixelColor.red/255)) + errorPixelColor.red)/2,
36
- g: ((d2.g*(errorPixelColor.green/255)) + errorPixelColor.green)/2,
37
- b: ((d2.b*(errorPixelColor.blue/255)) + errorPixelColor.blue)/2,
38
- a: d2.a
39
- }
40
- }
41
- };
42
-
43
- var errorPixelTransformer = errorPixelTransform.flat;
44
- var largeImageThreshold = 1200;
45
-
46
- _this['resemble'] = function( fileData ){
47
-
48
- var data = {};
49
- var images = [];
50
- var updateCallbackArray = [];
51
-
52
- var tolerance = { // between 0 and 255
53
- red: 16,
54
- green: 16,
55
- blue: 16,
56
- alpha: 16,
57
- minBrightness: 16,
58
- maxBrightness: 240
59
- };
60
-
61
- var ignoreAntialiasing = false;
62
- var ignoreColors = false;
15
+ var pixelTransparency = 1;
16
+
17
+ var errorPixelColor = { // Color for Error Pixels. Between 0 and 255.
18
+ red: 255,
19
+ green: 0,
20
+ blue: 255,
21
+ alpha: 255
22
+ };
23
+
24
+ var errorPixelTransform = {
25
+ flat: function (d1, d2) {
26
+ return {
27
+ r: errorPixelColor.red,
28
+ g: errorPixelColor.green,
29
+ b: errorPixelColor.blue,
30
+ a: errorPixelColor.alpha
31
+ };
32
+ },
33
+ movement: function (d1, d2) {
34
+ return {
35
+ r: ((d2.r * (errorPixelColor.red / 255)) + errorPixelColor.red) / 2,
36
+ g: ((d2.g * (errorPixelColor.green / 255)) + errorPixelColor.green) / 2,
37
+ b: ((d2.b * (errorPixelColor.blue / 255)) + errorPixelColor.blue) / 2,
38
+ a: d2.a
39
+ };
40
+ }
41
+ };
42
+
43
+ var errorPixelTransformer = errorPixelTransform.flat;
44
+ var largeImageThreshold = 1200;
45
+
46
+ _this['resemble'] = function (fileData) {
47
+
48
+ var data = {};
49
+ var images = [];
50
+ var updateCallbackArray = [];
51
+
52
+ var tolerance = { // between 0 and 255
53
+ red: 16,
54
+ green: 16,
55
+ blue: 16,
56
+ alpha: 16,
57
+ minBrightness: 16,
58
+ maxBrightness: 240
59
+ };
60
+
61
+ var ignoreAntialiasing = false;
62
+ var ignoreColors = false;
63
63
  var ignoreRectangles = null;
64
64
  var includeRectangles = null;
65
65
 
66
- function triggerDataUpdate(){
67
- var len = updateCallbackArray.length;
68
- var i;
69
- for(i=0;i<len;i++){
70
- if (typeof updateCallbackArray[i] === 'function'){
71
- updateCallbackArray[i](data);
72
- }
73
- }
74
- }
75
-
76
- function loop(x, y, callback){
77
- var i,j;
78
-
79
- for (i=0;i<x;i++){
80
- for (j=0;j<y;j++){
81
- callback(i, j);
82
- }
83
- }
84
- }
85
-
86
- function parseImage(sourceImageData, width, height){
87
-
88
- var pixleCount = 0;
89
- var redTotal = 0;
90
- var greenTotal = 0;
91
- var blueTotal = 0;
92
- var brightnessTotal = 0;
93
-
94
- loop(height, width, function(verticalPos, horizontalPos){
95
- var offset = (verticalPos*width + horizontalPos) * 4;
96
- var red = sourceImageData[offset];
97
- var green = sourceImageData[offset + 1];
98
- var blue = sourceImageData[offset + 2];
99
- var brightness = getBrightness(red,green,blue);
100
-
101
- pixleCount++;
102
-
103
- redTotal += red / 255 * 100;
104
- greenTotal += green / 255 * 100;
105
- blueTotal += blue / 255 * 100;
106
- brightnessTotal += brightness / 255 * 100;
107
- });
108
-
109
- data.red = Math.floor(redTotal / pixleCount);
110
- data.green = Math.floor(greenTotal / pixleCount);
111
- data.blue = Math.floor(blueTotal / pixleCount);
112
- data.brightness = Math.floor(brightnessTotal / pixleCount);
113
-
114
- triggerDataUpdate();
115
- }
116
-
117
- function loadImageData( fileData, callback ){
118
- sharp(fileData)
119
- .png()
120
- .toBuffer()
121
- .then(pngData => {
122
- var png = new PNG();
123
- png.parse(pngData, function (err, data) {
124
- callback(data, data.width, data.height);
125
- });
126
- })
127
- }
128
-
129
- function isColorSimilar(a, b, color){
130
-
131
- var absDiff = Math.abs(a - b);
132
-
133
- if(typeof a === 'undefined'){
134
- return false;
135
- }
136
- if(typeof b === 'undefined'){
137
- return false;
138
- }
139
-
140
- if(a === b){
141
- return true;
142
- } else if ( absDiff < tolerance[color] ) {
143
- return true;
144
- } else {
145
- return false;
146
- }
147
- }
66
+ function triggerDataUpdate() {
67
+ var len = updateCallbackArray.length;
68
+ var i;
69
+ for (i = 0; i < len; i++) {
70
+ if (typeof updateCallbackArray[i] === 'function') {
71
+ updateCallbackArray[i](data);
72
+ }
73
+ }
74
+ }
148
75
 
149
- function isWithinRectangle(x, y, rectangle) {
150
- return (x >= rectangle[1]) &&
151
- (x < rectangle[1] + rectangle[3]) &&
152
- (y >= rectangle[0]) &&
153
- (y < rectangle[0] + rectangle[2])
76
+ function loop(x, y, callback) {
77
+ var i,
78
+ j;
79
+
80
+ for (i = 0; i < x; i++) {
81
+ for (j = 0; j < y; j++) {
82
+ callback(i, j);
83
+ }
84
+ }
154
85
  }
155
86
 
156
- function isNumber(n) {
157
- return !isNaN(parseFloat(n));
158
- }
159
-
160
- function isPixelBrightnessSimilar(d1, d2){
161
- var alpha = isColorSimilar(d1.a, d2.a, 'alpha');
162
- var brightness = isColorSimilar(d1.brightness, d2.brightness, 'minBrightness');
163
- return brightness && alpha;
164
- }
165
-
166
- function getBrightness(r,g,b){
167
- return 0.3*r + 0.59*g + 0.11*b;
168
- }
169
-
170
- function isRGBSame(d1,d2){
171
- var red = d1.r === d2.r;
172
- var green = d1.g === d2.g;
173
- var blue = d1.b === d2.b;
174
- return red && green && blue;
175
- }
176
-
177
- function isRGBSimilar(d1, d2){
178
- var red = isColorSimilar(d1.r,d2.r,'red');
179
- var green = isColorSimilar(d1.g,d2.g,'green');
180
- var blue = isColorSimilar(d1.b,d2.b,'blue');
181
- var alpha = isColorSimilar(d1.a, d2.a, 'alpha');
182
-
183
- return red && green && blue && alpha;
184
- }
185
-
186
- function isContrasting(d1, d2){
187
- return Math.abs(d1.brightness - d2.brightness) > tolerance.maxBrightness;
188
- }
189
-
190
- function getHue(r,g,b){
191
-
192
- r = r / 255;
193
- g = g / 255;
194
- b = b / 255;
195
- var max = Math.max(r, g, b), min = Math.min(r, g, b);
196
- var h;
197
- var d;
198
-
199
- if (max == min){
200
- h = 0; // achromatic
201
- } else{
202
- d = max - min;
203
- switch(max){
204
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
205
- case g: h = (b - r) / d + 2; break;
206
- case b: h = (r - g) / d + 4; break;
207
- }
208
- h /= 6;
209
- }
210
-
211
- return h;
212
- }
213
-
214
- function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
215
- var offset;
216
- var targetPix;
217
- var distance = 1;
218
- var i;
219
- var j;
220
- var hasHighContrastSibling = 0;
221
- var hasSiblingWithDifferentHue = 0;
222
- var hasEquivilantSibling = 0;
223
-
224
- addHueInfo(sourcePix);
225
-
226
- for (i = distance*-1; i <= distance; i++){
227
- for (j = distance*-1; j <= distance; j++){
228
-
229
- if(i===0 && j===0){
230
- // ignore source pixel
231
- } else {
232
-
233
- offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
234
- targetPix = getPixelInfo(data, offset, cacheSet);
235
-
236
- if(targetPix === null){
237
- continue;
238
- }
239
-
240
- addBrightnessInfo(targetPix);
241
- addHueInfo(targetPix);
242
-
243
- if( isContrasting(sourcePix, targetPix) ){
244
- hasHighContrastSibling++;
245
- }
246
-
247
- if( isRGBSame(sourcePix,targetPix) ){
248
- hasEquivilantSibling++;
249
- }
250
-
251
- if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
252
- hasSiblingWithDifferentHue++;
253
- }
254
-
255
- if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
256
- return true;
257
- }
258
- }
259
- }
260
- }
261
-
262
- if(hasEquivilantSibling < 2){
263
- return true;
264
- }
265
-
266
- return false;
267
- }
268
-
269
- function errorPixel(px, offset, data1, data2){
270
- var data = errorPixelTransformer(data1, data2);
271
- px[offset] = data.r;
272
- px[offset + 1] = data.g;
273
- px[offset + 2] = data.b;
274
- px[offset + 3] = data.a;
275
- }
276
-
277
- function copyPixel(px, offset, data){
278
- px[offset] = data.r; //r
279
- px[offset + 1] = data.g; //g
280
- px[offset + 2] = data.b; //b
281
- px[offset + 3] = data.a * pixelTransparency; //a
282
- }
283
-
284
- function copyGrayScalePixel(px, offset, data){
285
- px[offset] = data.brightness; //r
286
- px[offset + 1] = data.brightness; //g
287
- px[offset + 2] = data.brightness; //b
288
- px[offset + 3] = data.a * pixelTransparency; //a
289
- }
290
-
291
- function getPixelInfo(data, offset, cacheSet){
292
- var r;
293
- var g;
294
- var b;
295
- var d;
296
- var a;
297
-
298
- r = data[offset];
299
-
300
- if(typeof r !== 'undefined'){
301
- g = data[offset+1];
302
- b = data[offset+2];
303
- a = data[offset+3];
304
- d = {
305
- r: r,
306
- g: g,
307
- b: b,
308
- a: a
309
- };
310
-
311
- return d;
312
- } else {
313
- return null;
314
- }
315
- }
316
-
317
- function addBrightnessInfo(data){
318
- data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
319
- }
320
-
321
- function addHueInfo(data){
322
- data.h = getHue(data.r,data.g,data.b);
323
- }
324
-
325
- function analyseImages(img1, img2, width, height){
326
-
327
- var data1 = img1.data;
328
- var data2 = img2.data;
329
-
330
- //TODO
331
- var imgd = new PNG({
332
- width: img1.width,
333
- height: img1.height,
334
- deflateChunkSize: img1.deflateChunkSize,
335
- deflateLevel: img1.deflateLevel,
336
- deflateStrategy: img1.deflateStrategy,
87
+ function parseImage(sourceImageData, width, height) {
88
+
89
+ var pixleCount = 0;
90
+ var redTotal = 0;
91
+ var greenTotal = 0;
92
+ var blueTotal = 0;
93
+ var brightnessTotal = 0;
94
+
95
+ loop(height, width, function (verticalPos, horizontalPos) {
96
+ var offset = (verticalPos * width + horizontalPos) * 4;
97
+ var red = sourceImageData[offset];
98
+ var green = sourceImageData[offset + 1];
99
+ var blue = sourceImageData[offset + 2];
100
+ var brightness = getBrightness(red, green, blue);
101
+
102
+ pixleCount++;
103
+
104
+ redTotal += red / 255 * 100;
105
+ greenTotal += green / 255 * 100;
106
+ blueTotal += blue / 255 * 100;
107
+ brightnessTotal += brightness / 255 * 100;
337
108
  });
338
- var targetPix = imgd.data;
339
109
 
340
- var mismatchCount = 0;
110
+ data.red = Math.floor(redTotal / pixleCount);
111
+ data.green = Math.floor(greenTotal / pixleCount);
112
+ data.blue = Math.floor(blueTotal / pixleCount);
113
+ data.brightness = Math.floor(brightnessTotal / pixleCount);
341
114
 
342
- var time = Date.now();
115
+ triggerDataUpdate();
116
+ }
343
117
 
344
- var skip;
118
+ function loadImageData(fileData, callback) {
119
+ sharp(fileData)
120
+ .png()
121
+ .toBuffer()
122
+ .then(pngData => {
123
+ var png = new PNG();
124
+ png.parse(pngData, function (err, data) {
125
+ callback(data, data.width, data.height);
126
+ });
127
+ });
128
+ }
345
129
 
346
- var currentRectangle = null;
347
- var rectagnlesIdx = 0;
130
+ function isColorSimilar(a, b, color) {
348
131
 
349
- if(!!largeImageThreshold && ignoreAntialiasing && (width > largeImageThreshold || height > largeImageThreshold)){
350
- skip = 6;
351
- }
132
+ var absDiff = Math.abs(a - b);
352
133
 
353
- loop(height, width, function(verticalPos, horizontalPos){
134
+ if (typeof a === 'undefined') {
135
+ return false;
136
+ }
137
+ if (typeof b === 'undefined') {
138
+ return false;
139
+ }
354
140
 
355
- var offset = (verticalPos*width + horizontalPos) * 4;
141
+ if (a === b) {
142
+ return true;
143
+ } else if (absDiff < tolerance[color]) {
144
+ return true;
145
+ } else {
146
+ return false;
147
+ }
148
+ }
356
149
 
357
- if(skip){ // only skip if the image isn't small
358
- if(verticalPos % skip === 0 || horizontalPos % skip === 0){
150
+ function isWithinRectangle(x, y, rectangle) {
151
+ return (x >= rectangle[1]) &&
152
+ (x < rectangle[1] + rectangle[3]) &&
153
+ (y >= rectangle[0]) &&
154
+ (y < rectangle[0] + rectangle[2]);
155
+ }
359
156
 
360
- copyPixel(targetPix, offset, {
361
- r: 0,
362
- b: 0,
363
- g: 0,
364
- a: 0
365
- });
157
+ function isNumber(n) {
158
+ return !isNaN(parseFloat(n));
159
+ }
366
160
 
367
- return;
368
- }
369
- }
161
+ function isPixelBrightnessSimilar(d1, d2) {
162
+ var alpha = isColorSimilar(d1.a, d2.a, 'alpha');
163
+ var brightness = isColorSimilar(d1.brightness, d2.brightness, 'minBrightness');
164
+ return brightness && alpha;
165
+ }
370
166
 
371
- var pixel1 = getPixelInfo(data1, offset, 1);
372
- var pixel2 = getPixelInfo(data2, offset, 2);
167
+ function getBrightness(r, g, b) {
168
+ return 0.3 * r + 0.59 * g + 0.11 * b;
169
+ }
170
+
171
+ function isRGBSame(d1, d2) {
172
+ var red = d1.r === d2.r;
173
+ var green = d1.g === d2.g;
174
+ var blue = d1.b === d2.b;
175
+ return red && green && blue;
176
+ }
373
177
 
374
- if(pixel1 === null || pixel2 === null){
375
- return;
376
- }
178
+ function isRGBSimilar(d1, d2) {
179
+ var red = isColorSimilar(d1.r, d2.r, 'red');
180
+ var green = isColorSimilar(d1.g, d2.g, 'green');
181
+ var blue = isColorSimilar(d1.b, d2.b, 'blue');
182
+ var alpha = isColorSimilar(d1.a, d2.a, 'alpha');
377
183
 
378
- if (ignoreRectangles) {
379
- for(rectagnlesIdx = 0; rectagnlesIdx < ignoreRectangles.length; rectagnlesIdx++) {
380
- currentRectangle = ignoreRectangles[rectagnlesIdx];
381
- //console.log(currentRectangle, verticalPos, horizontalPos);
382
- if (isWithinRectangle(verticalPos, horizontalPos, currentRectangle)) {
383
- copyGrayScalePixel(targetPix, offset, pixel2);
384
- //copyPixel(targetPix, offset, pixel1, pixel2);
385
- return;
184
+ return red && green && blue && alpha;
185
+ }
186
+
187
+ function isContrasting(d1, d2) {
188
+ return Math.abs(d1.brightness - d2.brightness) > tolerance.maxBrightness;
189
+ }
190
+
191
+ function getHue(r, g, b) {
192
+
193
+ r = r / 255;
194
+ g = g / 255;
195
+ b = b / 255;
196
+ var max = Math.max(r, g, b),
197
+ min = Math.min(r, g, b);
198
+ var h;
199
+ var d;
200
+
201
+ if (max == min) {
202
+ h = 0; // achromatic
203
+ } else {
204
+ d = max - min;
205
+ switch (max) {
206
+ case r:
207
+ h = (g - b) / d + (g < b ? 6 : 0);
208
+ break;
209
+ case g:
210
+ h = (b - r) / d + 2;
211
+ break;
212
+ case b:
213
+ h = (r - g) / d + 4;
214
+ break;
386
215
  }
387
- }
216
+ h /= 6;
388
217
  }
389
218
 
390
- if (includeRectangles) {
391
- var isWithinAnyRectangle = false;
392
- for(rectagnlesIdx = 0; rectagnlesIdx < includeRectangles.length; rectagnlesIdx++) {
393
- currentRectangle = includeRectangles[rectagnlesIdx];
394
- if (isWithinRectangle(verticalPos, horizontalPos, currentRectangle)) {
395
- isWithinAnyRectangle = true;
219
+ return h;
220
+ }
221
+
222
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width) {
223
+ var offset;
224
+ var targetPix;
225
+ var distance = 1;
226
+ var i;
227
+ var j;
228
+ var hasHighContrastSibling = 0;
229
+ var hasSiblingWithDifferentHue = 0;
230
+ var hasEquivilantSibling = 0;
231
+
232
+ addHueInfo(sourcePix);
233
+
234
+ for (i = distance * -1; i <= distance; i++) {
235
+ for (j = distance * -1; j <= distance; j++) {
236
+
237
+ if (i === 0 && j === 0) {
238
+ // ignore source pixel
239
+ } else {
240
+
241
+ offset = ((verticalPos + j) * width + (horizontalPos + i)) * 4;
242
+ targetPix = getPixelInfo(data, offset, cacheSet);
243
+
244
+ if (targetPix === null) {
245
+ continue;
246
+ }
247
+
248
+ addBrightnessInfo(targetPix);
249
+ addHueInfo(targetPix);
250
+
251
+ if (isContrasting(sourcePix, targetPix)) {
252
+ hasHighContrastSibling++;
253
+ }
254
+
255
+ if (isRGBSame(sourcePix, targetPix)) {
256
+ hasEquivilantSibling++;
257
+ }
258
+
259
+ if (Math.abs(targetPix.h - sourcePix.h) > 0.3) {
260
+ hasSiblingWithDifferentHue++;
261
+ }
262
+
263
+ if (hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1) {
264
+ return true;
265
+ }
266
+ }
396
267
  }
397
- }
398
- // Better solution but i'm not sure if you want to use reducers in your repo?
399
- // var isWithinAnyRectangle = includeRectangles.reduce(function (acc, currentRectangle) {
400
- // if(isWithinRectangle) {
401
- // return true;
402
- // }
403
- // return acc;
404
- // }, false);
405
- if(!isWithinAnyRectangle) {
406
- copyGrayScalePixel(targetPix, offset, pixel2);
407
- return;
408
- }
409
268
  }
410
269
 
411
- if (ignoreColors){
412
-
413
- addBrightnessInfo(pixel1);
414
- addBrightnessInfo(pixel2);
415
-
416
- if( isPixelBrightnessSimilar(pixel1, pixel2) ){
417
- copyGrayScalePixel(targetPix, offset, pixel2);
418
- } else {
419
- errorPixel(targetPix, offset, pixel1, pixel2);
420
- mismatchCount++;
421
- }
422
- return;
423
- }
424
-
425
- if( isRGBSimilar(pixel1, pixel2) ){
426
- copyPixel(targetPix, offset, pixel1);
427
-
428
- } else if( ignoreAntialiasing && (
429
- addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
430
- addBrightnessInfo(pixel2),
431
- isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
432
- isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
433
- )){
434
-
435
- if( isPixelBrightnessSimilar(pixel1, pixel2) ){
436
- copyGrayScalePixel(targetPix, offset, pixel2);
437
- } else {
438
- errorPixel(targetPix, offset, pixel1, pixel2);
439
- mismatchCount++;
440
- }
441
- } else {
442
- errorPixel(targetPix, offset, pixel1, pixel2);
443
- mismatchCount++;
444
- }
445
-
446
- });
447
-
448
- data.rawMisMatchPercentage = (mismatchCount / (height*width) * 100);
449
- data.misMatchPercentage = data.rawMisMatchPercentage.toFixed(2);
450
- data.analysisTime = Date.now() - time;
451
-
452
- data.getDiffImage = function(text){
453
- return imgd;
454
- };
455
-
456
- data.getDiffImageAsJPEG = function(quality) {
457
- return jpeg.encode({
458
- data: targetPix,
459
- width: img1.width,
460
- height: img1.height
461
- }, quality !== undefined ? quality : 50).data;
462
- };
463
- }
464
-
465
- function compare(one, two){
466
-
467
- function onceWeHaveBoth(img){
468
- var width;
469
- var height;
470
-
471
- images.push(img);
472
- if(images.length === 2){
473
- width = images[0].width > images[1].width ? images[0].width : images[1].width;
474
- height = images[0].height > images[1].height ? images[0].height : images[1].height;
475
-
476
- if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
477
- data.isSameDimensions = true;
478
- } else {
479
- data.isSameDimensions = false;
480
- }
481
-
482
- data.dimensionDifference = { width: images[0].width - images[1].width, height: images[0].height - images[1].height };
483
-
484
- //lksv: normalization removed
485
- analyseImages( images[0], images[1], width, height);
486
-
487
- triggerDataUpdate();
488
- }
489
- }
490
-
491
- images = [];
492
- loadImageData(one, onceWeHaveBoth);
493
- loadImageData(two, onceWeHaveBoth);
494
- }
495
-
496
- function getCompareApi(param){
497
-
498
- var secondFileData,
499
- hasMethod = typeof param === 'function';
500
-
501
- if( !hasMethod ){
502
- // assume it's file data
503
- secondFileData = param;
504
- }
505
-
506
- var self = {
507
- ignoreNothing: function(){
508
-
509
- tolerance.red = 16;
510
- tolerance.green = 16;
511
- tolerance.blue = 16;
512
- tolerance.alpha = 16;
513
- tolerance.minBrightness = 16;
514
- tolerance.maxBrightness = 240;
515
-
516
- ignoreAntialiasing = false;
517
- ignoreColors = false;
518
-
519
- if(hasMethod) { param(); }
520
- return self;
521
- },
522
- ignoreAntialiasing: function(){
523
-
524
- tolerance.red = 32;
525
- tolerance.green = 32;
526
- tolerance.blue = 32;
527
- tolerance.alpha = 32;
528
- tolerance.minBrightness = 64;
529
- tolerance.maxBrightness = 96;
530
-
531
- ignoreAntialiasing = true;
532
- ignoreColors = false;
533
-
534
- if(hasMethod) { param(); }
535
- return self;
536
- },
537
- ignoreColors: function(){
538
-
539
- tolerance.alpha = 16;
540
- tolerance.minBrightness = 16;
541
- tolerance.maxBrightness = 240;
542
-
543
- ignoreAntialiasing = false;
544
- ignoreColors = true;
545
-
546
- if(hasMethod) { param(); }
547
- return self;
548
- },
549
- //array of rectangles, each rectangle is defined as (x, y, width. height)
550
- //e.g. [[325, 170, 100, 40]]
551
- ignoreRectangles: function(rectangles) {
552
- ignoreRectangles = rectangles;
553
- return self;
554
- },
555
- //array of rectangles, each rectangle is defined as (x, y, width. height)
556
- //e.g. [[325, 170, 100, 40]]
557
- includeRectangles: function(rectangles) {
558
- includeRectangles = rectangles;
559
- return self;
560
- },
561
- repaint: function(){
562
- if(hasMethod) { param(); }
563
- return self;
564
- },
565
- onComplete: function( callback ){
270
+ if (hasEquivilantSibling < 2) {
271
+ return true;
272
+ }
566
273
 
567
- updateCallbackArray.push(callback);
274
+ return false;
275
+ }
276
+
277
+ function errorPixel(px, offset, data1, data2) {
278
+ var data = errorPixelTransformer(data1, data2);
279
+ px[offset] = data.r;
280
+ px[offset + 1] = data.g;
281
+ px[offset + 2] = data.b;
282
+ px[offset + 3] = data.a;
283
+ }
568
284
 
569
- var wrapper = function(){
570
- compare(fileData, secondFileData);
571
- };
285
+ function copyPixel(px, offset, data) {
286
+ px[offset] = data.r; //r
287
+ px[offset + 1] = data.g; //g
288
+ px[offset + 2] = data.b; //b
289
+ px[offset + 3] = data.a * pixelTransparency; //a
290
+ }
572
291
 
573
- wrapper();
292
+ function copyGrayScalePixel(px, offset, data) {
293
+ px[offset] = data.brightness; //r
294
+ px[offset + 1] = data.brightness; //g
295
+ px[offset + 2] = data.brightness; //b
296
+ px[offset + 3] = data.a * pixelTransparency; //a
297
+ }
574
298
 
575
- return getCompareApi(wrapper);
576
- }
577
- };
299
+ function getPixelInfo(data, offset, cacheSet) {
300
+ var r;
301
+ var g;
302
+ var b;
303
+ var d;
304
+ var a;
305
+
306
+ r = data[offset];
307
+
308
+ if (typeof r !== 'undefined') {
309
+ g = data[offset + 1];
310
+ b = data[offset + 2];
311
+ a = data[offset + 3];
312
+ d = {
313
+ r: r,
314
+ g: g,
315
+ b: b,
316
+ a: a
317
+ };
318
+
319
+ return d;
320
+ } else {
321
+ return null;
322
+ }
323
+ }
578
324
 
579
- return self;
580
- }
325
+ function addBrightnessInfo(data) {
326
+ data.brightness = getBrightness(data.r, data.g, data.b); // 'corrected' lightness
327
+ }
581
328
 
582
- return {
583
- onComplete: function( callback ){
584
- updateCallbackArray.push(callback);
585
- loadImageData(fileData, function(imageData, width, height){
586
- parseImage(imageData.data, width, height);
587
- });
588
- },
589
- compareTo: function(secondFileData){
590
- return getCompareApi(secondFileData);
591
- }
592
- };
329
+ function addHueInfo(data) {
330
+ data.h = getHue(data.r, data.g, data.b);
331
+ }
593
332
 
594
- };
333
+ function analyseImages(img1, img2, width, height) {
595
334
 
596
- _this['resemble'].outputSettings = function(options){
597
- var key;
598
- var undefined;
335
+ var data1 = img1.data;
336
+ var data2 = img2.data;
599
337
 
600
- if(options.errorColor){
601
- for (key in options.errorColor) {
602
- errorPixelColor[key] = options.errorColor[key] === undefined ? errorPixelColor[key] : options.errorColor[key];
603
- }
604
- }
338
+ //TODO
339
+ var imgd = new PNG({
340
+ width: img1.width,
341
+ height: img1.height,
342
+ deflateChunkSize: img1.deflateChunkSize,
343
+ deflateLevel: img1.deflateLevel,
344
+ deflateStrategy: img1.deflateStrategy,
345
+ });
346
+ var targetPix = imgd.data;
605
347
 
606
- if(options.errorType && errorPixelTransform[options.errorType] ){
607
- errorPixelTransformer = errorPixelTransform[options.errorType];
608
- }
348
+ var mismatchCount = 0;
609
349
 
610
- pixelTransparency = options.transparency || pixelTransparency;
350
+ var time = Date.now();
611
351
 
612
- if (options.largeImageThreshold !== undefined) {
613
- largeImageThreshold = options.largeImageThreshold;
614
- }
352
+ var skip;
353
+
354
+ var currentRectangle = null;
355
+ var rectagnlesIdx = 0;
356
+
357
+ if (!!largeImageThreshold && ignoreAntialiasing && (width > largeImageThreshold || height > largeImageThreshold)) {
358
+ skip = 6;
359
+ }
360
+
361
+ loop(height, width, function (verticalPos, horizontalPos) {
362
+
363
+ var offset = (verticalPos * width + horizontalPos) * 4;
364
+
365
+ if (skip) { // only skip if the image isn't small
366
+ if (verticalPos % skip === 0 || horizontalPos % skip === 0) {
367
+
368
+ copyPixel(targetPix, offset, {
369
+ r: 0,
370
+ b: 0,
371
+ g: 0,
372
+ a: 0
373
+ });
374
+
375
+ return;
376
+ }
377
+ }
378
+
379
+ var pixel1 = getPixelInfo(data1, offset, 1);
380
+ var pixel2 = getPixelInfo(data2, offset, 2);
381
+
382
+ if (pixel1 === null || pixel2 === null) {
383
+ return;
384
+ }
385
+
386
+ if (ignoreRectangles) {
387
+ for (rectagnlesIdx = 0; rectagnlesIdx < ignoreRectangles.length; rectagnlesIdx++) {
388
+ currentRectangle = ignoreRectangles[rectagnlesIdx];
389
+ //console.log(currentRectangle, verticalPos, horizontalPos);
390
+ if (isWithinRectangle(verticalPos, horizontalPos, currentRectangle)) {
391
+ copyGrayScalePixel(targetPix, offset, pixel2);
392
+ //copyPixel(targetPix, offset, pixel1, pixel2);
393
+ return;
394
+ }
395
+ }
396
+ }
397
+
398
+ if (includeRectangles) {
399
+ var isWithinAnyRectangle = false;
400
+ for (rectagnlesIdx = 0; rectagnlesIdx < includeRectangles.length; rectagnlesIdx++) {
401
+ currentRectangle = includeRectangles[rectagnlesIdx];
402
+ if (isWithinRectangle(verticalPos, horizontalPos, currentRectangle)) {
403
+ isWithinAnyRectangle = true;
404
+ }
405
+ }
406
+ // Better solution but i'm not sure if you want to use reducers in your repo?
407
+ // var isWithinAnyRectangle = includeRectangles.reduce(function (acc, currentRectangle) {
408
+ // if(isWithinRectangle) {
409
+ // return true;
410
+ // }
411
+ // return acc;
412
+ // }, false);
413
+ if (!isWithinAnyRectangle) {
414
+ copyGrayScalePixel(targetPix, offset, pixel2);
415
+ return;
416
+ }
417
+ }
418
+
419
+ if (ignoreColors) {
420
+
421
+ addBrightnessInfo(pixel1);
422
+ addBrightnessInfo(pixel2);
423
+
424
+ if (isPixelBrightnessSimilar(pixel1, pixel2)) {
425
+ copyGrayScalePixel(targetPix, offset, pixel2);
426
+ } else {
427
+ errorPixel(targetPix, offset, pixel1, pixel2);
428
+ mismatchCount++;
429
+ }
430
+ return;
431
+ }
432
+
433
+ if (isRGBSimilar(pixel1, pixel2)) {
434
+ copyPixel(targetPix, offset, pixel1);
435
+
436
+ } else if (ignoreAntialiasing && (
437
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
438
+ addBrightnessInfo(pixel2),
439
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
440
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
441
+ )) {
442
+
443
+ if (isPixelBrightnessSimilar(pixel1, pixel2)) {
444
+ copyGrayScalePixel(targetPix, offset, pixel2);
445
+ } else {
446
+ errorPixel(targetPix, offset, pixel1, pixel2);
447
+ mismatchCount++;
448
+ }
449
+ } else {
450
+ errorPixel(targetPix, offset, pixel1, pixel2);
451
+ mismatchCount++;
452
+ }
453
+
454
+ });
455
+
456
+ data.rawMisMatchPercentage = (mismatchCount / (height * width) * 100);
457
+ data.misMatchPercentage = data.rawMisMatchPercentage.toFixed(2);
458
+ data.analysisTime = Date.now() - time;
459
+
460
+ data.getDiffImage = function (text) {
461
+ return imgd;
462
+ };
463
+
464
+ data.getDiffImageAsJPEG = function (quality) {
465
+ return jpeg.encode({
466
+ data: targetPix,
467
+ width: img1.width,
468
+ height: img1.height
469
+ }, quality !== undefined ? quality : 50).data;
470
+ };
471
+ }
472
+
473
+ function compare(one, two) {
474
+
475
+ function onceWeHaveBoth(img) {
476
+ var width;
477
+ var height;
478
+
479
+ images.push(img);
480
+ if (images.length === 2) {
481
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
482
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
483
+
484
+ if ((images[0].width === images[1].width) && (images[0].height === images[1].height)) {
485
+ data.isSameDimensions = true;
486
+ } else {
487
+ data.isSameDimensions = false;
488
+ }
489
+
490
+ data.dimensionDifference = {
491
+ width: images[0].width - images[1].width,
492
+ height: images[0].height - images[1].height
493
+ };
494
+
495
+ //lksv: normalization removed
496
+ analyseImages(images[0], images[1], width, height);
497
+
498
+ triggerDataUpdate();
499
+ }
500
+ }
501
+
502
+ images = [];
503
+ loadImageData(one, onceWeHaveBoth);
504
+ loadImageData(two, onceWeHaveBoth);
505
+ }
506
+
507
+ function getCompareApi(param) {
508
+
509
+ var secondFileData,
510
+ hasMethod = typeof param === 'function';
511
+
512
+ if (!hasMethod) {
513
+ // assume it's file data
514
+ secondFileData = param;
515
+ }
516
+
517
+ var self = {
518
+ ignoreNothing: function () {
519
+
520
+ tolerance.red = 16;
521
+ tolerance.green = 16;
522
+ tolerance.blue = 16;
523
+ tolerance.alpha = 16;
524
+ tolerance.minBrightness = 16;
525
+ tolerance.maxBrightness = 240;
526
+
527
+ ignoreAntialiasing = false;
528
+ ignoreColors = false;
529
+
530
+ if (hasMethod) {
531
+ param();
532
+ }
533
+ return self;
534
+ },
535
+ ignoreAntialiasing: function () {
536
+
537
+ tolerance.red = 32;
538
+ tolerance.green = 32;
539
+ tolerance.blue = 32;
540
+ tolerance.alpha = 32;
541
+ tolerance.minBrightness = 64;
542
+ tolerance.maxBrightness = 96;
543
+
544
+ ignoreAntialiasing = true;
545
+ ignoreColors = false;
546
+
547
+ if (hasMethod) {
548
+ param();
549
+ }
550
+ return self;
551
+ },
552
+ ignoreColors: function () {
553
+
554
+ tolerance.alpha = 16;
555
+ tolerance.minBrightness = 16;
556
+ tolerance.maxBrightness = 240;
557
+
558
+ ignoreAntialiasing = false;
559
+ ignoreColors = true;
560
+
561
+ if (hasMethod) {
562
+ param();
563
+ }
564
+ return self;
565
+ },
566
+ //array of rectangles, each rectangle is defined as (x, y, width. height)
567
+ //e.g. [[325, 170, 100, 40]]
568
+ ignoreRectangles: function (rectangles) {
569
+ ignoreRectangles = rectangles;
570
+ return self;
571
+ },
572
+ //array of rectangles, each rectangle is defined as (x, y, width. height)
573
+ //e.g. [[325, 170, 100, 40]]
574
+ includeRectangles: function (rectangles) {
575
+ includeRectangles = rectangles;
576
+ return self;
577
+ },
578
+ repaint: function () {
579
+ if (hasMethod) {
580
+ param();
581
+ }
582
+ return self;
583
+ },
584
+ onComplete: function (callback) {
585
+
586
+ updateCallbackArray.push(callback);
587
+
588
+ var wrapper = function () {
589
+ compare(fileData, secondFileData);
590
+ };
591
+
592
+ wrapper();
593
+
594
+ return getCompareApi(wrapper);
595
+ }
596
+ };
597
+
598
+ return self;
599
+ }
600
+
601
+ return {
602
+ onComplete: function (callback) {
603
+ updateCallbackArray.push(callback);
604
+ loadImageData(fileData, function (imageData, width, height) {
605
+ parseImage(imageData.data, width, height);
606
+ });
607
+ },
608
+ compareTo: function (secondFileData) {
609
+ return getCompareApi(secondFileData);
610
+ }
611
+ };
612
+
613
+ };
614
+
615
+ _this['resemble'].outputSettings = function (options) {
616
+ var key;
617
+ var undefined;
618
+
619
+ if (options.errorColor) {
620
+ for (key in options.errorColor) {
621
+ errorPixelColor[key] = options.errorColor[key] === undefined ? errorPixelColor[key] : options.errorColor[key];
622
+ }
623
+ }
624
+
625
+ if (options.errorType && errorPixelTransform[options.errorType]) {
626
+ errorPixelTransformer = errorPixelTransform[options.errorType];
627
+ }
628
+
629
+ pixelTransparency = options.transparency || pixelTransparency;
630
+
631
+ if (options.largeImageThreshold !== undefined) {
632
+ largeImageThreshold = options.largeImageThreshold;
633
+ }
615
634
 
616
- return this;
617
- };
635
+ return this;
636
+ };
618
637
 
619
- module.exports = _this['resemble']
638
+ module.exports = _this['resemble'];