6 changed files with 613 additions and 0 deletions
@ -0,0 +1,91 @@ |
|||||||
|
$(function(){ |
||||||
|
var $target = $('#drop-zone'); |
||||||
|
|
||||||
|
function dropZone($target, onDrop){ |
||||||
|
$target. |
||||||
|
bind('dragover', function(){ |
||||||
|
$target.addClass( 'drag-over' ); |
||||||
|
return false; |
||||||
|
}). |
||||||
|
bind("dragend", function () { |
||||||
|
$target.removeClass( 'drag-over' ); |
||||||
|
return false; |
||||||
|
}). |
||||||
|
bind("mouseout", function () { |
||||||
|
$target.removeClass( 'drag-over' ); |
||||||
|
return false; |
||||||
|
}). |
||||||
|
bind("drop", function(event) { |
||||||
|
var file = event.originalEvent.dataTransfer.files[0]; |
||||||
|
|
||||||
|
event.stopPropagation(); |
||||||
|
event.preventDefault(); |
||||||
|
|
||||||
|
$target.removeClass( 'drag-over' ); |
||||||
|
|
||||||
|
var droppedImage = new Image(); |
||||||
|
var fileReader = new FileReader(); |
||||||
|
|
||||||
|
fileReader.onload = function (event) { |
||||||
|
droppedImage.src = event.target.result; |
||||||
|
$target.html(droppedImage); |
||||||
|
}; |
||||||
|
|
||||||
|
fileReader.readAsDataURL(file); |
||||||
|
|
||||||
|
onDrop(file); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
dropZone($target, function(file){ |
||||||
|
|
||||||
|
resemble(file).onComplete(function(data){ |
||||||
|
$('#image-data').show(); |
||||||
|
$('#red').css('width',data.red+'%'); |
||||||
|
$('#green').css('width',data.green+'%'); |
||||||
|
$('#blue').css('width',data.blue+'%'); |
||||||
|
$('#brightness').css('width',data.brightness+'%'); |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
function onComplete(data){ |
||||||
|
var diffImage = new Image(); |
||||||
|
diffImage.src = data.imageDiffFileData; |
||||||
|
$('#image-diff').html(diffImage); |
||||||
|
|
||||||
|
$(diffImage).click(function(){ |
||||||
|
window.open(diffImage.src, '_blank'); |
||||||
|
}); |
||||||
|
|
||||||
|
if(data.misMatchPercentage == 0){ |
||||||
|
$('#thesame').show(); |
||||||
|
$('#diff-results').hide(); |
||||||
|
} else { |
||||||
|
$('#mismatch').text(data.misMatchPercentage); |
||||||
|
if(!data.isSameDimensions){ |
||||||
|
$('#differentdimensions').show(); |
||||||
|
} else { |
||||||
|
$('#differentdimensions').hide(); |
||||||
|
} |
||||||
|
$('#diff-results').show(); |
||||||
|
$('#thesame').hide(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var file1; |
||||||
|
var file2; |
||||||
|
dropZone($('#dropzone1'), function(file){ |
||||||
|
file1 = file; |
||||||
|
if(file2){ |
||||||
|
resemble(file).compareTo(file2).onComplete(onComplete); |
||||||
|
} |
||||||
|
}); |
||||||
|
dropZone($('#dropzone2'), function(file){ |
||||||
|
file2 = file; |
||||||
|
if(file1){ |
||||||
|
resemble(file).compareTo(file1).onComplete(onComplete); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
@ -0,0 +1,64 @@ |
|||||||
|
|
||||||
|
|
||||||
|
h1 { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
padding-top: 60px; |
||||||
|
} |
||||||
|
|
||||||
|
footer { |
||||||
|
margin-top: 45px; |
||||||
|
padding: 35px 0 36px; |
||||||
|
border-top: 1px solid #e5e5e5; |
||||||
|
} |
||||||
|
|
||||||
|
.drop-zone{ |
||||||
|
border: 10px dashed #ccc; |
||||||
|
color: #ccc; |
||||||
|
font-size: 32px; |
||||||
|
height: 400px; |
||||||
|
line-height: 400px; |
||||||
|
text-align: center; |
||||||
|
width: 400px; |
||||||
|
overflow: hidden; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
.drop-zone.drag-over{ |
||||||
|
border: 10px dashed #0088CC; |
||||||
|
} |
||||||
|
.drop-zone img { |
||||||
|
width: 400px; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.small-drop-zone{ |
||||||
|
margin-top: 20px; |
||||||
|
margin-left: 90px; |
||||||
|
border: 10px dashed #ccc; |
||||||
|
color: #ccc; |
||||||
|
font-size: 32px; |
||||||
|
height: 330px; |
||||||
|
line-height: 330px; |
||||||
|
text-align: center; |
||||||
|
width: 330px; |
||||||
|
overflow: hidden; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
.small-drop-zone.drag-over{ |
||||||
|
border: 10px dashed #0088CC; |
||||||
|
} |
||||||
|
.small-drop-zone img { |
||||||
|
width: 330px; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
#image-diff { |
||||||
|
margin-left: 0px; |
||||||
|
margin-top: 90px; |
||||||
|
border-style: solid; |
||||||
|
} |
@ -0,0 +1,148 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
||||||
|
<title>Resemble.js : Image analysis</title> |
||||||
|
<meta name="description" content=""> |
||||||
|
<meta name="viewport" content="width=device-width"> |
||||||
|
<link rel="stylesheet" href="libs/twitter-bootstrap/bootstrap.min.css"> |
||||||
|
<link rel="stylesheet" href="demoassets/resemble.css"> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div class="container"> |
||||||
|
<header> |
||||||
|
<div class="page-header"> |
||||||
|
<h1>Resemble.js : Image analysis and comparison</h1> |
||||||
|
</div> |
||||||
|
</header> |
||||||
|
|
||||||
|
<section role="main"> |
||||||
|
<div class="row"> |
||||||
|
<div class="span12"> |
||||||
|
<div class="hero-unit"> |
||||||
|
<div class="row"> |
||||||
|
<div class="span6"> |
||||||
|
<p> |
||||||
|
<div id="drop-zone" class="drop-zone"> |
||||||
|
Drop image here. |
||||||
|
</div> |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
<div class="span4"> |
||||||
|
<h2>What is this?</h2> |
||||||
|
<p> |
||||||
|
Resemble.js analyses and compares images with HTML5 canvas and JavaScript. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
<strong>Try it for yourself.</strong> |
||||||
|
</p> |
||||||
|
<div id="image-data" style="display:none"> |
||||||
|
|
||||||
|
RGB |
||||||
|
<div class="progress progress-danger"> |
||||||
|
<div id="red" class="bar" style="width: 0%;"></div> |
||||||
|
</div> |
||||||
|
<div class="progress progress-success"> |
||||||
|
<div id="green" class="bar" style="width: 0%;"></div> |
||||||
|
</div> |
||||||
|
<div class="progress"> |
||||||
|
<div id="blue" class="bar" style="width: 0%;"></div> |
||||||
|
</div> |
||||||
|
|
||||||
|
Brightness |
||||||
|
<div class="progress progress-warning"> |
||||||
|
<div id="brightness" class="bar" style="width: 0%;"></div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="row"> |
||||||
|
<div class="span12"> |
||||||
|
<div class="row"> |
||||||
|
<div class="span6"> |
||||||
|
<div id="dropzone1" class="small-drop-zone"> |
||||||
|
Drop first image |
||||||
|
</div> |
||||||
|
<div id="dropzone2" class="small-drop-zone"> |
||||||
|
Drop second image |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="span6"> |
||||||
|
<h2>Compare two images?</h2> |
||||||
|
<p> |
||||||
|
Drop two images on the boxes to the right. The box below will show a generated 'diff' image, pink areas show mismatch. This example best works with two very similar but slightly different images. Try for yourself! |
||||||
|
</p> |
||||||
|
<div id="image-diff" class="small-drop-zone"> |
||||||
|
Diff will appear here. |
||||||
|
</div> |
||||||
|
<br/> |
||||||
|
<p id="diff-results" style="display:none;"> |
||||||
|
<strong>The second image is <span id="mismatch"></span>% different compared to the first. |
||||||
|
<span id="differentdimensions" style="display:none;">And they have different dimensions.</span></strong> |
||||||
|
</p> |
||||||
|
<p id="thesame" style="display:none;"> |
||||||
|
<strong>These images are the same!</strong> |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<br/><br/> |
||||||
|
<div class="row"> |
||||||
|
<div class="span6"> |
||||||
|
<h2>How does it work?</h2> |
||||||
|
<p> |
||||||
|
Dark magic. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
<br/> |
||||||
|
<a class="btn btn-large btn-primary" href="#"><strong>View project on Github</strong></a> |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
<div class="span6"> |
||||||
|
<h2>How can I use it?</h2> |
||||||
|
<p>Invoke Resemble on an image or canvas image to extract data</p> |
||||||
|
<pre> |
||||||
|
var data = resemble('img').onComplete(function(data){ |
||||||
|
return data; |
||||||
|
}); |
||||||
|
/* |
||||||
|
{ |
||||||
|
red: 255, |
||||||
|
green: 255, |
||||||
|
blue: 255, |
||||||
|
brightness: 255 |
||||||
|
} |
||||||
|
*/</pre> |
||||||
|
<p>Use resemble to compare two image</p> |
||||||
|
<pre> |
||||||
|
resemble(file).compareTo(file2).onComplete(function(){ |
||||||
|
return data; |
||||||
|
}); |
||||||
|
/* |
||||||
|
{ |
||||||
|
misMatchPercentage : 100, // % |
||||||
|
isSameDimensions: true, // or false |
||||||
|
imageDiffFileData: {} // dataUrl of image as png |
||||||
|
} |
||||||
|
*/</pre> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</section> |
||||||
|
|
||||||
|
<footer class="footer"> |
||||||
|
<p> |
||||||
|
Footer message |
||||||
|
</p> |
||||||
|
</footer> |
||||||
|
</div> |
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> |
||||||
|
<script src="resemble.js"></script> |
||||||
|
<script src="demoassets/main.js"></script> |
||||||
|
</body> |
||||||
|
</html> |
File diff suppressed because one or more lines are too long
@ -0,0 +1,67 @@ |
|||||||
|
|
||||||
|
|
||||||
|
h1 { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
padding-top: 60px; |
||||||
|
} |
||||||
|
|
||||||
|
footer { |
||||||
|
margin-top: 45px; |
||||||
|
padding: 35px 0 36px; |
||||||
|
border-top: 1px solid #e5e5e5; |
||||||
|
} |
||||||
|
|
||||||
|
.drop-zone{ |
||||||
|
border: 10px dashed #ccc; |
||||||
|
color: #ccc; |
||||||
|
font-size: 32px; |
||||||
|
height: 400px; |
||||||
|
line-height: 400px; |
||||||
|
text-align: center; |
||||||
|
width: 400px; |
||||||
|
overflow: hidden; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
.drop-zone.drag-over{ |
||||||
|
border: 10px dashed #0088CC; |
||||||
|
} |
||||||
|
.drop-zone img { |
||||||
|
width: 400px; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.small-drop-zone{ |
||||||
|
margin-top: 20px; |
||||||
|
margin-left: 90px; |
||||||
|
border: 10px dashed #ccc; |
||||||
|
color: #ccc; |
||||||
|
font-size: 32px; |
||||||
|
height: 330px; |
||||||
|
line-height: 330px; |
||||||
|
text-align: center; |
||||||
|
width: 330px; |
||||||
|
overflow: hidden; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
.small-drop-zone.drag-over{ |
||||||
|
border: 10px dashed #0088CC; |
||||||
|
} |
||||||
|
.small-drop-zone img { |
||||||
|
width: 330px; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
#image-diff { |
||||||
|
margin-left: 0px; |
||||||
|
margin-top: 90px; |
||||||
|
border-style: solid; |
||||||
|
} |
||||||
|
#image-diff img { |
||||||
|
cursor: pointer !important; |
||||||
|
} |
@ -0,0 +1,234 @@ |
|||||||
|
(function(_this){ |
||||||
|
|
||||||
|
_this['resemble'] = function( fileData ){ |
||||||
|
|
||||||
|
var data = {}; |
||||||
|
var images = []; |
||||||
|
var updateCallbackArray = []; |
||||||
|
|
||||||
|
var tolerance = [ // between 0 and 255
|
||||||
|
255, // red
|
||||||
|
255, // green 16
|
||||||
|
255, // blue 24
|
||||||
|
255, // alpha
|
||||||
|
255 // brightness
|
||||||
|
]; |
||||||
|
|
||||||
|
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 alpha = sourceImageData[offset + 3]; |
||||||
|
var brightness = (0.3*red + 0.59*green + 0.11*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 hiddenImage = new Image(); |
||||||
|
var fileReader = new FileReader(); |
||||||
|
|
||||||
|
fileReader.onload = function (event) { |
||||||
|
hiddenImage.src = event.target.result; |
||||||
|
}; |
||||||
|
|
||||||
|
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); |
||||||
|
}; |
||||||
|
|
||||||
|
fileReader.readAsDataURL(fileData); |
||||||
|
} |
||||||
|
|
||||||
|
function isPixelDifferent(d1, d2, off, plus){ |
||||||
|
var a = d1[off + plus]; |
||||||
|
var b = d2[off + plus]; |
||||||
|
|
||||||
|
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[plus] ) { |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function compareBrightness(data1, data2, offset){ |
||||||
|
var red1 = data1[offset + 0]; |
||||||
|
var green1 = data1[offset + 1]; |
||||||
|
var blue1 = data1[offset + 2]; |
||||||
|
|
||||||
|
var red2 = data2[offset + 0]; |
||||||
|
var green2 = data2[offset + 1]; |
||||||
|
var blue2 = data2[offset + 2]; |
||||||
|
|
||||||
|
var brightness1; |
||||||
|
var brightness2; |
||||||
|
|
||||||
|
if(red1 && green1 && blue1 && red2 && green2 && blue2){ |
||||||
|
|
||||||
|
brightness1 = (0.3*red1 + 0.59*green1 + 0.11*blue1); |
||||||
|
brightness2 = (0.3*red2 + 0.59*green2 + 0.11*blue2); |
||||||
|
|
||||||
|
return Math.abs(brightness1 - brightness2) < tolerance[4]; |
||||||
|
|
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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 pix = imgd.data; |
||||||
|
|
||||||
|
var mismatchCount = 0; |
||||||
|
|
||||||
|
loop(height, width, function(verticalPos, horizontalPos){ |
||||||
|
|
||||||
|
var offset = (verticalPos*width + horizontalPos) * 4; |
||||||
|
var red = isPixelDifferent(data1, data2, offset, 0); |
||||||
|
var green = isPixelDifferent(data1, data2, offset, 1); |
||||||
|
var blue = isPixelDifferent(data1, data2, offset, 2); |
||||||
|
var alpha = isPixelDifferent(data1, data2, offset, 3); |
||||||
|
|
||||||
|
var brightness = compareBrightness(data1, data2, offset); |
||||||
|
|
||||||
|
if(brightness && red && green && blue){ |
||||||
|
|
||||||
|
pix[offset] = data1[offset + 0]; |
||||||
|
pix[offset + 1] = data1[offset + 1]; |
||||||
|
pix[offset + 2] = data1[offset + 2]; |
||||||
|
pix[offset + 3] = data1[offset + 3]; |
||||||
|
|
||||||
|
} else { |
||||||
|
pix[offset] = 255; |
||||||
|
pix[offset + 1] = 0; |
||||||
|
pix[offset + 2] = 255; |
||||||
|
pix[offset + 3] = 255; |
||||||
|
|
||||||
|
mismatchCount++; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
context.putImageData(imgd, 0,0); |
||||||
|
|
||||||
|
data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2); |
||||||
|
data.imageDiffFileData = hiddenCanvas.toDataURL("image/png"); |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
analyseImages(images[0], images[1], width, height); |
||||||
|
|
||||||
|
triggerDataUpdate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
loadImageData(one, onceWeHaveBoth); |
||||||
|
loadImageData(two, onceWeHaveBoth); |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
onComplete: function( callback ){ |
||||||
|
updateCallbackArray.push(callback); |
||||||
|
loadImageData(fileData, function(imageData, width, height){ |
||||||
|
parseImage(imageData.data, width, height); |
||||||
|
}); |
||||||
|
}, |
||||||
|
compareTo: function(secondFileData){ |
||||||
|
return { |
||||||
|
onComplete: function( callback ){ |
||||||
|
updateCallbackArray.push(callback); |
||||||
|
compare(fileData, secondFileData); |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
}; |
||||||
|
}(this)); |
Loading…
Reference in new issue