Create Stunning Image Filters with Canvas: From Basics to Convolution
This tutorial explains how to implement common image filters such as red, grayscale, and inverse effects using the Canvas API, then introduces convolution fundamentals to achieve advanced effects like edge detection and sharpening, complete with code samples and visual results.
Preface
Filters are used to achieve various image effects such as grayscale, color inversion, black‑white, mosaic, sharpening, etc. While Photoshop provides these functions, front‑end developers can implement them easily with the Canvas API. This article first shows simple filter examples, then introduces convolution basics for more complex effects.
1. Basics
1. Canvas API used in image processing
clearRect(x, y, width, height) – clears the specified rectangle.
drawImage(img, x, y, width, height) – draws an image onto the canvas.
getImageData(x, y, width, height) – returns pixel data of the specified rectangle.
putImageData(imgData, x, y) – puts image data back onto the canvas.
2. Processing flow
Code:
<code><canvas id="my_canvas"></canvas>
// filter function
function filter(imageData, ctx) {
// todo... process imageData
return imageData;
}
let img = new Image();
img.src = "img.jpg";
img.onload = function () {
let myCanvas = document.querySelector("#my_canvas");
myCanvas.width = 400;
myCanvas.height = 300;
let myContext = myCanvas.getContext("2d");
// draw image onto canvas
myContext.drawImage(img, 0, 0, myCanvas.width, myCanvas.height);
// get pixel data
let imageData = myContext.getImageData(0, 0, myCanvas.width, myCanvas.height);
// process pixel data
imageData = filter(imageData, myContext);
// put processed data back
myContext.putImageData(imageData, 0, 0);
};</code>The processing flow is simple, but how do we manipulate the pixel data?
3. Understanding pixel data
<code>// Get a 2x2 pixel block
let imageData = ctx.getImageData(0, 0, 2, 2);
console.log(imageData);
</code>getImageData returns an
ImageDataobject that contains a copy of the pixel data for the specified rectangle. Each pixel consists of four components (RGBA). The RGBA values are:
R – red (0‑255; 0 is black, 255 is pure red)
G – green (0‑255; 0 is black, 255 is pure green)
B – blue (0‑255; 0 is black, 255 is pure blue)
A – alpha (transparency) (0‑255; 0 is fully transparent, 255 is fully opaque)
2. Implementing filters
With pixel data understood, we can modify it inside the
filterfunction. Below are three simple filters applied to an example image.
1. Red filter
Keeps the red channel unchanged while setting green and blue to 0.
<code>function filter(imageData, ctx) {
let len = imageData.data.length / 4; // 4 values per pixel
for (let i = 0; i < len; i++) {
// imageData.data[i * 4 + 0] = red (unchanged)
imageData.data[i * 4 + 1] = 0; // green
imageData.data[i * 4 + 2] = 0; // blue
}
return imageData;
}
</code>Result:
2. Grayscale filter
Sets R, G, B to the average of the three channels.
<code>function filter(imageData, ctx) {
let len = imageData.data.length / 4;
for (let i = 0; i < len; i++) {
let newColor = (imageData.data[i*4] + imageData.data[i*4+1] + imageData.data[i*4+2]) / 3;
imageData.data[i*4] = newColor;
imageData.data[i*4+1] = newColor;
imageData.data[i*4+2] = newColor;
}
return imageData;
}
</code>Result:
3. Inverse filter
Replaces each channel with 255 minus its value.
<code>function filter(imageData, ctx) {
let len = imageData.data.length / 4;
for (let i = 0; i < len; i++) {
imageData.data[i*4] = 255 - imageData.data[i*4];
imageData.data[i*4+1] = 255 - imageData.data[i*4+1];
imageData.data[i*4+2] = 255 - imageData.data[i*4+2];
}
return imageData;
}
</code>Result:
These simple filters manipulate the four values of each pixel. More complex filters such as edge detection require convolution.
3. Convolution
Convolution is a common image‑processing technique that applies a kernel to each pixel to produce effects such as edge detection, sharpening, blur, emboss, etc.
1. Convolution process
Convolution uses a kernel (usually a 3×3 matrix) that is centered on each target pixel. The kernel’s elements are multiplied by the corresponding image pixel values, summed, and the result becomes the new pixel value.
When the kernel moves across the image, the output size shrinks (e.g., a 6×6 image with a 3×3 kernel yields a 4×4 output). Padding—adding a border of zeros—prevents size reduction.
2. Kernel characteristics
Size should be odd (e.g., 3×3, 5×5) so it has a central element.
Each element is a weight that determines the contribution of the corresponding pixel.
If the sum of all weights equals 1, overall brightness stays unchanged.
Sum > 1 brightens the image; sum < 1 darkens it; sum = 0 yields a very dark image.
3. Edge detection
An edge‑detection kernel typically has 8 in the center and -1 around it.
Applying this kernel highlights areas with strong color differences; uniform regions become black while edges appear bright.
<code>function convolutionMatrix(output, input, kernel) {
let w = input.width, h = input.height;
let iD = input.data, oD = output.data;
for (let y = 1; y < h - 1; y++) {
for (let x = 1; x < w - 1; x++) {
for (let c = 0; c < 3; c++) {
let i = (y * w + x) * 4 + c;
oD[i] = kernel[0] * iD[i - w*4 - 4] +
kernel[1] * iD[i - w*4] +
kernel[2] * iD[i - w*4 + 4] +
kernel[3] * iD[i - 4] +
kernel[4] * iD[i] +
kernel[5] * iD[i + 4] +
kernel[6] * iD[i + w*4 - 4] +
kernel[7] * iD[i + w*4] +
kernel[8] * iD[i + w*4 + 4];
}
oD[(y * w + x) * 4 + 3] = 255; // alpha
}
}
return output;
}
function filter(imageData, ctx) {
let kernel = [-1,-1,-1,-1,8,-1,-1,-1,-1]; // edge‑detection kernel
return convolutionMatrix(ctx.createImageData(imageData), imageData, kernel);
}
</code>Using a different kernel yields other effects, such as sharpening with a central value of 9.
<code>let kernel = [-1,-1,-1,-1,9,-1,-1,-1,-1]; // sharpening kernel</code>4. Summary
Image processing with Canvas is fun; you can also capture video from the camera via
navigator.mediaDevices, apply filters in real time, and draw the result back to the canvas. Understanding convolution opens the door to neural networks and deep learning, where convolution is a fundamental operation.
Demo
https://wqs.jd.com/demo/filter/index.html
WecTeam
WecTeam (维C团) is the front‑end technology team of JD.com’s Jingxi business unit, focusing on front‑end engineering, web performance optimization, mini‑program and app development, serverless, multi‑platform reuse, and visual building.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.