Grayscaling An HTML5 Canvas

I’ve been looking at how to turn a colour image into a grayscale one using JavaScript on an HTML 5 Canvas. I had done something similar a few years back to an image using Perl.

Wikipedia has a good article on converting colour to grayscale, and it’s very simple formula based on the luminance of the image. The recommendation is to add together 30% of the red value, 59% of the green value and 11% of the blue value.

var luma = red * 0.3 + green * 0.59 + blue * 0.11;

We can easily apply this formula over the ImageData in an HTML 5 Canvas Context object to turn the image held in the Canvas to grayscale. The ImageData.data holds an array with four pieces of data per pixel, the red, the green, the blue and the alpha values. These are integer values between 0 and 255. The code to grayscale the ImageData would look like this.

for (var i = 0; i < imageData.data.length; i+=4) {
  var luma = Math.floor(imageData.data[i] * 0.3 +
  imageData.data[i+1] * 0.59 +
  imageData.data[i+2] * 0.11);
  imageData.data[i] = imageData.data[i+1] = imageData.data[i+2] = luma;
  imageData.data[i+3] = 255;
}

Notice the use of Math.floor(), this is just to round the luminance down into an integer value.

Colour

Grayscale

There is another common way to grayscale an image, and that is to get the red, green and blue pixels to all match. You can pick the colour you want to be the key, for example red, then just make sure the values for the green and blue for each pixel match that of the red one. This is making use of a single channel, and can give very different effects depending on your source image.

To use the red channel we could the following code over some ImageData.

for (var i = 0; i < imageData.data.length; i+=4) {
  imageData.data[i+1] = imageData.data[i+2] = imageData.data[i];
  imageData.data[i+3] = 255;
}

Grayscale Red Channel

To use the green channel, use the following.

for (var i = 0; i < imageData.data.length; i+=4) {
  imageData.data[i] = imageData.data[i+2] = imageData.data[i+1];
  imageData.data[i+3] = 255;
}

Grayscale Green Channel

To use the blue channel, use the following.

for (var i = 0; i < imageData.data.length; i+=4) {
  imageData.data[i] = imageData.data[i+1] = imageData.data[i+2];
  imageData.data[i+3] = 255;
}

Grayscale Blue Channel