Build a Simple Photo Blur Tool

This is the core technique behind Haven Toolbox's Image Redact tool, stripped down to the basics: load an image onto a canvas, then pixelate part of it. No server, no upload, just the Canvas API.

The HTML: a file input and a canvas

<input type="file" id="fileInput" accept="image/*">
<canvas id="canvas"></canvas>
<button id="pixelateBtn">Pixelate center</button>
<button id="downloadBtn">Download</button>

Load the image onto the canvas

const fileInput = document.querySelector('#fileInput');
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');

fileInput.addEventListener('change', () => {
  const file = fileInput.files[0];
  const img = new Image();
  img.onload = () => {
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage(img, 0, 0);
  };
  img.src = URL.createObjectURL(file);
});

Picking a file fires the change event, which loads it into an Image object and draws it onto the canvas once it's ready. The canvas is resized to match the image so nothing gets cropped.

Pixelate a region

This pixelates the middle third of the image, in blocks of 12 pixels. For each block, it averages every pixel's color, then paints the whole block back with that single average color:

document.querySelector('#pixelateBtn').addEventListener('click', () => {
  const x = canvas.width / 3;
  const y = canvas.height / 3;
  const w = canvas.width / 3;
  const h = canvas.height / 3;
  const blockSize = 12;

  const imageData = ctx.getImageData(x, y, w, h);
  const data = imageData.data;

  for (let by = 0; by < h; by += blockSize) {
    for (let bx = 0; bx < w; bx += blockSize) {
      let r = 0, g = 0, b = 0, count = 0;

      for (let dy = 0; dy < blockSize && by + dy < h; dy++) {
        for (let dx = 0; dx < blockSize && bx + dx < w; dx++) {
          const i = ((by + dy) * w + (bx + dx)) * 4;
          r += data[i]; g += data[i + 1]; b += data[i + 2];
          count++;
        }
      }
      r /= count; g /= count; b /= count;

      for (let dy = 0; dy < blockSize && by + dy < h; dy++) {
        for (let dx = 0; dx < blockSize && bx + dx < w; dx++) {
          const i = ((by + dy) * w + (bx + dx)) * 4;
          data[i] = r; data[i + 1] = g; data[i + 2] = b;
        }
      }
    }
  }

  ctx.putImageData(imageData, x, y);
});

getImageData returns the raw pixel values for that region as a flat array, four numbers (red, green, blue, alpha) per pixel. The nested loops walk the region block by block, average the colors inside each one, then write that average back over every pixel in the block. putImageData paints the result back onto the canvas.

Download the result

document.querySelector('#downloadBtn').addEventListener('click', () => {
  canvas.toBlob(blob => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'pixelated.png';
    a.click();
    URL.revokeObjectURL(url);
  });
});

canvas.toBlob turns the canvas into an image file in memory, which gets handed to a temporary link and clicked programmatically to trigger the download.

Where to go from here

This version pixelates a fixed region in the middle of the image. A real tool would let you drag out the exact area yourself, offer blur and blackout as alternatives, and keep an undo history, which is exactly what Haven Toolbox's Image Redact tool does. See the local-only guide for more on why none of this needs a server.

← back to guides