From 740bb874a4c5b998d49e08cbc3e4fe6dfe13ddce Mon Sep 17 00:00:00 2001 From: Grzegorz Martens Date: Mon, 26 Oct 2026 17:38:22 +0100 Subject: [PATCH] M11: say damaged Group 3 with end-of-line codes is stored as the decoder recovers it With end-of-line codes, the CCITT decoder picks a bad row up again at the next code and reports no damage (an invalid code, a row of too many pixels: probed as a black box), so such an image is stored again as Group 4 the way it decodes. Without them, damage stops the decoding, too few rows come out, and the image is left alone. Telling damage apart would take a Group 3 parser of our own; the optimize README and the mono-compression parity note say so instead. From reviews with the pdfcraft-review skill. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01P6yUtvWGPsJpMLyh6pxSXG --- crates/optimize/README.md | 9 ++++++--- parity/acrobat-features.toml | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/optimize/README.md b/crates/optimize/README.md index e26ceba945..6383510c96 100644 --- a/crates/optimize/README.md +++ b/crates/optimize/README.md @@ -68,9 +68,12 @@ let report = optimize_with_progress(&mut doc, &settings, &mut |stage| keep_going smaller, which only a resampled image or one packed from more bits may be: a 1-bit image that is only stored again becomes Group 4 or stays. Group 4 alone is only decoded to be resampled; Group 3, or Group 4 inside another filter such as `ASCII85Decode`, is stored again as Group 4 - alone when that is smaller. With Retain, a resampled image keeps its kind of compression (CCITT, - or Flate) and nothing else changes; an image of more bits is then left to the grey or colour - settings. Every change is kept only when it is smaller as stored. + alone when that is smaller. Damaged Group 3 with end-of-line codes is stored as the decoder + recovers it, a bad row picked up again at the next code, as it reports no damage there; without + them, damage stops the decoding and the image is left alone. With Retain, a resampled image + keeps its kind of compression (CCITT, or Flate) and nothing else changes; an image of more bits + is then left to the grey or colour settings. Every change is kept only when it is smaller as + stored. - Apart from the downsampling it is lossless: the samples keep their meaning, so the colour space, decode array and `/Mask` stay, but for packed RGB, which becomes grey with one decode pair. Group 4 wins on scans, whose ragged edges defeat Flate; on clean computer-drawn 1-bit diff --git a/parity/acrobat-features.toml b/parity/acrobat-features.toml index 048afd9a36..6cc4f4797c 100644 --- a/parity/acrobat-features.toml +++ b/parity/acrobat-features.toml @@ -7385,7 +7385,7 @@ status = "partial" commands = ["optimize.advanced", "optimize.reduce"] tools = ["doc_optimize", "doc_reduce"] evidence = ["crates/optimize/tests/optimize.rs::eight_bit_black_and_white_images_become_one_bit", "crates/filters/src/ccitt.rs::bitmaps_round_trip", "crates/filters/src/ccitt.rs::a_page_of_text_like_marks_round_trips_and_shrinks", "crates/filters/src/ccitt.rs::what_it_cannot_encode_is_an_error", "crates/optimize/tests/optimize.rs::black_and_white_images_become_ccitt_group_4", "crates/optimize/tests/optimize.rs::group_3_fax_images_become_group_4", "crates/optimize/tests/optimize.rs::rgb_and_two_colour_indexed_black_and_white_images_become_one_bit", "crates/automation/tests/it/automation.rs::doc_optimize_stores_black_and_white_images_as_ccitt_group_4", "crates/ui-egui/tests/it/create.rs::the_pdf_optimizer_dialog_saves_an_optimized_copy"] -notes = "CCITT Group 4, lossless: PDF Optimizer ▸ Images ▸ Monochrome Images (on by default, so Reduce File Size does it too; doc_optimize mono) stores a 1-bit image of one colour component (grey, indexed, a separation) or an image mask, kept with no filter or general-purpose ones, as Group 4 when that is smaller as stored; the samples decode to the same bits, so colour space, decode array and masks stay. Packed to one bit first, then stored the same way (colour-key masks aside): eight-bit grey of only black and white, eight-bit DeviceRGB of only black and white (as DeviceGray; calibrated RGB, RGB with a profile, RGB drawn where /DefaultGray or /DefaultRGB is in force, and RGB whose soft mask has a /Matte aside), and an indexed image of 2, 4 or 8 bits that uses only palette entries 0 and 1 (keeping its palette), unless the grey or colour settings make it smaller still, as they can a dithered scan downsampled to JPEG, its soft mask counted. Group 4 wins on scans; on clean computer-drawn 1-bit art Flate can be smaller, and the image then stays. Group 3 fax images are stored again as Group 4 when that is smaller. CCITT fax images are decoded to be downsampled (optimize.downsample-images), and a resampled image is stored as Group 4 or 1-bit Flate, whichever is smaller. Not yet: JBIG2 (lossless or lossy, which Adobe's help says beats CCITT for monochrome), inline images, soft masks and /Mask images, Group 4 for rows wider than 32,767 samples." +notes = "CCITT Group 4, lossless: PDF Optimizer ▸ Images ▸ Monochrome Images (on by default, so Reduce File Size does it too; doc_optimize mono) stores a 1-bit image of one colour component (grey, indexed, a separation) or an image mask, kept with no filter or general-purpose ones, as Group 4 when that is smaller as stored; the samples decode to the same bits, so colour space, decode array and masks stay. Packed to one bit first, then stored the same way (colour-key masks aside): eight-bit grey of only black and white, eight-bit DeviceRGB of only black and white (as DeviceGray; calibrated RGB, RGB with a profile, RGB drawn where /DefaultGray or /DefaultRGB is in force, and RGB whose soft mask has a /Matte aside), and an indexed image of 2, 4 or 8 bits that uses only palette entries 0 and 1 (keeping its palette), unless the grey or colour settings make it smaller still, as they can a dithered scan downsampled to JPEG, its soft mask counted. Group 4 wins on scans; on clean computer-drawn 1-bit art Flate can be smaller, and the image then stays. Group 3 fax images are stored again as Group 4 when that is smaller (damaged Group 3 with end-of-line codes as the decoder recovers it, as it reports no damage there). CCITT fax images are decoded to be downsampled (optimize.downsample-images), and a resampled image is stored as Group 4 or 1-bit Flate, whichever is smaller. Not yet: JBIG2 (lossless or lossy, which Adobe's help says beats CCITT for monochrome), inline images, soft masks and /Mask images, Group 4 for rows wider than 32,767 samples." [[feature]] id = "optimize.only-if-smaller"