Skip to content

Instantly share code, notes, and snippets.

@veltman
Created May 28, 2017 20:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save veltman/1298cabd1ffd10c9c15d99a8395c6957 to your computer and use it in GitHub Desktop.
Save veltman/1298cabd1ffd10c9c15d99a8395c6957 to your computer and use it in GitHub Desktop.
Quadtree pixelation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
<canvas width="960" height="500"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
let width = 960,
height = 500,
canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
active = width * height,
img = new Image(),
tree = d3.quadtree()
.extent([[0, 0], [width, height]]);
img.onload = draw;
img.src = "neon.jpg";
function draw() {
context.drawImage(img, 0, 0);
let data = context.getImageData(0, 0, width, height).data;
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
tree.add(colorAt(data, x, y));
}
}
setAverageColor(tree.root());
depixelate(tree.root());
}
function depixelate(node, x=0, y=0, w=(tree._x1 - tree._x0), h=(tree._y1 - tree._y0), depth=1) {
context.fillStyle = "rgb(" + node.color.map(d => Math.round(d)) + ")";
context.fillRect(x, y, w, h);
if (node.length) {
node.forEach((child, i) => {
let cw = w / 2,
ch = h / 2,
cx = i % 2 ? x + cw : x,
cy = i > 1 ? y + ch : y;
setTimeout(() => depixelate(child, cx, cy, cw, ch, depth + 1), depth > 7 ? 0 : d3.randomExponential(1 / 1000)());
});
} else {
active--;
if (!active) {
active = width * height;
setTimeout(() => depixelate(tree.root()), 500);
}
}
}
function setAverageColor(node) {
if (!node.length) {
return node.color = node.data.slice(2);
}
return node.color = arrayMean(node.filter(d => d).map(setAverageColor));
}
function arrayMean(arrays) {
let mean = new Array(3).fill(0);
for (let i = 0, l = arrays.length; i < l; i++) {
for (let j = 0; j < 3; j++) {
mean[j] += arrays[i][j] / l;
}
}
return mean;
}
function colorAt(data, x, y) {
let index = y * width + x;
return [x, y, data[index * 4], data[index * 4 + 1], data[index * 4 + 2]];
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment