Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Created March 31, 2011 14:47
Show Gist options
  • Save ynkdir/896487 to your computer and use it in GitHub Desktop.
Save ynkdir/896487 to your computer and use it in GitHub Desktop.
github like image diff
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8" />
<title>github like image diff</title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/ui-lightness/jquery-ui.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js"></script>
<style>
body {
background: #808080;
}
</style>
<script>
function LoadImage(url) {
var d = $.Deferred();
var img = new Image();
img.onload = function() { d.resolve(img); };
img.src = url;
return d.promise();
}
function ImageDataGetPixel(imgdata, x, y) {
var i = (y * imgdata.width + x) * 4;
var r = imgdata.data[i];
var g = imgdata.data[i + 1];
var b = imgdata.data[i + 2];
var a = imgdata.data[i + 3];
return [r, g, b, a];
}
function ImageDataSetPixel(imgdata, x, y, pixel) {
var i = (y * imgdata.width + x) * 4;
imgdata.data[i] = pixel[0];
imgdata.data[i + 1] = pixel[1];
imgdata.data[i + 2] = pixel[2];
imgdata.data[i + 3] = pixel[3];
}
function DiffPixel(p1, p2) {
var r = p1[0] - p2[0];
var g = p1[1] - p2[1];
var b = p1[2] - p2[2];
var a = p1[3] - p2[3];
if (r < 0) { r = -r; }
if (g < 0) { g = -g; }
if (b < 0) { b = -b; }
if (a < 0) { a = -b; }
return [r, g, b, 255];
}
// TODO: use background
// background-image: -moz-element(#canvaselement)
function CreateTransBackgroundImage(img, width, height) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
var size = 5;
var yi = 0;
var xi = 0;
var x, y;
for (y = 0; y < width; y += 5) {
xi = yi % 2 ? 0 : 1;
for (x = 0; x < width; x += 5) {
if (xi % 2) {
ctx.fillStyle = 'rgb(196, 196, 196)';
} else {
ctx.fillStyle = 'rgb(255, 255, 255)';
}
ctx.fillRect(x, y, size, size);
xi++;
}
yi++;
}
ctx.drawImage(img,
Math.round((width - img.width) / 2),
Math.round((height - img.height) / 2));
return canvas;
}
function cmp_2up(img1, img2) {
//var e1 = $('<img\/>').attr('src', img1.src)
var e1 = $(CreateTransBackgroundImage(img1, img1.width, img1.height))
.css({
width: img1.width,
height: img1.height,
border: '1px solid red'
});
//var e2 = $('<img\/>').attr('src', img2.src)
var e2 = $(CreateTransBackgroundImage(img2, img2.width, img2.height))
.css({
width: img2.width,
height: img2.height,
border: '1px solid green'
});
$('#cmp_2up')
.html('')
.append(e1, e2);
}
function cmp_swipe(img1, img2) {
var width = Math.max(img1.width, img2.width);
var height = Math.max(img1.height, img2.height);
//var e1 = $('<img\/>').attr('src', img1.src)
var e1 = $(CreateTransBackgroundImage(img1, img1.width, img1.height))
.css({
position: 'absolute',
left: Math.round((width - img1.width) / 2),
top: Math.round((height - img1.height) / 2),
border: '1px solid red'
});
// e1.clone() not work for canvas
var e1clone = $(CreateTransBackgroundImage(img1, img1.width, img1.height))
.css({
position: 'absolute',
left: Math.round((width - img1.width) / 2),
top: Math.round((height - img1.height) / 2),
border: '1px solid red'
});
//var e2 = $('<img\/>').attr('src', img2.src)
var e2 = $(CreateTransBackgroundImage(img2, img2.width, img2.height))
.css({
position: 'absolute',
left: Math.round((width - img2.width) / 2),
top: Math.round((height - img2.height) / 2),
border: '1px solid green'
});
var e3 = $('<div><\/div>')
.css({
position: 'absolute',
left: 0,
top: 0,
width: 0,
height: height,
borderRight: '1px solid gray',
overflow: 'hidden'
})
//.append(e1.clone());
.append(e1clone);
var container = $('<div><\/div>')
.css({
position: 'relative',
width: width,
height: height
})
.append(e1, e2, e3);
var slider = $('<div><\/div>')
.css({
width: width
})
.slider({
value: 0,
slide: function(event, ui) {
$(e3).css({
width: Math.round(width * (ui.value / 100))
});
}
});
$('#cmp_swipe')
.html('')
.append(container, slider);
}
function cmp_onion(img1, img2) {
var width = Math.max(img1.width, img2.width);
var height = Math.max(img1.height, img2.height);
//var e1 = $('<img\/>').attr('src', img1.src)
var e1 = $(CreateTransBackgroundImage(img1, img1.width, img1.height))
.css({
position: 'absolute',
left: Math.round((width - img1.width) / 2),
top: Math.round((height - img1.height) / 2),
border: '1px solid red'
});
//var e2 = $('<img\/>').attr('src', img2.src)
var e2 = $(CreateTransBackgroundImage(img2, img2.width, img2.height))
.css({
position: 'absolute',
left: Math.round((width - img2.width) / 2),
top: Math.round((height - img2.height) / 2),
border: '1px solid green'
});
var container = $('<div><\/div>')
.css({
position: 'relative',
width: width,
height: height
})
.append(e1, e2);
var slider = $('<div><\/div>')
.css({
width: width
})
.slider({
value: 100,
slide: function(event, ui) {
$(e2).css('opacity', ui.value / 100);
}
});
$('#cmp_onion')
.html('')
.append(container, slider);
}
function cmp_diff(img1, img2) {
var width = Math.max(img1.width, img2.width);
var height = Math.max(img1.height, img2.height);
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(0, 0, 0)';
ctx.fillRect(0, 0, width, height);
ctx.drawImage(img1,
Math.round((width - img1.width) / 2),
Math.round((height - img1.height) / 2));
var imgdata1 = ctx.getImageData(0, 0, width, height);
ctx.fillStyle = 'rgb(0, 0, 0)';
ctx.fillRect(0, 0, width, height);
ctx.drawImage(img2,
Math.round((width - img2.width) / 2),
Math.round((height - img2.height) / 2));
var imgdata2 = ctx.getImageData(0, 0, width, height);
var imgdiff = ctx.createImageData(width, height);
var x, y;
for (y = 0; y < img1.height; ++y) {
for (x = 0; x < img1.width; ++x) {
var p1 = ImageDataGetPixel(imgdata1, x, y);
var p2 = ImageDataGetPixel(imgdata2, x, y);
ImageDataSetPixel(imgdiff, x, y, DiffPixel(p1, p2));
}
}
ctx.putImageData(imgdiff, 0, 0);
$('#cmp_diff')
.html('')
.append(canvas);
}
function MakeDiff() {
var img1_url = document.getElementById('img1_url').value;
var img2_url = document.getElementById('img2_url').value;
$.when(LoadImage(img1_url), LoadImage(img2_url))
.done(function(img1, img2) {
cmp_2up(img1, img2);
cmp_swipe(img1, img2);
cmp_onion(img1, img2);
try {
cmp_diff(img1, img2);
} catch (e) {
$('#cmp_diff').html(e.toString());
}
});
}
</script>
</head>
<body>
<div>
img1: <input id="img1_url" name="img1_url" type="text" value="" /><br />
img2: <input id="img2_url" name="img2_url" type="text" value="" /><br />
<button type="button" onclick="MakeDiff();">load</button>
<button type="button" onclick="$('#img1_url').val('https://github.com/cameronmcefee/Image-Diff-View-Modes/raw/8bf009f5e2aaf3c363d64d4e013527589c810b7e/1_normal.jpg'); $('#img2_url').val('https://github.com/cameronmcefee/Image-Diff-View-Modes/raw/8e95f70c9c47168305970e91021072673d7cdad8/1_normal.jpg'); MakeDiff();">1</button>
<button type="button" onclick="$('#img1_url').val('https://github.com/cameronmcefee/Image-Diff-View-Modes/raw/8bf009f5e2aaf3c363d64d4e013527589c810b7e/2_transparentPixels.png'); $('#img2_url').val('https://github.com/cameronmcefee/Image-Diff-View-Modes/raw/8e95f70c9c47168305970e91021072673d7cdad8/2_transparentPixels.png'); MakeDiff();">2</button>
<button type="button" onclick="$('#img1_url').val('https://github.com/cameronmcefee/Image-Diff-View-Modes/raw/8bf009f5e2aaf3c363d64d4e013527589c810b7e/3_tooLarge.jpg'); $('#img2_url').val('https://github.com/cameronmcefee/Image-Diff-View-Modes/raw/8e95f70c9c47168305970e91021072673d7cdad8/3_tooLarge.jpg'); MakeDiff();">3</button>
<button type="button" onclick="$('#img1_url').val('https://github.com/cameronmcefee/Image-Diff-View-Modes/raw/8bf009f5e2aaf3c363d64d4e013527589c810b7e/4_differentSize.jpg'); $('#img2_url').val('https://github.com/cameronmcefee/Image-Diff-View-Modes/raw/8e95f70c9c47168305970e91021072673d7cdad8/4_differentSize.jpg'); MakeDiff();">4</button>
</div>
<h3>2up</h3>
<div id="cmp_2up"></div>
<h3>swipe</h3>
<div id="cmp_swipe"></div>
<h3>onion</h3>
<div id="cmp_onion"></div>
<h3>diff (don't work for other domain's image due to security reason)</h3>
<div id="cmp_diff"></div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment