From 29ee8490cd834840e142161c4ee879094b0d4540 Mon Sep 17 00:00:00 2001 From: Hubert OG Date: Wed, 14 Sep 2016 10:45:30 +0200 Subject: [PATCH 1/6] Added mask option --- README.md | 12 +++++- examples/1_normal_c.jpg | Bin 0 -> 21058 bytes examples/index.html | 84 +++++++++++++++++++++++++++++----------- js/imagediff.js | 81 +++++++++++++++++++++++++++++++++++++- 4 files changed, 152 insertions(+), 25 deletions(-) mode change 100644 => 100755 README.md create mode 100755 examples/1_normal_c.jpg mode change 100644 => 100755 examples/index.html mode change 100644 => 100755 js/imagediff.js diff --git a/README.md b/README.md old mode 100644 new mode 100755 index b52f6dd..f293d49 --- a/README.md +++ b/README.md @@ -8,18 +8,25 @@ API * `createCanvas()` create a new Canvas element. * `createImageData(width, height)` create a new ImageData object. +* `displayMask(width, height, regions)` create a image representation of regions mask. * `isImage(object)` tests for Image object. * `isCanvas(object)` tests for Canvas object. * `isContext(object)` tests for CanvasRenderingContext2D object. * `isImageData(object)` tests for ImageData object. * `isImageType(object)` tests for any of the above. * `toImageData(object)` converts image type object to a new ImageData object. -* `equal(a, b, tolerance)` tests image type objects for equality; accepts tolerance in pixels. +* `equal(a, b, tolerance, options)` tests image type objects for equality; accepts tolerance in pixels. * `diff(a, b, options)` performs an image diff on a and b, returning a - b. * `options.align` set to `'top'` to top-align the images when diffing different sizes. * `noConflict()` removes imagediff from the global space for compatibility, returning imagediff. * `imageDataToPNG(imageData, outputFile, [callback])` (node only) renders the imageData to png in outputFile with optional callback. +Regions +_______ + +`equal` method accepts optional region array. + + NodeJS ------ @@ -73,6 +80,9 @@ If you are using js-imagediff pelase drop us a line and let us know what you are Changelog --------- +

NEXT

+* Accept regions for masking image comparison +

1.0.8

* Update canvas dependency. * Expose internal Canvas. diff --git a/examples/1_normal_c.jpg b/examples/1_normal_c.jpg new file mode 100755 index 0000000000000000000000000000000000000000..4b03f183304142329bea707e9de06a26f76ae69c GIT binary patch literal 21058 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 Example:

See more examples at humblesoftware.github.com/js-imagediff. Sample images from the github imagediff demo.

-
+
example image one example image two
+ +
diff --git a/js/imagediff.js b/js/imagediff.js old mode 100644 new mode 100755 index 7760ffa..defb5d5 --- a/js/imagediff.js +++ b/js/imagediff.js @@ -141,6 +141,68 @@ return canvas; } + // Image mask generation + + + function fillArray(array, value, start, end) { + var i, + i0 = (start !== undefined) ? start : 0, + i1 = (end !== undefined) ? end : array.length; + if(Array.prototype.fill) { + return array.fill(value, start, end); + } + for(i = i0; i < i1; i += 1) { + array[i] = value; + } + return array; + } + /* + region format: [x0, y0, x1, y1, include] + */ + function createMask (width, height, regions) { + var + array = fillArray(Array(width * height), false), + i, y, region; + + for(i = 0; i < regions.length; i += 1) { + region = regions[i]; + for(y = region[1]; y < region[3]; y += 1) { + fillArray(array, region[4], y * width + region[0], y * width + region[2]); + } + } + return array; + } + function displayMask(width, height, regions) { + var + mask = createMask(width, height, regions), + image = getImageData(width, height), + iData = image.data, + length = mask.length, + i, ii, color; + + + + // height = a.height, + // width = a.width, + // c = getImageData(width, height), // c = a - b + // aData = a.data, + // bData = b.data, + // cData = c.data, + // length = cData.length, + // row, column, + // i, j, k, v; + + for (i = 0, ii = 0; i < length; i += 1, ii += 4) { + color = mask[i] ? 255 : 0; + iData[ii] = color; + iData[ii+1] = color; + iData[ii+2] = color; + iData[ii+3] = 255; + } + + return image; + } + // ImageData Equality Operators function equalWidth (a, b) { @@ -152,18 +214,31 @@ function equalDimensions (a, b) { return equalHeight(a, b) && equalWidth(a, b); } - function equal (a, b, tolerance) { + function equal (a, b, tolerance, options) { var aData = a.data, bData = b.data, length = aData.length, + mask = null, i; tolerance = tolerance || 0; + options = options || {}; if (!equalDimensions(a, b)) return false; - for (i = length; i--;) if (aData[i] !== bData[i] && Math.abs(aData[i] - bData[i]) > tolerance) return false; + + if(options.regions) { + mask = createMask(a.width, a.height, options.regions); + } + + for (i = length; i >= 0; i -= 1) { + if ((!mask || mask[i]) && + aData[i] !== bData[i] && + Math.abs(aData[i] - bData[i]) > tolerance) { + return false; + } + } return true; } @@ -350,6 +425,8 @@ createCanvas : getCanvas, createImageData : getImageData, + displayMask : displayMask, + isImage : isImage, isCanvas : isCanvas, isContext : isContext, From e3d74f5ed46c24eb540226d4a52f3feaf7da59bc Mon Sep 17 00:00:00 2001 From: Hubert OG Date: Wed, 14 Sep 2016 10:58:44 +0200 Subject: [PATCH 2/6] Display mask on diff --- examples/index.html | 16 ++++++++++------ js/imagediff.js | 35 ++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/examples/index.html b/examples/index.html index 3ee8430..29ad2f1 100755 --- a/examples/index.html +++ b/examples/index.html @@ -4,7 +4,7 @@ JS-ImageDiff Example - + @@ -16,7 +16,7 @@

JS-ImageDiff Example:

example image one example image two
- - -
+ -
+
diff --git a/js/imagediff.js b/js/imagediff.js index a0ace7a..d78a253 100755 --- a/js/imagediff.js +++ b/js/imagediff.js @@ -180,24 +180,18 @@ length = mask.length, i, ii, color; - - - // height = a.height, - // width = a.width, - // c = getImageData(width, height), // c = a - b - // aData = a.data, - // bData = b.data, - // cData = c.data, - // length = cData.length, - // row, column, - // i, j, k, v; - for (i = 0, ii = 0; i < length; i += 1, ii += 4) { color = mask[i] ? 255 : 0; iData[ii] = color; iData[ii+1] = color; iData[ii+2] = color; iData[ii+3] = 255; + + if(!(mask[i] === true || mask[i] === false)) { + iData[ii] = 255; + iData[ii+1] = 0; + iData[ii+2] = 0; + } } return image; @@ -219,7 +213,7 @@ var aData = a.data, bData = b.data, - length = aData.length, + length = aData.length / 4, mask = null, i, ii, j; @@ -261,23 +255,23 @@ length = cData.length, mask = null, row, column, - i, j, k, v; + i, ii, j, k, v; if(options.regions && options.mask) { mask = createMask(width, height, options.regions); } - for (i = 0; i < length; i += 4) { + for (i = 0, ii = 0; ii < length; i += 1, ii += 4) { if(mask && !mask[i]) { - cData[i] = 255; - cData[i+1] = 0; - cData[i+2] = 0; - cData[i+3] = 255; + cData[ii] = 0; + cData[ii+1] = 0; + cData[ii+2] = 92; + cData[ii+3] = 255; } else { - cData[i] = Math.abs(aData[i] - bData[i]); - cData[i+1] = Math.abs(aData[i+1] - bData[i+1]); - cData[i+2] = Math.abs(aData[i+2] - bData[i+2]); - cData[i+3] = Math.abs(255 - Math.abs(aData[i+3] - bData[i+3])); + cData[ii] = Math.abs(aData[ii] - bData[ii]); + cData[ii+1] = Math.abs(aData[ii+1] - bData[ii+1]); + cData[ii+2] = Math.abs(aData[ii+2] - bData[ii+2]); + cData[ii+3] = Math.abs(255 - Math.abs(aData[ii+3] - bData[ii+3])); } } @@ -452,11 +446,11 @@ return toImageData(object); }, - equal : function (a, b, tolerance) { + equal : function (a, b, tolerance, options) { checkType(a, b); a = toImageData(a); b = toImageData(b); - return equal(a, b, tolerance); + return equal(a, b, tolerance, options); }, diff : function (a, b, options) { checkType(a, b); From 2d7cf8c18c4c9e5387c1aa1ea81be811e59d90e1 Mon Sep 17 00:00:00 2001 From: Hubert OG Date: Wed, 14 Sep 2016 11:38:53 +0200 Subject: [PATCH 5/6] Readme update --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f293d49..caaaab1 100755 --- a/README.md +++ b/README.md @@ -24,7 +24,20 @@ API Regions _______ -`equal` method accepts optional region array. +Sometimes there's only part of the image that you want to test. +`equal` method accepts optional `regions` array that allows you to specify mask for image comparison. +Each region in the array is a five element array in the form `[x0, y0, x1, y1, include]`, where + +* `(x0, y0)` is the smallest coordinate corner of the region (inclusive) +* `(x1, y1)` is the largest coordinate corner of the region (non-inclusive) +* `include` is a boolean value that decides whether the rectangle should be checked for equality. + +Setting `include` to `true` will add the region to the mask, setting it to `false` will substract it. +Initially the mask is empty, therefore passing a single rectangle, e.g.: + +`equal(a, b, 0, {regions: [[20, 20, 240, 120, true]]})` + +will yield `true` if the images are equal within the single passed rectangle (`[20, 20, 240, 120]`). NodeJS From 5bc5157a0f2679e1c2901bece431bfbebf3e4cf2 Mon Sep 17 00:00:00 2001 From: Hubert OG Date: Wed, 14 Sep 2016 11:40:28 +0200 Subject: [PATCH 6/6] `displayMask` method explanation --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index caaaab1..4b3c41f 100755 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Initially the mask is empty, therefore passing a single rectangle, e.g.: will yield `true` if the images are equal within the single passed rectangle (`[20, 20, 240, 120]`). +You can use `displayMask` method to generate visual representation of created mask. NodeJS ------