DotJpegli

Pure managed JPEG encoding for .NET.

DotJpegli is a safe, portable C# JPEG encoder based on Google Jpegli. Encode RGB or grayscale pixels as baseline or progressive JPEG, with control over quality, sampling, color profiles and metadata.

The library is implemented entirely in managed .NET, with no native dependencies, P/Invoke, unsafe code or runtime NuGet dependencies. NativeAOT and trimming are fully supported on .NET 10 and .NET 11.

Visual & Perceptual Evaluation

Photograph comparison

Fine clouds of dust, saturated colour and thousands of stars make Webb's Cosmic Cliffs a demanding subject. Open the 2400 × 1390 source photograph to inspect its full detail:

James Webb Space Telescope photograph of the Cosmic Cliffs: glowing amber clouds, blue starlight and intricate filaments in the Carina Nebula.
Photograph: NASA, ESA, CSA, and STScI — ESA/Webb source, CC BY 4.0. Resized from the official lossless TIFF; the comparison images are re-encoded and the detail panels are cropped. Open 2400 × 1390 lossless source PNG ↗

Every encoder receives the same RGB pixels. Links open the complete files; sizes include headers and metadata. SSIMULACRA2 measures each decoded image against the source; higher scores indicate closer agreement with that metric.

Encoder / source Settings File size SSIMULACRA2
Source PNG Lossless common input 4,437,354 bytes · 4333.4 KiB 100.00
DotJpegli 4.0.0 Distance 1, 4:2:0, progressive level 2 723,724 bytes · 706.8 KiB 80.49
Google's C++ jpegli Distance 1, 4:2:0, progressive level 2 723,938 bytes · 707.0 KiB 80.49
mozjpeg 4.1.1 Quality 90, 4:2:0, progressive, trellis 726,330 bytes · 709.3 KiB 78.92
libjpeg-turbo 3.2.0 Quality 90, 4:2:0, progressive 822,647 bytes · 803.4 KiB 80.41
WebP 1.6.0 Quality 90, method 6 640,770 bytes · 625.8 KiB 82.28
AVIF · libavif 1.4.2 / libaom 3.14.1 Quality 90, speed 6, 8-bit 4:2:0 837,683 bytes · 818.0 KiB 86.85
JPEG XL · libjxl 0.12.0 Distance 1, effort 7 759,353 bytes · 741.6 KiB 88.02

These are selected high-quality settings for one photograph. Quality scales differ across codecs, and these outputs are not matched perceptual quality. JPEG XL and AVIF retain more detail according to this metric at the settings shown. DotJpegli is 214 bytes smaller than Google's jpegli here; their bytes and decoded pixels differ slightly. JPEG XL requires a compatible viewer.

The following lossless sheet shows the same 480 × 300 detail from every image, with one source pixel per image pixel. Open it at full size to compare star edges, wispy dust and colour transitions:

Pixel-for-pixel source and encoded detail crops for DotJpegli, Google jpegli, mozjpeg, libjpeg-turbo, WebP, AVIF and JPEG XL, each labelled with its complete file size. Credit: NASA, ESA, CSA, and STScI; CC BY 4.0.
See the source, exact settings, hashes and reproduction instructions. Google also published a separate human-rater study of jpegli, mozjpeg and libjpeg-turbo; the example above is generated for this repository. Open full-size detail crop sheet ↗

Capabilities

Features

Full-featured JPEG compression implemented in safe, portable managed C# without native binaries or runtime dependencies.

Encoding

Baseline and progressive JPEG, perceptual quality or distance, chroma subsampling and custom scan scripts.

Pixel input

RGB, BGR, grayscale and other layouts; byte, ushort and float sources; configurable row stride.

Color and metadata

ICC profiles and source color conversion, Exif, XMP, IPTC, comments and raw metadata markers.

Output and execution

Byte arrays or streams, cancellation and optional parallel encoding.

Portable acceleration

Managed SIMD on .NET 10 and .NET 11, with scalar fallbacks.

Pure managed & NativeAOT

Zero unsafe blocks, zero P/Invoke, zero runtime NuGet dependencies, and full trimming and NativeAOT compatibility.

Standalone Tooling

Command-line encoder

Download a self-contained NativeAOT dotjpegli package or portable archive from Releases. Downloads are available for Windows (x64, ARM64), Linux (x64, ARM64) and macOS (ARM64), and do not require .NET to be installed.

Encode images from the command line
shell
dotjpegli encode input.png output.jpg --quality 90 --progressive
dotjpegli encode input.png output.jpg --distance 1 --subsampling 444 --threads 4

See the CLI guide for installation, options and local publishing.

Windows win-x64 · win-arm64

Per-user .msi installer (adds dotjpegli to user PATH), portable .zip archive and standalone .exe executable.

Linux linux-x64 · linux-arm64

Debian/Ubuntu .deb, Fedora/RHEL/openSUSE .rpm, single-file .AppImage, .flatpak bundle and portable .tar.gz.

macOS osx-arm64

Apple Silicon .pkg installer (installs /usr/local/bin/dotjpegli) and ad-hoc signed portable .tar.gz archive.

Library API

Quick start

Add the NuGet package to any .NET Standard 2.1, .NET 10 or .NET 11 project and encode pixels to a byte array or stream.

1. Install the package
sh
dotnet add package DotJpegli --version 4.0.0

Supports .NET Standard 2.1, .NET 10 and .NET 11.

Build from source
sh
dotnet add path/to/YourApp.csproj reference src/DotJpegli/DotJpegli.csproj

Building from source requires .NET SDK 11.0.100-rc.3.26522.148, pinned in global.json with prerelease SDKs enabled.

2. Encode an image
csharp
using DotJpegli;

byte[] rgbPixels = [255, 0, 0]; // One red pixel, in R, G, B order.

byte[] jpeg = JpegliEncoder.Encode(rgbPixels, width: 1, height: 1, options: new()
{
    Quality = 85
});

File.WriteAllBytes("output.jpg", jpeg);

For RGB input, the defaults are baseline JPEG, quality 85 and 4:2:0 chroma subsampling. For other pixel layouts, row padding and higher-precision sources, see the encoding guide. Alpha channels are ignored; composite translucent pixels before encoding.

3. Write progressive JPEG to a stream
csharp
using FileStream output = File.Create("progressive.jpg");

JpegliEncoder.Encode(output, rgbPixels, width: 1, height: 1, options: new()
{
    Quality = 85,
    Progressive = true
});

The stream overload avoids retaining the complete encoded JPEG in a returned byte array. See compression and scan options for quality, sampling and progression controls.

Benchmarks & Evidence

Performance

These charts compare DotJpegli with native Google Jpegli on 24 Kodak photographs.

Compression efficiency

Mean JPEG sizes differ from native by at most 0.032% at matched PSNR and SSIM.

Photograph group mean JPEG file-size differences from native Google Jpegli are at most 0.032% across all four encoding modes at matched PSNR and SSIM.

Encoding wall time

On an AMD EPYC 9V45, progressive encoding averaged 29.6–30.5% less time than native; sequential averaged 15.7–16.8% less.

Percentage encoding-time differences from native Google Jpegli, pairing Kodak photographs and deterministic controls for each encoding mode.

Allocations per encode

DotJpegli averaged 98.8–146.3 KiB of managed GC allocations per encode, compared with 1,924.8–4,288.3 KiB of native heap requests for Google Jpegli (measurements, including the output JPEG; not peak memory).

DotJpegli managed GC allocation bytes and official Google C++ jpegli requested heap bytes in KiB per encode, grouped by sampling and sequential or progressive encoding.

See methodology and full results and chart data. The full comparison does not meet native performance parity.

Reference Guides

Documentation

Detailed guides covering pixel layouts, ICC color profiles, scan scripts, quantization tables, parity evidence and release engineering.

Scope

DotJpegli produces lossy, eight-bit JPEG, including from higher-precision sources and even at quality 100. Jpegli's quality scale is not interchangeable with libjpeg's. Decoding is outside the project's scope.

Validation

Quality and compression parity with upstream is established within a documented RGB8 YCbCr scope. Byte-identical upstream output is not claimed. Performance results and acceptance bounds are documented separately.