Eric Hinzpeter
NOTE· 2026-07-24· 5 min

Why I Stopped Uploading My Photos to Random Online Converters

Most free image converters make you upload your photos to a server you know nothing about, and choke the moment you drop in a RAW or HEIC file. So I built one that never leaves your browser.

Every free image converter I tried let me down the same way. You upload your photo to their server, with no real idea what happens to it after that, how long it sits there, or who else can see it, and the moment you drop in a RAW file off a camera or a HEIC photo straight from an iPhone, most of them just give up and tell you to open Lightroom. The free ones tend to be free because they're covered in ads, which does not help either.

None of that is a huge deal for one holiday photo. It adds up when it's your job, or when the file is a client's product shot you'd rather not hand to a random server. So I built my own image converter, and I made the two annoyances I cared about most the whole point of it: nothing gets uploaded, and RAW and HEIC work without opening any other app.

The upload problem nobody warns you about

Type "convert HEIC to JPG" into Google and the top results all work the same way. You drag your photo onto their page, it disappears for a second, and a converted file comes back. Somewhere in that gap, your photo left your machine and sat on a server you've never heard of, under a privacy policy you didn't read.

Most of the time that's harmless. But I didn't want to think about it every time, especially not when the file was a client's unreleased product shot headed to a free tool with a business model I couldn't identify. The only real fix is no server in the loop at all.

My version reads the file with the browser's own FileReader, draws it into an off-screen canvas, and produces the converted image with canvas.toBlob(), all inside the tab you're already looking at. The file never becomes a network request. There's nothing to upload because there's nowhere to upload it to.

RAW and HEIC are the actual gap

The other problem was narrower but more annoying. Plenty of converters handle JPG, PNG, and WebP just fine. Almost none of them touch a camera's RAW file, and the free HEIC converters that do exist often produce something over-compressed or stripped of the file's real resolution.

That gap matters more than it sounds like, because it's exactly the files that need converting most. A DNG off a drone or a CR2 off a Canon isn't something you can post or email as-is. Neither is an iPhone HEIC, which most non-Apple software still can't open. The usual advice is "just open it in Lightroom," which is a fine answer if you own Lightroom and just want a quick JPG out of one photo, and a bad one if you don't or if you've got a folder of forty.

So the converter needed to read DNG, CR2, CR3, NEF, ARW, RAF, ORF, and RW2 (the RAW formats from Adobe, Canon, Nikon, Sony, Fujifilm, Olympus, and Panasonic), plus HEIC and HEIF, and turn any of them into a normal WebP, AVIF, JPG, or PNG. Doing that without a server behind it turned out to be the harder half of the build.

How the browser turns a file into a converted image

Once a file is decoded into pixels, the actual conversion is the easy part. It uses canvas.toBlob(mime, quality), a method built into every modern browser, to write out WebP, AVIF, JPG, or PNG at whatever size you asked for. There are three quality presets, 0.95 for minimal compression, 0.85 as the balanced default, and 0.65 when file size matters more than every last pixel, and you can watch the resulting file shrink in real time as you switch between them.

For a plain JPG or PNG, that's the whole story: read the file, draw it, and call toBlob. RAW and HEIC need real decoding before any of that can happen, which is where the two heavier libraries come in.

Decoders that load only when you actually need them

HEIC support needs a library called heic2any, because most browsers other than Safari don't ship a HEIC decoder at all. Loading it on every page visit would be wasteful for the far more common case of converting a JPG, so it's fetched with a dynamic import() only the first time you drop a .heic file. If you never touch HEIC, that code never reaches your browser.

RAW files follow the same pattern with a bigger payload. Dropping a DNG or any other RAW file loads libraw-wasm, a WebAssembly build of the LibRaw library, weighing in at around 1.4 MB. It demosaics the sensor data in a Web Worker, using the camera's own recorded white balance, so the tab stays responsive while a 40-megapixel file decodes in the background. A few seconds per file is normal. Turning raw sensor data into a picture is real computation, and it's happening on your machine instead of someone else's server.

Some of the newest iPhone ProRAW files use JPEG-XL compression the WebAssembly build can't unpack yet. When that happens, the tool falls back to the full-resolution preview image every RAW file carries inside itself, so you still get a usable result instead of an error.

When it's actually useful

I reach for it most when I've got a folder of camera RAW files after a shoot and just need shareable JPGs, or when someone sends me an iPhone HEIC and I need a WebP that works everywhere without opening any editor. It's also just a fast way to batch-shrink a folder of PNGs to WebP before they go on a page, without wondering where they went in between.

It's one of 12 free tools I've built and put online, all running the same way: client-side, no upload. If you're curious how the RAW decoding fits together with everything else in that repo, that post covers the full set. And if the idea of scoping a tool to exactly the problem you have, instead of adapting to whatever a general app decided to prioritize, sounds familiar, it's the same instinct behind why I built my own JLPT trainer instead of fighting Duolingo, and behind rebuilding a WordPress theme from scratch rather than wrestling a page builder into doing what I wanted.

The tool itself is live at /tools/image-converter. Drop a RAW file in and you'll get a JPG or WebP out the other side without opening anything else.

FAQ

Does the image converter upload my photos anywhere?
No. Every conversion happens in your browser tab, using the canvas element and a WebAssembly RAW decoder that both run locally. Nothing about the file, not the pixels, not the filename, gets sent to a server.
Which RAW formats does it actually support?
DNG, CR2, CR3, NEF, ARW, RAF, ORF, and RW2, which covers Adobe's format plus Canon, Nikon, Sony, Fujifilm, Olympus, and Panasonic cameras. It also handles HEIC and HEIF straight off an iPhone.
Why does converting a RAW file take a few seconds instead of being instant?
A RAW file is raw sensor data, not a picture yet. Turning it into one means demosaicing every pixel, which the tool does in a Web Worker so a 40-megapixel file doesn't lock up the page while it works.
Is this a replacement for Lightroom?
No, and I wouldn't claim that. It decodes RAW using the camera's own recorded white balance and stops there. There's no exposure, color grading, or lens correction. It's for getting a shareable JPG or WebP out of a RAW file fast, not for editing one.
Why does it only load the RAW or HEIC decoder sometimes?
Both are heavy: the RAW decoder alone is about 1.4 MB of WebAssembly. Loading either one on every visit would slow the page down for the far more common case of converting a plain JPG or PNG, so they're fetched only the moment you drop a matching file.
What happens to iPhone photos in Apple's newer ProRAW format?
Some of the newest ProRAW DNGs use JPEG-XL compression that the WebAssembly RAW decoder can't unpack yet. When that happens, the tool falls back to the full-resolution preview image the camera embeds in the file itself, so you still get a usable photo out of it.

Written by

Portrait of Eric Hinzpeter

Eric Hinzpeter

Eric Hinzpeter, Senior B2B Content Strategist. He builds production AI agents and marketing automation, and documents the results here.

AboutLinkedIn