Subscribe

Checkboxify your images with JavaScript ✅

✍️

Making art using canvas and JavaScript magic

23 Sep, 2020 · 4 min read

Lately, we have been on a journey with Canvas and have learned the following elements of it:

Today, we are doing something indirectly using canvas, and this has been something that's been on my mind for a long time!

We are creating checkbox art! ✅

I don't know if this was an official art form, but now it is.

The result will look like this:

Checkbox art with JavaScript

HTML Structure

As for our HTML, we need our sample image, a canvas to use, and our output div.

<img
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600097347472/FaJTB7UrN.jpeg"
  id="eeveelutions"
/>
<canvas id="canvas" width="100" height="100"></canvas>
<div id="output"></div>

In this case, the image is 200x200, The canvas is 100x100, and the output will become 400x400.

CSS Styling

Because we are using checkboxes to style, I am floating them to make them snap to each other. And I am using <br /> to create a new row. The br will act as a clear for the float.

body {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
  padding: 0;
}
canvas {
  opacity: 0;
}
input {
  width: 4px;
  height: 4px;
  margin: 0;
  padding: 0;
  float: left;
}
br {
  clear: both;
}
#output {
  width: 400px;
  line-height: 0px;
}

In our canvas, we are hiding by setting the opacity to 0.

JavaScript checkboxify your images

First, let's define all our variables.

const img = document.getElementById('eeveelutions');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const output = document.getElementById('output');
let loaded = 0;

Now we need to listen to our image load before acting on it.

img.onload = function () {
  loaded++;
  // Do stuff
};

We count when the image gets loaded because it will fire twice, the actual load and once it gets drawn on the canvas.

Next up, we can add the image to the canvas.

ctx.drawImage(img, 0, 0, 100, 100);

The parameters of this are: (source, x, y, width, height)

Ok, so we now have our canvas, and the image is drawn on it. We must then check if it's the second load and start doing some magic inside that load.

if (loaded > 1) {
  // The second draw on the canvas
}

We can then get the image data from the canvas. (x, y, width, height)

const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);

I'll now show you the rest of the function.

let j = 0;
for (i = 0; i < imgData.data.length; i += 4) {
  let count = imgData.data[i] + imgData.data[i + 1] + imgData.data[i + 2];

  let _break = document.createElement('br');
  let checkbox = document.createElement('INPUT');
  checkbox.setAttribute('type', 'checkbox');
  checkbox.checked = true;
  if (count > 383) checkbox.checked = false;

  output.appendChild(checkbox);
  j++;
  if (j === 100) {
    j = 0;
    output.appendChild(_break);
  }
}

We use the j parameter to count the rows, so every 100 lines are 1 row, so we need to add a <br /> element.

The main loop only loops over every element since the image data API gives us rgba values for each pixel, so four values define 1 pixel.

Then we count the colors of our rgba pixel by adding the first three (r g b).

And check if this pixel is a black or a white pixel by checking if it's bigger than 383 (half of 255+255+255).

Then we create a checkbox, and if our pixel is black, we check it.

Last we add our checkbox to the output div, and if needed, add our row break.

There you go, have a play around on this Codepen.

See the Pen Checkbox by Chris Bongers (@rebelchris) on CodePen.

Browser Support

The image data API, as well as canvas, have outstanding support!

HTML Canvas imageData support

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Spread the knowledge with fellow developers on Twitter
Tweet this tip
Powered by Webmentions - Learn more

Read next 📖

TypeORM viewEntity

30 Mar, 2022 · 5 min read

TypeORM viewEntity

The Record Utility Type in TypeScript

12 Mar, 2022 · 3 min read

The Record Utility Type in TypeScript

Join 1371 devs and subscribe to my newsletter