Reading Pixel Data from Images Using Canvas โ Histograms and Color Analysis
The Canvas API gives you direct access to every pixel in an image. Here's how to use that for real analysis: histograms, channel separation, and precise color picking.
Getting Raw Pixel Data
function getImageData(imageFile) {
return new Promise((resolve) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
resolve(ctx.getImageData(0, 0, img.width, img.height));
};
img.src = URL.createObjectURL(imageFile);
});
}
getImageData() returns a flat Uint8ClampedArray with 4 values per pixel: [R, G, B, A, R, G, B, A, ...].
Building a Histogram
A histogram counts how many pixels have each brightness value (0โ255):
function buildHistogram(imageData) {
const r = new Array(256).fill(0);
const g = new Array(256).fill(0);
const b = new Array(256).fill(0);
const luma = new Array(256).fill(0);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
r[data[i]]++;
g[data[i + 1]]++;
b[data[i + 2]]++;
// Perceptual luminance (BT.601)
const l = Math.round(0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2]);
luma[l]++;
}
return { r, g, b, luma };
}
The luma formula uses BT.601 weights, which match human perception โ green contributes most to perceived brightness.
Channel Separation
To show each color channel as a grayscale image:
function extractChannel(imageData, channel) {
const result = new ImageData(imageData.width, imageData.height);
const src = imageData.data;
const dst = result.data;
const offset = { r: 0, g: 1, b: 2, a: 3 }[channel];
for (let i = 0; i < src.length; i += 4) {
const value = src[i + offset];
dst[i] = dst[i + 1] = dst[i + 2] = value;
dst[i + 3] = 255;
}
return result;
}
Pixel Color Picker
Get the exact color at a mouse position:
function getPixelColor(canvas, x, y) {
const ctx = canvas.getContext('2d');
const pixel = ctx.getImageData(x, y, 1, 1).data;
const [r, g, b, a] = pixel;
const hex = '#' + [r, g, b].map(v => v.toString(16).padStart(2, '0')).join('');
return { r, g, b, a, hex };
}
Gotcha: The coordinates must be relative to the canvas element, not the page. Use getBoundingClientRect() to convert mouse coordinates.
Analyze your images at toolzip.app/tools/image-inspector.