Native vs WASM image encoder benchmark
How good is the image encoder built into your browser? Pick some photos,
or use our reference images. This page encodes them with your browser's built-in
image encoder — canvas.toBlob() — in three formats (JPEG, WebP, AVIF),
six quality levels each. Then it encodes the same pixels again with the
reference encoders compiled to WASM (MozJPEG, libwebp, libavif),
so you can compare your browser against known-good implementations.
You get output bytes, encode latency and DSSIM quality for both paths, measured on
your machine and your browser version. Nothing is uploaded; your photos never leave
this page.
Your environment
Encoders are native code inside your browser/engine, so the numbers below are a property of this exact setup — browser, version, OS, CPU/GPU all move them. Read locally; only shared if you choose to share.
- Status
- collecting…
1 · Choose images
Your photos
Best signal — real content at real resolutions. PNG/JPEG/WebP/AVIF, whatever your browser can decode.
Reference images (served from cdn.pixkeep.app)
The same four images our published numbers use — comparable across devices.
2 · Run
Each cell is one full-resolution encode — size and time from that single run. Quality (DSSIM) is scored against a shared 1200px center crop, the same framing for every encoder. Single-run timings carry some noise; if a number looks off, run it again. WebP and AVIF on 12MP photos are minutes-scale — AVIF most of all. Keep this tab in the foreground (background tabs get throttled and pollute the timings).
Formats:
idle
Methodology & caveats
- Quality scales are not comparable across encoders. "q80" in Chromium's JPEG encoder, MozJPEG and libwebp are three different points on three curves. Compare formats at matched DSSIM, not matched q.
- Support is detected by the returned blob's type — browsers that can't encode a format silently return PNG instead of throwing.
- WASM reference encoders: MozJPEG (
@wasm-codecs/mozjpeg), libwebp (@jsquash/webp), AVIF (@jsquash/avif) — both groups encode the full image once per quality for size and time, plus the 1200px analysis frame for DSSIM. The first WASM encode per format absorbs worker startup and.wasmcompilation (unmeasured), so timed runs never see a cold start; WASM time includes RGBA extraction and the worker round-trip. - One measured run per cell. No medians, no warm-up repetitions — one shot, honestly labelled. Re-run the bench if you want a second sample; a few percent between runs is expected.
- Timings: full-resolution encode, warm module, DevTools closed.
Found something odd? Bring it to Discussions — reproducible oddities become blog posts.