A privacy-first image format converter that runs entirely in the browser using Rust compiled to WebAssembly — supporting six formats with zero server uploads, zero JavaScript, and full offline capability.

All image processing happens locally in the browser via WebAssembly. No files are uploaded to any server, no data is collected, and no account is needed — your images never leave your device.
Supports six image formats — JPEG, PNG, WebP, GIF, BMP, and TIFF — with a quality slider for lossy formats, giving users fine-grained control over file size and output fidelity.
Upload images via drag-and-drop or file browser with instant thumbnail preview, a three-stage progress bar, and automatic download of the converted file — all with smooth visual feedback.
Once loaded, the app works completely offline. The Rust-to-WASM compilation is aggressively optimized for size with LTO, single codegen units, and panic-as-abort — resulting in a minimal bundle.
Reading files in WASM means working with the browser's asynchronous FileReader API from synchronous Rust code. I wrapped the FileReader in a JavaScript Promise, bridged it to a Rust Future via wasm-bindgen-futures, and converted the resulting ArrayBuffer into a Vec<u8> — creating a seamless pipeline between the Web File API and Rust's image processing crate.
Image decoding and encoding in WASM can block the browser's single main thread, freezing the UI. I broke the conversion into discrete stages (decode, encode, finalize) with yielded timeouts between each step, allowing the browser to repaint and update the progress bar — giving users visual feedback instead of a frozen screen.
Rust's ownership model doesn't know about browser-managed blob URLs. Each image preview creates a blob URL that the browser holds in memory indefinitely unless explicitly revoked. I implemented manual tracking of old URLs, revoking them before creating new ones, to prevent memory leaks during repeated conversions in a single session.