The problem I kept running into
Every time I needed to resize a photo for a passport application, an exam form, or just to shrink a screenshot before sharing it, I ended up on some random "free" image tool that:
- Uploaded my photo to their server (privacy, anyone?)
- Buried the download button under three ad banners
- Forced me to sign up for a "free" account
- Randomly failed on files over 2MB
So I built ResizeHub — a completely free, browser-based image toolkit that resizes, compresses, and converts images without ever sending your file to a server. Everything happens client-side, in your browser, using the Canvas API.
Here's a breakdown of how it works and why client-side image processing is a genuinely underrated approach for web tools.
Why process images in the browser instead of on a server?
Most "free" image tools follow the same pattern: user uploads file → server processes it → server sends back a result. That's simple to build, but it comes with real costs:
- Privacy risk — your image (which might contain a face, ID document, or signature) sits on someone else's server, even if briefly
- Server cost — every resize operation burns compute and bandwidth on the backend, which is why most of these tools carry ads or paywalls
- Latency — upload time + processing time + download time, especially painful on slow connections
- Scalability ceiling — more users means more server load, so free tiers get throttled fast
Doing it client-side flips all of this:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = () => {
canvas.width = targetWidth;
canvas.height = targetHeight;
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
canvas.toBlob((blob) => {
// blob is your resized image — ready to download
// it never left the browser
}, 'image/jpeg', quality);
};
img.src = URL.createObjectURL(userFile);
That's genuinely most of the core logic. The Canvas API gives you pixel-level control over dimensions, and toBlob() lets you control output quality and format entirely on the client.
Handling exact file-size targets (the hard part)
Resizing to exact dimensions is easy. Resizing to an exact file size (a common requirement for government exam forms — "signature must be under 20KB") is trickier, because JPEG compression quality doesn't map linearly to output size.
The approach that works well is a binary search over the quality parameter:
async function compressToTargetSize(canvas, targetKB, mimeType = 'image/jpeg') {
let min = 0, max = 1, quality = 0.7;
let result;
for (let i = 0; i < 8; i++) {
result = await new Promise((resolve) =>
canvas.toBlob(resolve, mimeType, quality)
);
const sizeKB = result.size / 1024;
if (Math.abs(sizeKB - targetKB) < 2) break;
if (sizeKB > targetKB) {
max = quality;
} else {
min = quality;
}
quality = (min + max) / 2;
}
return result;
}
Eight iterations of binary search converge close enough for practical purposes, and it all runs in milliseconds since there's no network round trip.
Format conversion without a backend
Converting between formats (PNG ↔ JPEG ↔ WebP) is just a matter of changing the MIME type passed to toBlob() — the browser's built-in codecs handle the actual encoding. No image-processing library, no server, no dependency bloat.
For formats the Canvas API doesn't natively support (like HEIC, common on iPhone photos), a lightweight WASM decoder can convert to a canvas-compatible format first, still entirely client-side.
What this approach is good and bad for
Good for: resizing, compressing, cropping, format conversion, basic adjustments — anything the Canvas API can express as pixel operations.
Not great for: heavy AI operations like background removal or upscaling, which genuinely need a model running somewhere. Those still need a server (or an on-device ML model, which is a whole separate rabbit hole).
Try it
I packaged this into a free toolkit at resizehub.in — includes image resize/compress, exact-KB compression for exam forms, passport/signature photo presets, and format conversion. No signup, no upload limits since nothing uploads in the first place.
If you're building something similar or have ideas for improving the compression algorithm, I'd genuinely like to hear about it in the comments.
Top comments (5)
The "nothing uploads, so there's nothing to limit" framing is exactly right, and I arrived at the identical conclusion from the other side of the world. I build internal tools for a hospital (physical therapist, not an engineer — everything's written with AI), and one of them is a client-side image resizer for the same reason: the moment you're handling anything near patient photos, "we'll process it on our server" isn't a feature, it's a liability. Client-side wasn't the clever choice, it was the only choice that let the tool exist at all.
Your binary-search-on-JPEG-quality detail made me grin, because I hit that exact wall. Korean government and hospital forms are merciless about it — "photo must be under 100KB," hard limit, upload rejected otherwise. Nudging quality by hand is hopeless; binary search converging in ~8 steps is the clean answer, and it's the kind of trick that looks trivial until you're the one staring at a form that won't accept your file.
One thing I'll offer back: the failure mode my staff hit wasn't size, it was orientation — phone photos carry EXIF rotation, and canvas silently drops it, so faces came out sideways. Reading the EXIF orientation and applying it before the resize saved me a second round of confused bug reports. Might save you one too.
Genuinely good build. "Free" tools that respect the file are rarer than they should be.
Thanks! I really appreciate your feedback. I built ResizeHub for the same reason—privacy and speed. I'll definitely look into EXIF orientation support as you suggested. Thanks for sharing your experience!
Happy to help — that one cost me a round of "why is everyone sideways?" reports, so it's worth passing on. One heads-up when you add it: browsers are inconsistent about whether they auto-apply EXIF rotation to an
versus a canvas, so the safe move is to strip the EXIF orientation tag after you bake the rotation into the actual pixels — otherwise a corrected image can get double-rotated by the next viewer that reads the tag. Good luck with ResizeHub. The privacy-first version of these tools deserves to win.
Thanks again! That's a really valuable tip. I'll implement proper EXIF handling in ResizeHub and test it across browsers. I appreciate you taking the time to explain it.
Anytime — good luck with it. Rooting for the privacy-first version to win.