Convert image to a somewhat NES-style image:
xxxxxxxxxx
<meta charset="utf-8">
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.10/d3.min.js"></script>
<script src="nes-palette.js"></script>
<script type="text/javascript">
var width = 480,
height = 640,
pixelSize = 4,
batchSize = pixelSize * 2,
imageData;
nesColors = nesColors.map(rgbToLab);
var ctx = d3.select("body").append("canvas")
.attr("width",width * 2)
.attr("height",height)
.node()
.getContext("2d");
var img = new Image();
var batches = [];
d3.range(0,width,batchSize).map(function(x){
d3.range(0,height,batchSize).map(function(y){
batches.push({x: x, y: y});
});
});
d3.shuffle(batches);
img.onload = function() {
ctx.drawImage(img,0,0,width,height);
imageData = ctx.getImageData(0,0,width,height);
ctx.putImageData(imageData,width,0);
setTimeout(processBatch,500);
};
img.src = "magritte.jpg";
d3.select(self.frameElement).style("height", height + "px");
// Process one batch of pixels
function processBatch() {
var batch = batches.pop();
d3.range(0,batchSize,pixelSize).forEach(function(x){
d3.range(0,batchSize,pixelSize).forEach(function(y){
processPixel(batch.x + x,batch.y + y);
});
});
// Repaint occasionally
if (batches.length % 12 === 1) {
ctx.putImageData(imageData,width,0);
requestAnimationFrame(processBatch);
} else if (batches.length) {
processBatch();
}
// Could do a second pass to re-round colors to most common results
}
// Average sub-pixels, update each one to the collective average
function processPixel(px,py) {
var indices = [];
d3.range(pixelSize).map(function(x){
d3.range(pixelSize).map(function(y){
indices.push(4 * ((py + y) * width + px + x));
});
});
var average = averageColor(indices.map(function(i){
return imageData.data.slice(i,i + 3);
}));
indices.forEach(function(i){
for (var j = 0; j < 4; j++) {
imageData.data[i + j] = average[j];
}
});
}
// Average colors, then round to nearest in palette
function averageColor(colors) {
var lab = colors.map(rgbToLab);
var average = d3.range(3).map(function(i){
return d3.mean(lab.map(function(color){
return color[i];
}));
});
var closest = closestPoint(average,nesColors);
var rgb = d3.lab.apply(null,closest).rgb();
return [rgb.r,rgb.g,rgb.b,255];
}
// Closest point from list - faster than sort?
function closestPoint(point,list) {
var minDistance = Infinity,
value;
list.forEach(function(p){
var distance = euclidean(point,p);
if (distance < minDistance) {
minDistance = distance;
value = p;
}
});
return value;
};
// Distance between n-dimensional points
function euclidean(a,b) {
var sum = 0;
a.forEach(function(val,i){
sum += Math.pow(b[i] - val,2);
});
return Math.sqrt(sum);
}
function rgbToLab(rgb) {
var lab = d3.lab(d3.rgb.apply(null,rgb));
return [lab.l,lab.a,lab.b];
}
</script>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.10/d3.min.js