Files
pdfcraft/crates/optimize/README.md
T
Guillem Hermida 359a3f2f09 M11: Optimize keeps a JPEG's colour transform (#1201)
Optimize decoded DCT images with the generic JPEG decoder, which converts
three components from YCbCr to RGB whenever the JPEG itself doesn't say
otherwise, and then dropped /DecodeParms. An RGB JPEG stored untransformed
(/ColorTransform 0 and no Adobe marker) therefore came out in other colours
when recompressed, resampled or merged from strips.

The samples are now read with the colour transform ISO 32000-2 §7.4.8
gives them: an Adobe APP14 marker's flag, else /ColorTransform (default 1).
Untransformed samples are taken as stored, and the result is written as a
plain YCbCr JPEG (or Flate), which needs no /DecodeParms. When the marker
and /ColorTransform disagree, a value is out of range, the parameters are
not paired with the filter as §7.4 pairs them, or the decoder reads the
components otherwise (named R, G and B), the image is left as it is.

The tests draw each image with PdfCraft's renderer before and after
Optimize: RGB JPEGs with and without an Adobe marker under each
/ColorTransform, CMYK JPEGs (still left alone) and JPEG strips merged into
one picture.

Part of #1201.
2026-10-16 17:28:19 +02:00

2.9 KiB

pdfcraft-optimize

Layer L4: the PDF Optimizer (execution plan M11.1; Acrobat's Reduce File Size and Optimize PDF ▸ Advanced optimization).

let report = optimize(&mut doc, &Settings::default())?;   // Reduce File Size's choices
let report = optimize(&mut doc, &Preset::Mobile.settings())?; // smaller, for screens
// Or with progress: called before each image and the clean-up; `false` cancels.
let report = optimize_with_progress(&mut doc, &settings, &mut |stage| keep_going)?;
  • Presets: Standard (Reduce File Size's choices: images above 225 ppi to 150 ppi, JPEG medium) and Mobile (above 144 ppi to 96 ppi, JPEG high), as in Acrobat's Settings menu.
  • Merge image fragments (fragments, on by default): some PDF printers draw a page picture as thousands of images one pixel row high. Runs of upright 8-bit grey or RGB images in one colour space, sharing their left and right edges and stacked edge to edge (at least four, drawn with nothing else between them), become one lossless image at their finest resolution, which the image settings then resample; the strips are dropped by Clean Up. A real page printed this way went from 4.3 MB to 231 KB (Standard) and 161 KB (Mobile). Not merged yet: side-by-side tiles, rotated strips, masks.
  • Images: the effective resolution of each image is measured where pages draw it (the CTM through form XObjects, up to 12 deep; the smallest over all uses). If a use can't be measured (forms nested deeper, or drawn too many times), no image is resampled. Colour and grayscale images above a threshold are resampled with a bicubic (Catmull-Rom) filter to a target resolution and stored as JPEG (Acrobat's quality steps) or ZIP; soft masks are resampled with their image. An image is replaced only if the result is smaller. Left alone: CMYK and other colour spaces, image masks, decode arrays, more than 8 bits, JPEG 2000, JBIG2 and CCITT. A JPEG is read with its colour transform (an Adobe marker's, else /ColorTransform, ISO 32000-2 §7.4.8), so one stored untransformed keeps its colours; one whose marker and /ColorTransform disagree is left alone, since readers differ on which wins.
  • Discard objects: thumbnails, alternate images, document tags, print settings.
  • Clean up: Flate for streams with no filter; for streams with an outer ASCII85 or ASCIIHex layer, that layer is removed when the result is smaller (the inner filters keep their encoded bytes). Streams with /DecodeParms, images and object streams are left alone.

The engine runs Remove Hidden Information (pdfcraft-redact) for the user-data categories, then this, then merges identical objects and writes a full, compressed save (pdfcraft_engine::optimizer::OptimizeJob, which the UI runs on a worker thread with a progress bar). JPEG decoding comes from zune-jpeg (the decoder behind image and the renderer), JPEG encoding and resampling from the image crate.