Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorThomas Steur <thomas.steur@googlemail.com>2014-05-28 06:49:10 +0400
committerThomas Steur <thomas.steur@googlemail.com>2014-05-28 06:49:10 +0400
commitab31aea98e870f7675227c7c9d87e0b08d825613 (patch)
treefe1cc36b0ac158830875fbeb8697f143d76ef0a7 /tests
parent7b62ecf324df7c01d1fc1cb9b0dc34832c3c3a12 (diff)
added missing resemblejs lib
Diffstat (limited to 'tests')
-rw-r--r--tests/lib/resemblejs/LICENSE18
-rw-r--r--tests/lib/resemblejs/README.md73
-rw-r--r--tests/lib/resemblejs/resemble.js600
3 files changed, 691 insertions, 0 deletions
diff --git a/tests/lib/resemblejs/LICENSE b/tests/lib/resemblejs/LICENSE
new file mode 100644
index 0000000000..df12acc478
--- /dev/null
+++ b/tests/lib/resemblejs/LICENSE
@@ -0,0 +1,18 @@
+The MIT License (MIT) Copyright © 2013 Huddle
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the “Software”), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/tests/lib/resemblejs/README.md b/tests/lib/resemblejs/README.md
new file mode 100644
index 0000000000..62e1041104
--- /dev/null
+++ b/tests/lib/resemblejs/README.md
@@ -0,0 +1,73 @@
+Resemble.js
+==========
+
+Analyse and compare images with Javascript and HTML5. [Resemble.js Demo](http://huddle.github.com/Resemble.js/)
+
+![Two image diff examples side-by-side, one pink, one yellow.](https://raw.github.com/Huddle/Resemble.js/master/demoassets/readmeimage.jpg "Visual image comparison")
+
+### Get it
+
+`npm install resemblejs`
+
+`bower install resemblejs`
+
+### Example
+
+Retrieve basic analysis on image.
+
+```javascript
+var api = resemble(fileData).onComplete(function(data){
+ console.log(data);
+ /*
+ {
+ red: 255,
+ green: 255,
+ blue: 255,
+ brightness: 255
+ }
+ */
+});
+```
+
+Use resemble to compare two images.
+
+```javascript
+var diff = resemble(file).compareTo(file2).ignoreColors().onComplete(function(data){
+ console.log(data);
+ /*
+ {
+ misMatchPercentage : 100, // %
+ isSameDimensions: true, // or false
+ dimensionDifference: { width: 0, height: -1 }, // defined if dimensions are not the same
+ getImageDataUrl: function(){}
+ }
+ */
+});
+```
+
+You can also change the comparison method after the first analysis.
+
+```javascript
+// diff.ignoreNothing();
+// diff.ignoreColors();
+diff.ignoreAntialiasing();
+```
+
+And change the output display style.
+
+```javascript
+resemble.outputSettings({
+ errorColor: {
+ red: 255,
+ green: 0,
+ blue: 255
+ },
+ errorType: 'movement',
+ transparency: 0.3
+});
+// resembleControl.repaint();
+```
+
+--------------------------------------
+
+Created by [James Cryer](http://github.com/jamescryer) and the Huddle development team. \ No newline at end of file
diff --git a/tests/lib/resemblejs/resemble.js b/tests/lib/resemblejs/resemble.js
new file mode 100644
index 0000000000..dbb927a7cd
--- /dev/null
+++ b/tests/lib/resemblejs/resemble.js
@@ -0,0 +1,600 @@
+/*
+ James Cryer / Huddle 2014
+ URL: https://github.com/Huddle/Resemble.js
+ */
+
+(function(_this){
+ 'use strict';
+
+ var pixelTransparency = 1;
+
+ var errorPixelColor = { // Color for Error Pixels. Between 0 and 255.
+ red: 255,
+ green: 0,
+ blue: 255,
+ alpha: 255
+ };
+
+ var errorPixelTransform = {
+ flat : function (d1, d2){
+ return {
+ r: errorPixelColor.red,
+ g: errorPixelColor.green,
+ b: errorPixelColor.blue,
+ a: errorPixelColor.alpha
+ }
+ },
+ movement: function (d1, d2){
+ return {
+ r: ((d2.r*(errorPixelColor.red/255)) + errorPixelColor.red)/2,
+ g: ((d2.g*(errorPixelColor.green/255)) + errorPixelColor.green)/2,
+ b: ((d2.b*(errorPixelColor.blue/255)) + errorPixelColor.blue)/2,
+ a: d2.a
+ }
+ }
+ };
+
+ var errorPixelTransformer = errorPixelTransform.flat;
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ alpha: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i<len;i++){
+ if (typeof updateCallbackArray[i] === 'function'){
+ updateCallbackArray[i](data);
+ }
+ }
+ }
+
+ function loop(x, y, callback){
+ var i,j;
+
+ for (i=0;i<x;i++){
+ for (j=0;j<y;j++){
+ callback(i, j);
+ }
+ }
+ }
+
+ function parseImage(sourceImageData, width, height){
+
+ var pixleCount = 0;
+ var redTotal = 0;
+ var greenTotal = 0;
+ var blueTotal = 0;
+ var brightnessTotal = 0;
+
+ loop(height, width, function(verticalPos, horizontalPos){
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var red = sourceImageData[offset];
+ var green = sourceImageData[offset + 1];
+ var blue = sourceImageData[offset + 2];
+ var brightness = getBrightness(red,green,blue);
+
+ pixleCount++;
+
+ redTotal += red / 255 * 100;
+ greenTotal += green / 255 * 100;
+ blueTotal += blue / 255 * 100;
+ brightnessTotal += brightness / 255 * 100;
+ });
+
+ data.red = Math.floor(redTotal / pixleCount);
+ data.green = Math.floor(greenTotal / pixleCount);
+ data.blue = Math.floor(blueTotal / pixleCount);
+ data.brightness = Math.floor(brightnessTotal / pixleCount);
+
+ triggerDataUpdate();
+ }
+
+ function loadImageData( fileData, callback ){
+ var fileReader;
+ var hiddenImage = new Image();
+
+ hiddenImage.onload = function() {
+
+ var hiddenCanvas = document.createElement('canvas');
+ var imageData;
+ var width = hiddenImage.width;
+ var height = hiddenImage.height;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+ hiddenCanvas.getContext('2d').drawImage(hiddenImage, 0, 0, width, height);
+ imageData = hiddenCanvas.getContext('2d').getImageData(0, 0, width, height);
+
+ images.push(imageData);
+
+ callback(imageData, width, height);
+ };
+
+ if (typeof fileData === 'string') {
+ hiddenImage.src = fileData;
+ } else {
+ fileReader = new FileReader();
+ fileReader.onload = function (event) {
+ hiddenImage.src = event.target.result;
+ };
+ fileReader.readAsDataURL(fileData);
+ }
+ }
+
+ function isColorSimilar(a, b, color){
+
+ var absDiff = Math.abs(a - b);
+
+ if(typeof a === 'undefined'){
+ return false;
+ }
+ if(typeof b === 'undefined'){
+ return false;
+ }
+
+ if(a === b){
+ return true;
+ } else if ( absDiff < tolerance[color] ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function isNumber(n) {
+ return !isNaN(parseFloat(n));
+ }
+
+ function isPixelBrightnessSimilar(d1, d2){
+ var alpha = isColorSimilar(d1.a, d2.a, 'alpha');
+ var brightness = isColorSimilar(d1.brightness, d2.brightness, 'minBrightness');
+ return brightness && alpha;
+ }
+
+ function getBrightness(r,g,b){
+ return 0.3*r + 0.59*g + 0.11*b;
+ }
+
+ function isRGBSame(d1,d2){
+ var red = d1.r === d2.r;
+ var green = d1.g === d2.g;
+ var blue = d1.b === d2.b;
+ return red && green && blue;
+ }
+
+ function isRGBSimilar(d1, d2){
+ var red = isColorSimilar(d1.r,d2.r,'red');
+ var green = isColorSimilar(d1.g,d2.g,'green');
+ var blue = isColorSimilar(d1.b,d2.b,'blue');
+ var alpha = isColorSimilar(d1.a, d2.a, 'alpha');
+
+ return red && green && blue && alpha;
+ }
+
+ function isContrasting(d1, d2){
+ return Math.abs(d1.brightness - d2.brightness) > tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset, data1, data2){
+ var data = errorPixelTransformer(data1, data2);
+ px[offset] = data.r;
+ px[offset + 1] = data.g;
+ px[offset + 2] = data.b;
+ px[offset + 3] = data.a;
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = data.a * pixelTransparency; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = data.a * pixelTransparency; //a
+ }
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+ var a;
+
+ r = data[offset];
+
+ if(typeof r !== 'undefined'){
+ g = data[offset+1];
+ b = data[offset+2];
+ a = data[offset+3];
+ d = {
+ r: r,
+ g: g,
+ b: b,
+ a: a
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset, pixel1, pixel2);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel1, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset, pixel1, pixel2);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset, pixel1, pixel2);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ data.dimensionDifference = { width: images[0].width - images[1].width, height: images[0].height - images[1].height };
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.alpha = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.alpha = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.alpha = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ repaint: function(){
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+
+ _this['resemble'].outputSettings = function(options){
+ var key;
+ var undefined;
+
+ if(options.errorColor){
+ for (key in options.errorColor) {
+ errorPixelColor[key] = options.errorColor[key] === undefined ? errorPixelColor[key] : options.errorColor[key];
+ }
+ }
+
+ if(options.errorType && errorPixelTransform[options.errorType] ){
+ errorPixelTransformer = errorPixelTransform[options.errorType];
+ }
+
+ pixelTransparency = options.transparency || pixelTransparency;
+
+ return this;
+ };
+
+}(this)); \ No newline at end of file