Skip to content

PDF stage 4.8: image masks, stencil masks, soft masks#572

Merged
andiwand merged 4 commits into
mainfrom
pdf-stage-4.8
Jun 28, 2026
Merged

PDF stage 4.8: image masks, stencil masks, soft masks#572
andiwand merged 4 commits into
mainfrom
pdf-stage-4.8

Conversation

@andiwand

@andiwand andiwand commented Jun 28, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Stage 4.8 of the PDF graphics work (src/odr/internal/pdf/STAGE4_PLAN.md): render the three PDF image-transparency mechanisms (ISO 32000-1 8.9.6 / 11.6.5.2).

What

  • /ImageMask true stencils (image XObject + inline BI…ID…EI) are painted in the current fill colour, which is known only at Do time. The decoded 1-bpc bitmap + geometry are stashed on the XObject at parse time (parse_stencil_mask); the page extractor recolours it to an RGBA PNG (encode_stencil_png) using the graphics-state fill colour.
  • /SMask (alpha) and /Mask (a stencil sub-image or a colour-key array) are composited into an RGBA PNG on the raster path at parse time. resolve_mask_alpha decodes a sub-image into a base-sized coverage plane (decode_mask_alpha, nearest-neighbour resampled if the mask differs in size); encode_image / encode_image_png emit RGBA when alpha or a colour key is present.
  • New write_png_rgba (PNG colour type 6) alongside the existing RGB writer.

Limitations (documented)

A /SMask or /Mask on a JPEG (DCTDecode) base is ignored — decoding the JPEG to composite alpha is out of scope; the opaque JPEG still renders.

Tests

  • pdf_image: write_png_rgba round-trip; alpha-plane and colour-key → RGBA; encode_stencil_png (paint colour + /Decode inversion); decode_mask_alpha (soft-mask grey→alpha, stencil set-bits, resampling).
  • pdf_page_extractor: stencil image XObject and inline image mask both emit a recoloured RGBA PNG ImageElement.

All 186 PDF unit tests pass. Reference-output regeneration is left to the maintainer.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1299bea6ef

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/odr/internal/pdf/pdf_image.cpp
andiwand and others added 2 commits June 28, 2026 15:28
Render the three PDF image-transparency mechanisms (ISO 32000-1 8.9.6 /
11.6.5.2):

- `/ImageMask true` stencils (image XObject + inline `BI…ID…EI`) are painted
  in the *current fill colour*, which is known only at `Do` time — so the
  decoded 1-bpc bitmap is stashed on the XObject and the page extractor
  recolours it to an RGBA PNG (`encode_stencil_png`) with the graphics-state
  fill colour.
- `/SMask` (alpha) and `/Mask` (a stencil sub-image or a colour-key array) are
  composited into an RGBA PNG on the raster path at parse time:
  `resolve_mask_alpha` decodes a sub-image into a base-sized coverage plane
  (`decode_mask_alpha`, nearest-neighbour resampled), and `encode_image` /
  `encode_image_png` emit RGBA when alpha or a colour key is present.

Adds `write_png_rgba`. A mask on a JPEG (`DCTDecode`) base is ignored — decoding
the JPEG to composite is out of scope.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The two PNG writers differed only in the stride multiplier (3 vs 4) and
the IHDR colour-type byte (2 vs 6). Collapse them into a single
`write_png(pixels, width, height, channels)` taking the channel count,
removing the near-duplicated container-emission code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uqx1dUpDUykRxui8FYwxvM
@andiwand andiwand enabled auto-merge (squash) June 28, 2026 14:15
Align pdf_page_extractor and pdf_document_parser with the module's
prevailing convention (const on by-value scalar definition params).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uqx1dUpDUykRxui8FYwxvM
@andiwand andiwand merged commit f0f5c97 into main Jun 28, 2026
11 checks passed
@andiwand andiwand deleted the pdf-stage-4.8 branch June 28, 2026 14:47
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