My most-used tool shrinks images without sending a single byte anywhere. Here's the 30 lines of JavaScript that do it.
Every image compressor you've used uploads your photo to a server, compresses it there, and sends it back. That works — but it means your photos leave your device.
I built the Image Compressor on Toolenix to do the whole job in the browser. No upload, no server, no waiting on a network. Here's how it works.
The core idea: canvas does the work
The browser's <canvas> element can decode an image, redraw it at a smaller size, and export it as a compressed JPEG — all locally. That's the entire trick. Three steps:
- Read the file into an
<img>withURL.createObjectURL. - Draw it onto a canvas at the target dimensions.
- Export with
canvas.toBlob()at a quality setting you choose.
The code
Here's the heart of it — a function that takes a file and a target width, and returns a compressed blob:
async function compressImage(file, maxWidth = 1920, quality = 0.8) { const img = await loadImage(file); // Keep the aspect ratio, shrink only if larger than maxWidth const scale = Math.min(1, maxWidth / img.width); const width = Math.round(img.width * scale); const height = Math.round(img.height * scale); const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, width, height); // toBlob with 'image/jpeg' + quality does the compression return new Promise((resolve) => { canvas.toBlob(resolve, 'image/jpeg', quality); }); } function loadImage(file) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = reject; img.src = URL.createObjectURL(file); }); } Quality 0.8 is the sweet spot in my experience: files shrink dramatically with no visible difference for web use. Drop to 0.6 for thumbnails, raise to 0.9 when quality matters more than size.
The details that make it feel like a real tool
The compression is the easy part. The UX around it is what makes people come back:
- Drag and drop — handle
dragover/dropevents, accept multiple files at once. - Before/after sizes — show the original KB and the compressed KB side by side. People love seeing "2.4 MB → 380 KB".
- Batch download — loop over files, compress each, and offer a single ZIP or individual downloads.
- Memory hygiene — call
URL.revokeObjectURL()after you're done, or a long session leaks memory with every image.
Why client-side wins for tools like this
- Privacy: a photo never leaves the device. For personal photos, that's the feature.
- Speed: no upload time, no queue, no server round-trip. Compression of a typical photo takes well under a second.
- Cost: static hosting. No server to scale, no bandwidth bill for other people's photos.
- Reliability: nothing to go down. If the page loads, the tool works — even offline after the first load.
The limits (honestly)
Canvas compression isn't magic. It can't beat a dedicated encoder on every image, PNG transparency needs care (JPEG has no alpha channel — draw onto a white background first or keep PNG output), and very large images can still spike memory. For a free web tool, though, it's more than good enough.
Try it
The compressor is live at toolenix.com — free, no sign-up, and your images never leave your browser. The whole site is built on the same idea: 113 tools, all client-side.
