diff --git a/js/imagediff.js b/js/imagediff.js index 958aab6..c1b12ff 100644 --- a/js/imagediff.js +++ b/js/imagediff.js @@ -148,20 +148,46 @@ function equalDimensions (a, b) { return equalHeight(a, b) && equalWidth(a, b); } - function equal (a, b, tolerance) { + function hasTotalDifference (aData, bData, totalToleranceRatio) { + var length = aData.length, + sumDifferences = 0, + i; + for (i = 0; i < length; i++) { + sumDifferences += Math.abs(aData[i] - bData[i]); + }; + + return sumDifferences / (255 * length) <= totalToleranceRatio; + } + function hasPerPixelDifference (aData, bData, relativePixelTolerance) { + var length = aData.length, + i; + for (i = length; i--;) if (aData[i] !== bData[i] && Math.abs(aData[i] - bData[i]) > relativePixelTolerance) return false; + return true; + } + function equal (a, b, options) { var - aData = a.data, - bData = b.data, - length = aData.length, - i; + aData = a.data, + bData = b.data, + toleranceValue, toleranceMethod; + + // Support old interface + if (typeof options === "number") { + options = { + toleranceValue: options + }; + } - tolerance = tolerance || 0; + toleranceValue = options && options.toleranceValue || 0; + toleranceMethod = options && options.toleranceMethod || 'relativePerPixel'; if (!equalDimensions(a, b)) return false; - for (i = length; i--;) if (aData[i] !== bData[i] && Math.abs(aData[i] - bData[i]) > tolerance) return false; - return true; + if (toleranceMethod === 'totalRatio') { + return hasTotalDifference(aData, bData, toleranceValue) + } else { + return hasPerPixelDifference(aData, bData, toleranceValue); + } } diff --git a/spec/ImageDiffSpec.js b/spec/ImageDiffSpec.js index 05fea69..9e5b900 100644 --- a/spec/ImageDiffSpec.js +++ b/spec/ImageDiffSpec.js @@ -258,22 +258,67 @@ describe('ImageUtils', function() { expect(imagediff.equal(a, b)).toEqual(false); }); - it('should be equal within optional tolerance', function () { - b = context.createImageData(2, 2); - b.data[0] = 100; - expect(imagediff.equal(a, b, 101)).toEqual(true); - }); + describe("tolerance", function () { + it('should be equal within optional tolerance', function () { + b = context.createImageData(2, 2); + b.data[0] = 100; + expect(imagediff.equal(a, b, 101)).toEqual(true); + }); - it('should be equal optional tolerance', function () { - b = context.createImageData(2, 2); - b.data[0] = 100; - expect(imagediff.equal(a, b, 100)).toEqual(true); - }); + it('should be equal optional tolerance', function () { + b = context.createImageData(2, 2); + b.data[0] = 100; + expect(imagediff.equal(a, b, 100)).toEqual(true); + }); - it('should not be equal outside tolerance', function () { - b = context.createImageData(2, 2); - b.data[0] = 100; - expect(imagediff.equal(a, b, 5)).toEqual(false); + it('should not be equal outside tolerance', function () { + b = context.createImageData(2, 2); + b.data[0] = 100; + expect(imagediff.equal(a, b, 5)).toEqual(false); + }); + + it('should be equal within optional tolerance using new API', function () { + b = context.createImageData(2, 2); + b.data[0] = 100; + expect(imagediff.equal(a, b, {toleranceValue: 101, toleranceMethod: 'relativePerPixel'})).toEqual(true); + }); + + it('should be equal optional tolerance using new API', function () { + b = context.createImageData(2, 2); + b.data[0] = 100; + expect(imagediff.equal(a, b, {toleranceValue: 100, toleranceMethod: 'relativePerPixel'})).toEqual(true); + }); + + it('should not be equal outside tolerance using new API', function () { + b = context.createImageData(2, 2); + b.data[0] = 100; + expect(imagediff.equal(a, b, {toleranceValue: 5, toleranceMethod: 'relativePerPixel'})).toEqual(false); + }); + + it('should be equal within optional total tolerance', function () { + b = context.createImageData(2, 2); + b.data[0] = 255; + expect(imagediff.equal(a, b, {toleranceValue: 1/4, toleranceMethod: 'totalRatio'})).toEqual(true); + }); + + it('should be equal optional total tolerance', function () { + b = context.createImageData(2, 2); + b.data[0] = 255; + expect(imagediff.equal(a, b, {toleranceValue: 1/16, toleranceMethod: 'totalRatio'})).toEqual(true); + }); + + it('should not be equal outside total tolerance', function () { + b = context.createImageData(2, 2); + b.data[0] = 255; + expect(imagediff.equal(a, b, {toleranceValue: 1/20, toleranceMethod: 'totalRatio'})).toEqual(false); + }); + + it('should use tolerance method "relativePerPixel" by default', function () { + b = context.createImageData(2, 2); + b.data[0] = 100; + expect(imagediff.equal(a, b, {toleranceValue: 100})).toEqual(true); + expect(imagediff.equal(a, b, {toleranceValue: 99})).toEqual(false); + }); }); });