Table of Contents

Class JpegWriterOptions

Namespace
Egami.Formats.Jpeg
Assembly
Egami.dll

Options for writing JPEG. The defaults are libjpeg-turbo's cjpeg defaults: quality 75, 4:2:0 and the standard Huffman tables of T.81 Annex K, so files compare one to one.

public sealed class JpegWriterOptions : WriterOptions
Inheritance
JpegWriterOptions
Inherited Members

Examples

using Raster photo = Raster.Load("duck.jpg", options: new JpegReaderOptions { FastUpsampling = true });
JpegDetails details = (JpegDetails)photo.Metadata.FormatDetails!;
Console.WriteLine($"{details.ColorSpace}, progressive: {details.Progressive}, quality about {details.EstimatedQuality}");
foreach (JpegComponent component in details.Components)
{
    Console.WriteLine($"Component {component.Id}: sampled {component.HorizontalSampling} × {component.VerticalSampling}");
}

// Gray output, and 4:4:4 (no chroma subsampling) for sharp colored edges.
photo.Save("gray.jpg", new JpegWriterOptions { ColorType = JpegColorType.Gray });
photo.Save("sharp.jpg", new JpegWriterOptions { Quality = 90, Subsampling = ChromaSubsampling.Subsample444 });

Properties

Arithmetic

Gets a value indicating whether to code the scans with T.81's arithmetic coder instead of Huffman codes, as cjpeg -arithmetic writes (SOF9, or SOF10 when Progressive): files are about 4 to 8% smaller than with optimized Huffman tables and decode to the same pixels, but no web browser reads them; libjpeg-turbo, ImageMagick and Egami do. OptimizeHuffman is ignored, and a sequential file streams in one pass at either precision. An Ultra HDR gain map is left out, and setting GainMap with this throws NotSupportedException. Re-saving an arithmetic-coded file writes Huffman codes unless this is set. Defaults to false.

public bool Arithmetic { get; init; }

Property Value

bool

Background

Gets the color that transparent pixels are composited onto before writing, since JPEG has no alpha, or null to ignore alpha (every pixel written as if opaque). Its own alpha is ignored. Defaults to null.

public Rgba8? Background { get; init; }

Property Value

Rgba8?

ColorType

Gets which components to write. Defaults to Auto.

public JpegColorType ColorType { get; init; }

Property Value

JpegColorType

Default

Gets the default options.

public static JpegWriterOptions Default { get; }

Property Value

JpegWriterOptions

GainMap

Gets how to write an HDR raster as an Ultra HDR JPEG (HDR Design question 10), or null (the default) to write its pixels as they are. Set, the raster is tone mapped with Bt2390 to the SDR base image, written at Quality, and Create(Raster, Raster?, GainMapOptions?) makes the map that brings the HDR raster back, written after it as KeepGainMap says. To choose the SDR rendition yourself, set GainMap of the SDR raster to Create(Raster, Raster?, GainMapOptions?)'s map and save that. Needs the whole raster, so a streamed encode throws NotSupportedException.

public GainMapOptions? GainMap { get; init; }

Property Value

GainMapOptions

Examples

// An HDR raster as Ultra HDR: the SDR base, tone mapped with BT.2390, and a gain map that brings the HDR raster back.
using Raster<RgbaF32> hdr = Raster.Load<RgbaF32>("render.exr");
hdr.Save("render.jpg", new JpegWriterOptions { Quality = 90, GainMap = new GainMapOptions() });

// Or choose the SDR rendition: the map goes in its metadata, and saving as JPEG writes both.
using Raster<Rgb8> sdr = hdr.Derive(ops => ops.ToneMap(ToneMapping.Reinhard)).As<Rgb8>();
sdr.Metadata.GainMap = GainMap.Create(hdr, sdr, new GainMapOptions { Scale = 4 });
sdr.Save("graded.jpg", new JpegWriterOptions { Quality = 90 });

KeepGainMap

Gets a value indicating whether a gain map the raster carries (GainMap, from an Ultra HDR, ISO 21496-1 or Apple file) is written back: the gain map JPEG after the image, an MPF index, ISO 21496-1 metadata and Adobe's hdrgm XMP with a GContainer directory, so HDR displays show the HDR rendition. A map read from the file is copied as it was stored; one an operation moved is encoded again. StripMetadata leaves it out too. Defaults to true.

public bool KeepGainMap { get; init; }

Property Value

bool

Examples

// Crops, turns, flips and resizes move the gain map with the picture; saving as JPEG writes it back.
using Raster photo = Raster.Load("ultrahdr.jpg");
using Raster cropped = photo.Derive(ops => ops.Crop(16, 16, 200, 150).Rotate(90));
cropped.Save("cropped.jpg");                                             // still Ultra HDR

// Operations that change pixel values drop it (Operation.GainMapDropped), and so do formats other than JPEG
// (Save.GainMapDropped); KeepGainMap = false leaves it out on purpose.
cropped.Save("sdr-only.jpg", new JpegWriterOptions { KeepGainMap = false });

Lossless

Gets how to write a lossless JPEG (T.81 annex H: SOF3, or SOF11 with Arithmetic), or null (the default) for a DCT file. Set, the samples are written exactly as the pixels hold them, gray, RGB (behind an Adobe marker) or CMYK, never subsampled or color-converted, at 2 to 16 bits, so they load back unchanged; Quality, Subsampling, OptimizeHuffman and Precision are ignored, and the Huffman tables are always made for the image. The encoder holds every sample until the end, about 2 bytes each, counted against MaxTotalBytes. libjpeg-turbo, DNG and DICOM readers read SOF3; only Egami and Thomas Richter's libjpeg read SOF11; no web browser reads either. RestartInterval is rounded up to whole rows of pixels, as T.81 asks of lossless files. With Progressive or Ycck the save throws ArgumentException. An Ultra HDR gain map is left out, and GainMap with this throws NotSupportedException. Defaults to null.

public JpegLosslessOptions? Lossless { get; init; }

Property Value

JpegLosslessOptions

Examples

// Lossless JPEG: the exact samples back, here 16-bit; the predictor is picked for the image unless you name one.
image.As<Rgb16>().Save("duck-lossless.jpg", new JpegWriterOptions { Lossless = new JpegLosslessOptions() });

// Predictor 1 (the sample to the left), arithmetic-coded (SOF11, which only Egami and Richter's libjpeg read).
image.Save("duck-lossless-arithmetic.jpg", new JpegWriterOptions
{
    Lossless = new JpegLosslessOptions { Predictor = 1 },
    Arithmetic = true,
});

OptimizeHuffman

Gets a value indicating whether to build Huffman tables for this image in a second pass instead of using the standard ones: usually 5 to 10% smaller files, and slower. Defaults to false.

public bool OptimizeHuffman { get; init; }

Property Value

bool

Precision

Gets the bits per sample, 8 or 12. 12 keeps the detail of 16-bit and float images (written as SOF1, or SOF2 when progressive, with Huffman tables always optimized), but no browser shows 12-bit JPEG; 8-bit pixel types gain nothing from it. Defaults to 8.

public int Precision { get; init; }

Property Value

int

Exceptions

ArgumentOutOfRangeException

The value is not 8 or 12.

Progressive

Gets a value indicating whether to write a progressive file: libjpeg's standard scan script (ten scans for color, six for gray) with Huffman tables optimized for each scan, as cjpeg -progressive writes. Readers show a coarse image first and refine it; files are usually a few percent smaller than baseline, and decode to the same pixels. The encoder holds every quantized coefficient until the last scan, about 2 bytes per sample, counted against MaxTotalBytes; a streamed encode buffers. Re-saving a progressive file writes baseline unless this is set. Defaults to false.

public bool Progressive { get; init; }

Property Value

bool

Quality

Gets the quality, 1 (smallest) to 100 (best). It scales the example quantization tables of T.81 Annex K with the IJG formula, so the same number gives about the same file as other libjpeg-based encoders. Defaults to 75.

public int Quality { get; init; }

Property Value

int

Exceptions

ArgumentOutOfRangeException

The value is outside 1 to 100.

RestartInterval

Gets the number of MCUs between restart markers, or 0 for none. Restart markers let a reader resynchronize after damaged data, at 2 bytes each. Defaults to 0.

public int RestartInterval { get; init; }

Property Value

int

Exceptions

ArgumentOutOfRangeException

The value is outside 0 to 65,535.

Subsampling

Gets the chroma subsampling. Defaults to Subsample420 (4:2:0). Ignored for gray output.

public ChromaSubsampling Subsampling { get; init; }

Property Value

ChromaSubsampling