Created
July 11, 2010 08:15
-
-
Save rsky/471390 to your computer and use it in GitHub Desktop.
HTML5 Canvasで画像をモザイク化してみた
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
margin: 0; | |
padding: 0; | |
font-family: sans-serif; | |
font-size: 14px; | |
line-height: 100%; | |
background-color: #fff; | |
color: #000; | |
} | |
form#ctl { | |
position: relative; | |
margin: 0; | |
padding: 24px 10px 10px 10px; | |
height: 25px; | |
background-color: #eee; | |
border-bottom: #000 solid 1px; | |
} | |
span#idc { | |
position: absolute; | |
top: 10px; | |
font-family: monospace; | |
font-weight: bold; | |
} | |
input#siz { | |
position: relative; | |
width: 120px; | |
vertical-align: middle; | |
} | |
span.num { | |
display: inline-block; | |
vertical-align: middle; | |
} | |
div#drp { | |
position: absolute; | |
top: 0; | |
right:0; | |
width: 175px; | |
height: 15px; | |
margin: 0; | |
padding: 22px 2px; | |
text-align: center; | |
vertical-align: middle; | |
background-color: #fff; | |
border-left: #000 solid 1px; | |
border-bottom: #000 solid 1px; | |
color: #000; | |
font-weight: bold; | |
} | |
div#drw { | |
margin-top: 10px; | |
text-align: center; | |
} | |
canvas#pat { | |
display: none; | |
} | |
img#img { | |
display: none; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>pixelate</title> | |
<script type="text/javascript" src="pixelate.js"></script> | |
<link rel="stylesheet" type="text/css" href="pixelate.css"> | |
</head> | |
<body onload="activate()"> | |
<form id="ctl" onsubmit="return false"> | |
<span id="idc">16</span> | |
<span id="sld"> | |
<span class="num">1</span> | |
<input id="siz" type="range" min="1" max="100" step="1" value="16"> | |
<span class="num">100</span> | |
</span> | |
<input id="ccl" type="checkbox"><label for="ccl">Circle</label> | |
<input type="button" id="btn" value="OK"> | |
<div id="drp">drop image here</div> | |
</form> | |
<div id="drw"> | |
<canvas id="cnv"></canvas> | |
<canvas id="pat"></canvas> | |
<img id="img" src="example.jpg"> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var btn, ccl, cnv, ctl, idc, img, pat, siz; | |
var tid = null; | |
var $ = function(id){ | |
return document.getElementById(id); | |
}; | |
var text = function(str){ | |
return document.createTextNode(str); | |
}; | |
var pixelate = function(ctx, x, y, width, height, fast){ | |
var image, data, color; | |
if (fast) { | |
image = ctx.getImageData(x, y, 1, 1); | |
data = image.data; | |
color = 'rgb(' + data[0] + ',' + | |
data[1] + ',' + | |
data[2] + ')'; | |
} else { | |
var r, g, b, a, i, l, n; | |
image = ctx.getImageData(x, y, width, height); | |
data = image.data; | |
l = data.length; | |
n = l / 4; | |
r = 0; | |
g = 0; | |
b = 0; | |
a = 0; | |
for (i = 0; i < l; i += 4) { | |
r += data[i]; | |
g += data[i + 1]; | |
b += data[i + 2]; | |
//a += data[i + 3]; | |
} | |
color = 'rgb(' + Math.round(r / n) + ',' + | |
Math.round(g / n) + ',' + | |
Math.round(b / n) + ')'; | |
} | |
ctx.fillStyle = color; | |
ctx.fillRect(x, y, width, height); | |
}; | |
var pixelateImage = function(){ | |
try { | |
pixelateImageDo(); | |
} catch (e) { | |
alert('Error: ' + e.toString()); | |
} | |
}; | |
var pixelateImageDo = function(){ | |
var ctx, size, width, height; | |
var x, y, z, xlen, ylen, xmod, ymod; | |
ctx = cnv.getContext('2d'); | |
width = img.width; | |
height = img.height; | |
cnv.width = width; | |
cnv.height = height; | |
ctx.drawImage(img, 0, 0); | |
size = Math.max(1, Math.min(100, parseInt(siz.value))); | |
if (size < 2) { | |
return; | |
} | |
xmod = width % size; | |
ymod = height % size; | |
xlen = width - xmod; | |
ylen = height - ymod; | |
for (x = 0; x < xlen; x += size) { | |
for (y = 0; y < ylen; y += size) { | |
pixelate(ctx, x, y, size, size); | |
} | |
if (ymod) { | |
pixelate(ctx, x, ylen, size, ymod); | |
} | |
} | |
if (xmod) { | |
for (y = 0; y < ylen; y += size) { | |
pixelate(ctx, xlen, y, xmod, size); | |
} | |
if (ymod) { | |
pixelate(ctx, xlen, ylen, xmod, ymod); | |
} | |
} | |
if (ccl.checked && size > 1) { | |
circularize(ctx, size, width, height); | |
} | |
}; | |
var circularize = function(ctx, size, width, height){ | |
var radius, patctx, patimage, patdata, i, l; | |
pat.width = size; | |
pat.height = size; | |
radius = size / 2; | |
patctx = pat.getContext('2d'); | |
patctx.fillStyle = '#fff'; | |
patctx.beginPath(); | |
patctx.arc(radius, radius, radius, 0, Math.PI * 2, false); | |
patctx.closePath(); | |
patctx.fill(); | |
patimage = patctx.getImageData(0, 0, size, size); | |
patdata = patimage.data; | |
l = patdata.length; | |
for (i = 0; i < l; i += 4) { | |
patdata[i] = 255; | |
patdata[i + 1] = 255; | |
patdata[i + 2] = 255; | |
patdata[i + 3] = 255 - patdata[i + 3]; | |
} | |
patctx.putImageData(patimage, 0, 0); | |
ctx.fillStyle = ctx.createPattern(pat, 'repeat'); | |
ctx.fillRect(0, 0, width, height); | |
}; | |
var finalizeImage = function(){ | |
window.open(cnv.toDataURL('image/png'), | |
null, | |
'width=' + cnv.width + ',height=' + cnv.height); | |
}; | |
var activate = function(){ | |
var drp = $('drp'); | |
btn = $('btn'); | |
ccl = $('ccl'); | |
cnv = $('cnv'); | |
ctl = $('ctl'); | |
idc = $('idc'); | |
img = $('img'); | |
pat = $('pat'); | |
siz = $('siz'); | |
idc.style.left = (siz.offsetLeft + parseInt(siz.value)) + 'px'; | |
drp.addEventListener('dragenter', function(ev){ | |
ev.preventDefault(); | |
this.style.backgroundColor = '#ffa'; | |
return false; | |
}, false); | |
drp.addEventListener('dragover', function(ev){ | |
ev.preventDefault(); | |
return false; | |
}, false); | |
drp.addEventListener('dragleave', function(ev){ | |
ev.preventDefault(); | |
this.style.backgroundColor = '#fff'; | |
return false; | |
}, false); | |
drp.addEventListener('drop', function(ev){ | |
var dt = ev.dataTransfer; | |
ev.stopPropagation(); | |
if (dt.files && dt.files.length) { | |
var re, i, files, length; | |
re = /^image\/(gif|jpeg|png)$/; | |
files = dt.files; | |
length = files.length; | |
for (i = 0; i < length; i++) { | |
if (re.test(files[i].type)) { | |
try { | |
var reader = new FileReader(); | |
reader.onloadend = function(){ | |
img.src = reader.result; | |
img.onload = pixelateImage; | |
}; | |
reader.readAsDataURL(files[i]); | |
} catch (e) { | |
alert('Error: ' + e.toString()); | |
} | |
break; | |
} | |
} | |
} | |
this.style.backgroundColor = '#fff'; | |
return false; | |
}, false); | |
btn.addEventListener('click', finalizeImage, true); | |
ccl.addEventListener('click', pixelateImage, true); | |
siz.addEventListener('change', function(){ | |
var value, offset; | |
if (tid) { | |
clearTimeout(tid); | |
} | |
value = Math.max(1, Math.min(100, parseInt(this.value))); | |
if (value.toString() != this.value) { | |
this.value = value; | |
} | |
offset = this.offsetLeft + value | |
if (value < 10) { | |
offset += 3; | |
} else if (value < 100) { | |
offset += value / 25; | |
} else { | |
offset += 2; | |
} | |
idc.innerHTML = value; | |
idc.style.left = Math.round(offset) + 'px'; | |
tid = setTimeout(function(){ | |
pixelateImage(); | |
tid = null; | |
}, 50); | |
}, true); | |
pixelateImage(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment