Canvas 2D Image Processing: Principles and Practice of Browser-Side Pixel Operations
Canvas in Image Processing
The browser offers three image processing paths:
| Approach | Performance | Flexibility | Best For |
|---|---|---|---|
| CSS filter | High (GPU) | Low (preset filters) | Simple visual effects |
| Canvas 2D | Medium | High (pixel-level) | Compression, cropping, format conversion |
| WebGL | Highest | High (requires shaders) | Complex filters, real-time processing |
ToolsKu's image tools (compress, crop, format conversion, watermark) are all built on the Canvas 2D API.
Basic Processing Flow
// 1. Load image
const img = new Image();
img.src = URL.createObjectURL(file);
await img.decode();
// 2. Create Canvas and draw
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d')!;
ctx.drawImage(img, 0, 0);
// 3. Export to target format
const blob = await new Promise<Blob>((resolve) =>
canvas.toBlob(resolve, 'image/webp', 0.85) // quality 85%
);
How Image Compression Works
Canvas compression is essentially re-encoding:
Original PNG (2MB, lossless)
↓ drawImage to Canvas
↓ toBlob('image/jpeg', 0.8)
Compressed JPEG (400KB, lossy 80% quality)
| Format | Compression | Typical Ratio | Transparency |
|---|---|---|---|
| JPEG | Lossy DCT | 60-80% | ❌ |
| WebP | Lossy/lossless | 70-90% | ✅ |
| PNG | Lossless DEFLATE | 10-30% | ✅ |
| AVIF | Lossy/lossless | 80-95% | ✅ |
ToolsKu's Image Compress tool supports batch WebP/JPEG compression. The default quality of 85% balances file size and visual quality.
Pixel-Level Operations
Manipulate RGBA pixels directly via ImageData:
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data; // Uint8ClampedArray, 4 bytes = 1 pixel
for (let i = 0; i < data.length; i += 4) {
// Grayscale
const avg = (data[i] + data[i+1] + data[i+2]) / 3;
data[i] = data[i+1] = data[i+2] = avg;
}
ctx.putImageData(imageData, 0, 0);
OffscreenCanvas Performance Optimization
Main-thread Canvas operations block the UI. OffscreenCanvas can run in a Worker:
// worker.ts
const offscreen = new OffscreenCanvas(width, height);
const ctx = offscreen.getContext('2d')!;
ctx.drawImage(imageBitmap, 0, 0);
const blob = await offscreen.convertToBlob({ type: 'image/webp', quality: 0.85 });
postMessage({ blob }, [blob]); // Transferable
When batch-processing 50 images, OffscreenCanvas + Worker reduces main-thread blocking from 10s to 0.
Common Questions
Why does the image look blurry after compression?
JPEG/WebP lossy compression discards high-frequency detail. Raise the quality parameter (0.9+) or use PNG/WebP lossless mode.
Are there Canvas size limits?
Most browsers cap a single Canvas edge at 16384px, with a total area of about 268MP. Exceeding this requires tiled processing.
How do you handle EXIF orientation?
Photos from phones may include EXIF Orientation. Read EXIF and rotate the Canvas before drawing, or the image will appear sideways. ToolsKu's Image Format Converter handles EXIF automatically.
Summary
Canvas 2D is the standard approach for browser-side image processing. Understanding the drawImage → toBlob encoding pipeline, ImageData pixel operations, and OffscreenCanvas Worker offloading is core to building high-performance image tools.
Try these browser-local tools — no sign-up required →