M11: merge image fragments, and the Standard and Mobile optimizer presets (closes #1783) (#1784)

* M11: merge image fragments, and the Standard and Mobile optimizer presets

Some PDF printers draw a page picture as thousands of images one pixel row
high (one real page: 3,300 strips, 4.3 MB). The optimizer works image by
image, a one-row image can't be resampled, and every JPEG strip carries its
own headers, so Reduce File Size saved 2 bytes on it.

- pdfcraft-optimize `fragments` (Settings::merge_fragments, on by default):
  runs of `q … cm /Im Do Q` drawing 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, nothing else drawn between them; or, failing that, the
  rows drawn one under the other up to a gap) become one lossless image at
  their finest resolution. The image settings then resample it, and Clean
  Up drops the strips. A page whose content can't be read back exactly is
  left alone.
- Presets as in Acrobat's Settings menu: Standard (Reduce File Size's
  choices) and Mobile (images above 144 ppi to 96 ppi, JPEG high). The PDF
  Optimizer dialog has a Settings menu (Custom once an option changes) and
  a Merge image fragments box; doc_optimize takes preset and
  merge_fragments and reports merged_images and fragments_merged.
- A progress stage for the merge; four new strings in all 21 catalogs.

On the real page: Standard/Reduce 4.3 MB → 231 KB, Mobile → 161 KB, with
a rendering closer to the original than Acrobat's Mobile result (147 KB).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Refresh catalog hashes after merging main

---------

Co-authored-by: magdale76 <16279778+magdale76@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
magdale76
2026-10-15 02:25:19 -04:00
committed by GitHub
co-authored by Claude Opus 5.5 magdale76 Brandon Thomas
parent 72a46facb8
commit df0bc0ffbc
34 changed files with 803 additions and 36 deletions
+4
View File
@@ -17,6 +17,8 @@ pub enum OptimizeStage {
/// Removing the user data chosen under Discard User Data.
#[default]
Discarding,
/// Merging the fragments of a page picture into one image.
Fragments,
/// About to process image `done` (0-based) of `total`.
Images { done: usize, total: usize },
/// Discarding objects and compressing unencoded streams.
@@ -33,6 +35,7 @@ impl OptimizeStage {
pub fn fraction(self) -> f32 {
match self {
OptimizeStage::Discarding => 0.0,
OptimizeStage::Fragments => 0.03,
OptimizeStage::Images { done, total } => 0.05 + 0.75 * if total == 0 { 1.0 } else { done.min(total) as f32 / total as f32 },
OptimizeStage::CleaningUp => 0.8,
OptimizeStage::Merging => 0.85,
@@ -85,6 +88,7 @@ impl OptimizeJob {
let discarded = if discard.is_empty() { Vec::new() } else { pdfcraft_redact::sanitize::remove_hidden(&mut cos, &discard)? };
let report = optimize::optimize_with_progress(&mut cos, &settings, &mut |s| {
step(match s {
optimize::Stage::Fragments => OptimizeStage::Fragments,
optimize::Stage::Images { done, total } => OptimizeStage::Images { done, total },
optimize::Stage::CleanUp => OptimizeStage::CleaningUp,
})