I found this script for converting an image to black and white, which works great, but I was hoping to understand the code a little bit better. I put my questions in the code, i
The canvas functions are, like most functions, described in an official specification. Also, MDC is helpful for more "informal" articles. E.g. the drawImage
function on MDC is here.
The getImageData
function returns an object, which contains an array with the byte data of all pixels. Each pixel is described by 4 bytes: r
, g
, b
and a
.
r
, g
and b
are the color components (red, green and blue) and alpha is the opacity. So each pixel uses 4 bytes, and therefore a pixel's data begins at pixel_index * 4
.
Yes, it's averaging the values. Because in the next 3 lines r
, g
and b
are all set to that same value, you'll obtain a gray color for each pixel (because the amount of all 3 components are the same).
So basically, for all pixels this will hold: r === g
, g === b
and thus also r === b
. Colors for which this holds are grayscale (0, 0, 0
being black and 255, 255, 255
being white).
function grayscale(src){ //Creates a canvas element with a grayscale version of the color image
//create canvas
var canvas = document.createElement('canvas');
//get its context
var ctx = canvas.getContext('2d');
//create empty image
var imgObj = new Image();
//start to load image from src url
imgObj.src = src;
//resize canvas up to size image size
canvas.width = imgObj.width;
canvas.height = imgObj.height;
//draw image on canvas, full canvas API is described here http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html
ctx.drawImage(imgObj, 0, 0);
//get array of image pixels
var imgPixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
//run through all the pixels
for(var y = 0; y < imgPixels.height; y++){
for(var x = 0; x < imgPixels.width; x++){
//here is x and y are multiplied by 4 because every pixel is four bytes: red, green, blue, alpha
var i = (y * 4) * imgPixels.width + x * 4; //Why is this multiplied by 4?
//compute average value for colors, this will convert it to bw
var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
//set values to array
imgPixels.data[i] = avg;
imgPixels.data[i + 1] = avg;
imgPixels.data[i + 2] = avg;
}
}
//draw pixels according to computed colors
ctx.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
return canvas.toDataURL();
}
In this function coefficient equal to 1/3 are used, however the usually used are: 0.3R + 0.59G + 0.11B (http://gimp-savvy.com/BOOK/index.html?node54.html).