Skip to content

v1.2.0: QOI and Netpbm

Latest

Choose a tag to compare

@sdcb sdcb released this 30 Oct 07:54

New packages

  • Sdcb.SimdCodecs.Qoi: QOI ("Quite OK Image") decoder and encoder, written from the specification. It decodes RGB and RGBA straight into a caller's buffer in any 8-bit layout, with no allocation. It encodes from RGBA, BGRA, RGB, BGR or grey, to an array or a stream.
  • Sdcb.SimdCodecs.Pnm: the Netpbm family, decode and encode.
    • P1–P6 PBM / PGM / PPM, plain (ASCII) and raw, with maxval up to 65535 (16-bit samples).
    • P7 PAM with 1–4 channels.
    • PFM, 32-bit float, both byte orders.

Facade

  • ImageFormat.Qoi now decodes; it was recognised only before.
  • New ImageFormat.Pnm and ImageFormat.Pfm, both sniffed by the facade.
  • PFM returns float samples. Use PixelConverter.StretchToRgba8 to get a viewable image.

Performance

Measured on a Ryzen 7 5800X at 1920×1080, single thread. Figures are the geometric mean of our time ÷ ImageSharp 3.1.12's, so lower is faster.

Decode Encode to a stream
QOI 0.29× 0.49×
Netpbm 0.23× 0.54×

Full results are in benchmarks/Sdcb.SimdCodecs.QoiPnm.Benchmarks/results/.

Verification

  • Exact against ImageMagick in both directions, for every variant it writes.
  • Hand-written streams cover every QOI chunk, plus Netpbm comments, odd maxvals and PFM byte orders.
  • Every SIMD tier is tested, and 300k fuzz iterations per format ran clean.
  • NativeAOT and Mono AOT (wasm) output matches JIT.

Samples

  • LINQPad qoi: QOI against PNG on size and speed.
  • LINQPad netpbm: every format, a hand-written PPM, 16-bit PGM, PFM.

Known gaps

  • Netpbm reads only the first image in a file.
  • PFM does not decode into 8-bit layouts.
  • PAM DEPTH is limited to 1–4.
  • QOI has not been benchmarked against a native implementation.
  • ImageSharp 3.1.12 reads and writes 16-bit PPM little-endian, unlike the spec and ImageMagick, so that case is not timed against it.

Details are in docs/known-gaps.md.