How to Compress Images in the Browser with Canvas API
Every image you upload to a "free" online compressor is sent to a server — often without you knowing what happens to it afterward. For a tool that processes your private photos, that's a terrible design.
Here's how to build (or use) an image compressor that runs entirely in the browser using the HTML5 Canvas API. No uploads, no server costs, and unlimited file sizes.
The Core Technique: Canvas toBlob()
The key API is HTMLCanvasElement.toBlob():
js
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
}, 'image/jpeg', 0.8);
};
img.src = 'your-image.jpg';
The second parameter is the MIME type (image/jpeg, image/png, image/webp, image/avif). The third is quality (0–1).
Step-Down Resizing for Large Images
If you're compressing a 6000×4000 px photo, drawing it at full resolution onto a canvas can eat 70+ MB of memory. Step-down resizing halves the dimensions repeatedly:
function stepDownEncode(img, maxDim, quality) {
let w = img.naturalWidth;
let h = img.naturalHeight;
let src = img;
while (w > maxDim * 2 || h > maxDim * 2) {
w = Math.floor(w / 2);
h = Math.floor(h / 2);
const temp = document.createElement('canvas');
temp.width = w;
temp.height = h;
temp.getContext('2d').drawImage(src, 0, 0, w, h);
src = temp;
}
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
canvas.getContext('2d').drawImage(src, 0, 0, w, h);
return new Promise((resolve) => {
canvas.toBlob((blob) => resolve(blob), 'image/jpeg', quality);
});
}
This prevents memory crashes and actually produces better quality (step-down preserves more detail than a single jump).
Comparing Real-World Results
Format Avg Original Avg Compressed Avg Savings
JPEG → JPEG (Q80) 3.2 MB 0.8 MB 75%
PNG → WebP (Q85) 4.8 MB 0.6 MB 87%
JPEG → AVIF (Q70) 3.2 MB 0.4 MB 87%
WebP consistently beats JPEG at the same visual quality by 25–35%. AVIF beats WebP by another 20–30%.
The Production Tool
If you don't want to build your own, the ToolBox Image Compressor (https://toolboximage.com/compressor/) implements all of this with a clean UI — drag & drop, batch processing (up to 200 images), side-by-side preview, and target-size compression. It's free, processes everything locally, and supports JPEG/PNG/WebP/AVIF/GIF input.
Key Takeaways
1. canvas.toBlob() is all you need for basic compression
2. Step-down resizing prevents memory issues on large images
3. WebP offers the best quality/size tradeoff for web use today
4. Client-side compression means zero server cost and zero privacy risk
Try the tool at toolboximage.com/compressor/ (https://toolboximage.com/compressor/)
Top comments (0)