Skip to content
>sdcb.ai
1.0 releasedlatest v1.0.1 · Oct 29, 2026MITnet10.0NativeAOT

SimdCodecs

Image codecs in pure managed C#: JPEG, PNG, TIFF, WebP, GIF, JPEG 2000 and JBIG2, plus EXIF and ICC. Not a single native DLL — and a JPEG decoder faster than libjpeg-turbo.

Install
dotnet add package Sdcb.SimdCodecs
JPEG, PNG, WebP, TIFF, JPEG 2000 and JBIG2 images, all decoded by Sdcb.SimdCodecs
Every tile decoded by this library: JPEG · PNG · WebP · TIFF · JPEG 2000 · JBIG2
0.82×
libjpeg-turbo’s decode time (446-file corpus, single thread)
0 B
managed allocation per JPEG decode
7 + 2
image formats, plus EXIF and ICC
0
native deps: x64 / ARM64 / NativeAOT / WASM

Why

Reading an image in .NET shouldn’t need a native library

Turning a file into pixels in .NET today means one of three roads:

  • System.Drawing
    GDI+ — Windows only
  • SkiaSharp · OpenCvSharp · Magick.NET
    A native binary per platform: heavy, and AOT / WASM need extra work
  • ImageSharp
    Managed, but 1.77× libjpeg-turbo’s time on JPEG decode

SimdCodecs is the fourth: every codec written in C# from the specification, with hand-written AVX2 / SSE / AdvSimd kernels and a scalar fallback. The bar is not “it works” — it is every encoder and decoder at or beyond its native reference library.

A pure-C# vision stack · zero native deps end to end
photo.jpg · scan.tif · page.jb2
Sdcb.SimdCodecsfile → pixels
SimdGcdrNetshadow removal
SimdPaddleOCRpixels → text
“Invoice No. 2026-1029 …”

All three share one pixel buffer: decode straight into it, enhance in place, recognise. The first step used to borrow ImageSharp or SkiaSharp — now it is pure C# too.

Formats

One package, seven formats

The Sdcb.SimdCodecs facade sniffs the magic bytes and dispatches; each format is also its own package with a richer API. The ones marked “browsers can’t” are worth a look in the lab.

JPEG

decodeencode

Baseline / progressive, any subsampling, CMYK / YCCK, 1/2–1/8 scaled decode, zero-allocation DecodeTo; encodes optimised Huffman, progressive, EXIF / XMP

Ultra HDR

decodeencode

JPEG gain-map read, assemble and HDR reconstruction (Ultra HDR / Adobe)

PNG

decodeencode

Every bit depth 1–16 and palettes, Adam7 interlacing, text chunks, HDR signalling (cICP / mDCV / cLLI)

TIFF

decodeencode

Multi-page; 8/16/32-bit integer and float; strips or tiles; Deflate, LZW, PackBits, CCITT G3/G4 fax

browsers can’t → see it in the lab

WebP

decodeencode

Lossy, lossless, alpha, animation with seeking; byte-exact with libwebp

GIF

decodeencode

87a / 89a, interlacing, transparency, every disposal; encodes stills and animations (exact palette, or Wu quantization + dithering)

JPEG 2000

decodeencode

Part 1 (T.800), for PDF /JPXDecode

browsers can’t → see it in the lab

JBIG2

decodeencode

T.88, for scanned PDFs’ /JBIG2Decode

browsers can’t → see it in the lab

EXIF

decodeencode

Read from JPEG, TIFF and PNG; ExifWriter builds a block for the JPEG encoder

ICC

decodeencode

Decoders return embedded profiles; bundled sRGB v4; splice a profile into an existing JPEG

HEIC

next

What iPhones shoot by default, and what Chrome and Firefox can’t open. On its way — pure C#, zero native deps, like the rest.

Star on GitHub to follow along →

Quick start

Decode into your own memory — any layout, any stride

Program.cs
using Sdcb.SimdCodecs;
using Sdcb.SimdCodecs.Abstractions;

byte[] file = File.ReadAllBytes("photo.webp");   // JPEG, PNG, TIFF, WebP, GIF, JPEG 2000, JBIG2

// Sniffs the format from the magic bytes; headers only
if (!SimdCodecs.TryReadInfo(file, out ImageInfo info)) throw new InvalidDataException();
Console.WriteLine($"{info.Width}×{info.Height}, {info.BitDepth}-bit, {info.FrameCount} frame(s), {info.Orientation}");

// Decode into a buffer you own (R G B A)
byte[] rgba = new byte[info.Width * info.Height * 4];
SimdCodecs.TryDecodeIntoRgba8(file, rgba);

Every package ships runnable LINQPad samples (listed in LINQPad’s NuGet browser), covering SkiaSharp, OpenCvSharp, Ultra HDR, multi-page TIFF and more.

Performance

Measured against the native libraries themselves

Single-threaded, AMD Ryzen 7 5800X, .NET 10. Time relative to the native library — shorter is faster.

JPEG decode to RGBA · 446 files

libjpeg-turbo 3.2.0 · native1.00×
Sdcb.SimdCodecs0.82×
ImageSharp 3.1.121.77×

0 B managed allocation per decode (ImageSharp: ~16 KiB plus its own image). At least as accurate as libjpeg-turbo’s default (~1 dB higher RGB PSNR where chroma is upsampled), and bit-identical on AVX2, SSE, AdvSimd, scalar and NativeAOT.Full report

WebP decode to RGBA · 1920×1080

lossy0.88×
lossy + alpha0.53×
lossless0.72×
libwebp 1.6.0 · nativeSdcb.SimdCodecs

Output is byte-identical to libwebp. On photo-like opaque lossy files the two are on par (0.87–1.13×).Full report

Lab

The same C#, in your browser

Open the lab

Compiled to WebAssembly; your images never leave your machine. It does only the three things browsers can’t do themselves:

NuGet

13 packages, one version

Dependency graph
Sdcb.SimdCodecs (facade)
 ├─ Abstractions
 ├─ Png ──────────┬─ Color.Icc ─ Abstractions
 │                └─ Abstractions
 ├─ Tiff ─────────┬─ Png
 │                └─ Abstractions
 ├─ Jpeg ─────────── Abstractions
 ├─ Jpeg.GainMap ─┬─ Jpeg
 │                └─ Abstractions
 ├─ Jbig2 ────────── Abstractions
 ├─ Jpeg2000 ─────── Abstractions
 ├─ Webp ─────────── Abstractions
 └─ Gif ──────────── Abstractions

Exif ─ Tiff        Jpeg.IccInjector (no dependencies)

All packages ship in lockstep under one version. No package uses another’s internals: code two packages need is shared as source, compiled into each.

Clean room

Written from the specs, natives only as black boxes

  • Algorithms only from ITU-T / ISO specs (T.81, T.88, T.800, …), the PNG spec, the prose and tables of RFC 6386 / 9649, papers and CPU manuals
  • Never reads libjpeg-turbo, libpng, libwebp, ImageSharp or any GPL code; every file is first-party MIT
  • Native libraries serve only as black-box oracles, compared output by output in CI (REQUIRE_ORACLES=1)
  • Hardened against hostile input: JBIG2 segment headers, EXIF IFDs, looping TIFF IFD chains

Credits

Derived from SharpAstro/Codecs (Unlicense); the JPEG marker and entropy layer is a port of the public-domain stb_image.

Known gaps are listed codec by codec in docs/known-gaps.md (in Chinese).

MIT licensed, fine for commercial use.

WeChat group QR code

C#/.NET Computer Vision community

Scan to join the WeChat group. The QR code rotates weekly — if it has expired, join QQ group 579060605 instead.