Kroma Lab

How We Built Image Processing in the Browser (No Server)

Close-up of hands typing code on a laptop keyboard

Most "free online image tool" sites work the same way. You drop a file, it uploads to a server, the server does the actual work, and you get a download link back. That's true even for tools that are explicit and responsible about privacy — the file still has to leave your device to get processed.

So what does real image processing in the browser actually look like, with no upload step at all? Kroma Lab compresses images, converts between formats, and reads/strips EXIF and GPS metadata entirely inside the browser tab. No backend endpoint receives your file. Here's how that's actually built, and where it gets hard.

The core idea: run real codecs in WebAssembly, not JavaScript

The obvious objection to browser-side image processing is performance. Isn't JavaScript too slow to decode and re-encode images at native-codec speed? That's true if you're writing the codec in JavaScript. It's not true if you compile the actual C/C++ codec libraries to WebAssembly and run those instead.

That's the approach: WASM builds of real encoder/decoder libraries for JPEG, PNG, WebP, and AVIF, plus a WASM build of libheif for HEIC decoding (the format iPhones use by default). The browser isn't approximating what a native image tool does — it's running close to the same underlying code, compiled to run in a sandboxed WASM runtime instead of natively.

Why everything runs in a Web Worker, not the main thread

Decoding and re-encoding an image is CPU-intensive work — running it on the main thread would freeze the tab's UI for the duration, which is a bad experience even if the actual work only takes a second or two. Every processing operation runs in a dedicated Web Worker instead, communicating back to the UI thread via a lightweight RPC layer rather than raw postMessage boilerplate.

Practically, this means the interface stays responsive while a large batch of files processes — you can cancel, watch progress, and interact with the page instead of staring at a frozen tab.

Compression: it's a search problem, not a single operation

"Compress this to under 5MB" sounds like one operation. It's actually an iterative search: encode at a starting quality, check the resulting size, adjust quality down (or up) based on the result, and repeat until the target is hit or further reduction stops helping. If quality reduction alone can't reach the target without unacceptable visual loss, resolution gets downscaled as a second lever before quality drops further — the same tradeoff a human doing this manually in an image editor would make, just automated and bounded by the target you set.

Metadata: reading and stripping without re-encoding

Compression and conversion inherently rebuild the image from pixel data, which naturally strips EXIF and GPS metadata as a side effect. But the metadata tool needs to do something different: read the embedded EXIF/GPS data for display, and strip it without re-encoding the image, so a straightforward "remove my location data" request doesn't also silently degrade image quality.

That means parsing the file's metadata segments directly (JPEG's EXIF markers, PNG's text chunks, and so on) and, for stripping, removing those segments at the byte level rather than decoding and re-encoding the whole image. The pixel data itself is never touched.

The honest tradeoffs

This approach isn't free of downsides, and it's worth being direct about them:

  • Encode time varies by format. AVIF's compression is meaningfully more computationally expensive than JPEG or WebP — it's derived from a video codec's compression techniques, which is part of why it produces smaller files, but it takes longer to encode as a result.
  • It requires a modern browser. The whole approach depends on the browser supporting WebAssembly, Worker, and the File API — all standard in current Chrome, Firefox, Safari, and Edge, but it does mean there's no fallback for genuinely old or unusual browsers. We gate the tool behind a feature check and tell people directly if their browser doesn't support it, rather than letting it fail silently.
  • No server also means no server-side fallback. If a particular file trips up a codec, there's no backend to retry the operation differently — the failure has to be handled gracefully client-side.

Why this tradeoff was worth it

For a tool that exists specifically to handle personal photos — including a tool whose entire purpose is telling you what's hidden inside your own photo — "trust our server" was never going to be a satisfying answer. Not uploading the file isn't a privacy policy here; it's an architectural fact you can verify yourself by opening your browser's network tab and watching nothing get sent anywhere.

That's the bet: for this category of tool, verifiable is worth more than a promise.

Detailed view of HTML code displayed on a computer monitor