Skip to content

Combine image soft masks of a different size at the larger resolution - #560

Merged
Velli20 merged 1 commit into
mainfrom
resample-mismatched-soft-masks
Oct 11, 2026
Merged

Velli20 merged 1 commit into
mainfrom
resample-mismatched-soft-masks

Conversation

@Velli20

@Velli20 Velli20 commented Oct 11, 2026

Copy link
Copy Markdown
Owner

Summary

An image's /SMask may have different dimensions from the image itself, since both map onto the unit square. The decoder paired mask and image pixels one to one. A low-resolution color image therefore kept its own size and took its alpha from only the first few mask samples.

Some producers draw each line of text as a 2×2 single-color image whose full-resolution soft mask holds the glyph shapes. Those lines rendered fully transparent, so the page appeared to have no text.

When the sizes differ, the decoder now:

  • enlarges whichever of the image and mask is smaller by nearest-neighbour sampling, to the larger width and the larger height;
  • combines them with the existing alpha path.

When the sizes already match, nothing changes.

Changes

  • pdf-image/src/raster.rs: resample_nearest scales a Gray8 or RGBA image to a target size. It tolerates short decoder buffers and returns a resource-limit error if the size overflows or allocation fails.
  • pdf-image/src/image_decoder.rs: apply_resized_soft_mask handles mismatched sizes. The existing assembly code moved into render_ready_image.
  • pdf-image/src/error.rs: PdfImageError::Raster wraps ImageRasterError.

Test plan

  • cargo conformance render on an affected document: text lines that were missing now render in their colors.
  • cargo test -p pdf-image -p pdf-graphics -p pdf-resources -p pdf-canvas, cargo clippy --all --workspace, cargo fmt --check.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Conformance reads

No document reads differently from the base commit any more.

840 documents of the PDFium corpus read as on 5fc63f6.
1008 documents of the pdf.js corpus read as on 5fc63f6.

Workflow run

An /SMask may have different dimensions from its image, since both map
onto the unit square. The decoder paired mask and image pixels one to
one, so a low-resolution color image kept its own size and took its
alpha from the first few mask samples. Images that carry glyph shapes
in a full-resolution mask over a 2x2 single-color image rendered fully
transparent, leaving pages without their text.

Combine the two at the larger width and the larger height, capped at 4M
pixels unless the image alone is larger, by dividing both axes by the
smallest whole factor that fits; a mask can be far finer than the area
it is drawn on. Build the result in one pass: each output pixel takes
its color from the image pixel it falls in and its coverage from a 2x2
grid of mask samples over the area it covers, so the work follows the
output size rather than the mask's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Velli20
Velli20 force-pushed the resample-mismatched-soft-masks branch from 6bf820c to eed107a Compare October 11, 2026 12:27
@Velli20
Velli20 merged commit d97eddc into main Oct 11, 2026
10 checks passed
@Velli20
Velli20 deleted the resample-mismatched-soft-masks branch October 11, 2026 12:37
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.

1 participant