Skip to content

Overview

High-performance image compression in Rust: a library, a CLI, and a self-hostable HTTP server (PoC). JPEG, PNG, WebP — and AVIF with the avif feature — in and out, plus GIF in (animated GIF included, as animated WebP); sources are format-sniffed by magic bytes and re-encoded in their own format (GIF, having no encoder here, becomes WebP). On imgproxy’s official benchmark harness, run on the same AWS instance types as their published results, oximg leads every format cell on both x86-64 and Graviton while resizing in linear light at measurably higher output quality (see Benchmarks).

  • HTTP resize service: GET /resize/{w}/{h}/{file} fits the source within w x h (never enlarges) and re-encodes it in its own format. 0 leaves an axis unconstrained (/resize/750/0/… is width-only — what srcset w descriptors and Next.js loaders emit), and {file} may span directories, so S3-style prefixes and nested trees are addressable as-is. Optional imgproxy-style HMAC URL signing.
  • Cloudflare Images URL compatibility: mount a second route (OXIMG_OPTIONS_PREFIX) speaking the option-list grammar — /image/width=750,quality=80/path/to/photo.png — so URLs built for Cloudflare Images survive a migration without a rewrite layer, per-request quality included.
  • Sources: a local directory, any HTTP(S) origin, or a private GCS bucket (gs:// with GCP-attached credentials — no public bucket, no public-endpoint egress). The origin round trip never holds a CPU slot (fetches are buffered and separately bounded), and transient fetch failures are retried, so a network blip is a slower response, not a broken image.
  • Production operability: graceful SIGTERM drain, upstream fetch deadlines (slow-origin 504s distinct from broken-origin 502s), and an opt-in Prometheus /metrics page whose queue-wait/processing split tells “needs more CPU” apart from “sources got bigger”.
  • Quality-first processing: resizing happens in linear light on 16-bit samples with Lanczos3, JPEG sources are decoded at full size so the whole reduction is the resampler’s, and alpha is premultiplied across the resample — the properties behind the SSIMULACRA2 scores in Benchmarks. Shrink-on-load is available (OXIMG_DCT_MARGIN) and off by default: it buys decode time with quality, and libjpeg’s reduced IDCT charges erratically for it — 13.4 SSIMULACRA2 points on a 5.3x downscale, for the same output size and the same bytes.
  • Performance as architecture, not flags: per-arch row-streaming SIMD resize kernels (AVX2 on x86-64, NEON on aarch64, both verified against an f64 reference), JPEG decode fused with resize+encode on a second thread under low load, request coalescing for concurrent identical URLs (per-process — a horizontally scaled deployment gets its dedup from the CDN in front, not from here), and CPU concurrency pinned to the core count. Peak memory stays at a fraction of imgproxy’s under identical load (BENCH.md).
  • Tunable profiles: the default maximizes quality per byte (progressive jpegli); one env flip (OXIMG_JPEG_PROGRESSIVE=0) trades ~10% output size for the lowest latency at unchanged pixels. PRESET=fast|small selects mozjpeg profiles instead.
  • Self-contained deploys: multi-arch Docker images (linux/amd64 + linux/arm64) on Docker Hub (oximg/oximg) and GHCR (ghcr.io/oximg/oximg); a single static-leaning binary otherwise.