Skip to content

Convert non-device image samples without whole-image intermediates - #562

Merged
Velli20 merged 1 commit into
mainfrom
fix-jpx-image-read-memory
Oct 11, 2026
Merged

Velli20 merged 1 commit into
mainfrom
fix-jpx-image-read-memory

Conversation

@Velli20

@Velli20 Velli20 commented Oct 11, 2026

Copy link
Copy Markdown
Owner

Fixes #520

Cause

issue19517 (pdf.js corpus) is one page with a 12608×16806 JPEG 2000 image in [/ICCBased] (alternate DeviceRGB) and a same-size soft mask. Reading it peaked at 5.5 GB, above the 3 GB worker limit:

  • non-device samples were widened to a whole-image Vec<f32> (~2.5 GB) before color conversion, in both the JPX and the plain-sample paths
  • image_from_rgba copied the full RGBA buffer (~850 MB) to multiply in the soft mask

Fix

  • pdf-image: a ComponentDomain converts samples to RGBA one pixel at a time, which replaces both whole-image f32 buffers. image_from_rgba reuses the uniquely owned buffer (Vec::from(Bytes)) instead of copying it.
  • pdf-color-space: ColorSpace::device_equivalent. An ICCBased space whose alternate is a device space (or that has no alternate) is decoded as that device space. That is exactly what ICCBasedColorSpace::apply already draws, so the per-pixel conversion is skipped for such images.
  • pdf-decode: DecodeMap::apply_to_f32 now writes into a caller-provided slice, so it works per pixel.

Peak RSS 5.5 GB → 2.2 GB. Read time in the regression build 57 s → 8 s. The memory fix alone timed out at 65 s, which is why the ICC shortcut is included.

Verification

  • cargo conformance verify conf2-bb565df26b2e: ✓ pass
  • cargo conformance render: the page shows the full-page red image the upstream report expects
  • cargo test, cargo clippy --all --workspace -- -D warnings, cargo fmt

No new unit test was added, following this workspace's practice of not adding new tests. The existing pdf-image and pdf-decode tests cover the Lab, Indexed, DeviceN-alpha, /Decode and soft-mask paths.

🤖 Generated with Claude Code

Reading a 12608x16806 JPEG 2000 image in an ICCBased space with a soft
mask peaked at 5.5 GB: every sample was widened to f32 before color
conversion, and the RGBA buffer was copied again to apply the mask.

Samples are now converted to RGBA one pixel at a time, the soft mask is
multiplied into the decoded buffer in place, and an ICCBased space whose
alternate is a device space is decoded as that device space, which is how
it is drawn until ICC color management exists. The read now peaks at
2.2 GB and takes 8 s instead of 57 s in the regression build.

Fixes #520

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

Copy link
Copy Markdown

Conformance reads

Documents that Safe-PDF reads differently from the base commit, compared with PDFium. A read
regresses when Safe-PDF fails to open a document it opened before, crashes or times out, or
counts a different number of pages than PDFium.

pdf.js corpus

1008 documents compared with 519b4eb: 1 read worse, 1 read better.

Regressions

Document Base This pull request
issue17190_1 timeout: time limit exceeded (stage safe-read) crash: memory limit exceeded (stage safe-read)

Improvements

Document Base This pull request
issue19517 crash: memory limit exceeded (stage safe-read) read, 1 page

840 documents of the PDFium corpus read as on 519b4eb.

Details are in the job summaries of the workflow run. Rerun a case locally with
cargo conformance run --corpus <corpus> --read-only --case <id>.

@Velli20
Velli20 merged commit a02dc06 into main Oct 11, 2026
10 checks passed
@Velli20
Velli20 deleted the fix-jpx-image-read-memory branch October 11, 2026 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[conformance] Crash: memory limit exceeded

1 participant