PDF stage 4.5: image XObjects — JPEG (DCTDecode) pass-through#563
PDF stage 4.5: image XObjects — JPEG (DCTDecode) pass-through#563andiwand wants to merge 1 commit into
Conversation
Render image XObjects invoked by `Do`, starting with JPEGs the browser can decode itself (ISO 32000-1 8.9 / 8.10.5). - The filter framework already hands back a `DCTDecode` payload undecoded (`stopped_at_filter`). `parse_x_object` now reads an image XObject's bytes at parse time and, for a non-`/ImageMask` JPEG, keeps the raw payload + `image/jpeg` mime on the `XObject`. Other codecs (Flate/LZW raster, masks) leave it empty for later stages. - A new `ImageElement` joins the page-element variant: the CTM in effect at `Do` (its unit square maps to user space), the snapshotted clip and the encoded bytes. `invoke_x_object` emits one for a pass-through image. - HTML: an `<image>` in the page `<svg>` (so it layers by paint order), placed by `flip * CTM * to_box` — the vertical flip accounts for the image's first row being its top — with a `data:image/jpeg;base64` href and the clip applied via `clip-path`. Tested at the extractor level (placement by the CTM, the no-pass-through skip, clip snapshot, paint-order interleaving) and verified end to end: the odr engine renders `speisekarte_helmarts.pdf` with four `<image>` tags carrying JPEG data URIs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F7Lp7cZPX84gvGmaGA6bHq
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c61143729f
ℹ️ 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".
| decode_parms = | ||
| parser.deep_resolve_object_copy(dictionary["DecodeParms"]); | ||
| } | ||
| DecodeResult result = decode(filter, decode_parms, std::move(raw)); |
There was a problem hiding this comment.
Avoid decoding images that will be skipped
When a page resource contains a non-JPEG Image XObject with a filter chain the generic decoder does not support for raster images, this unconditional decode() throws during parse_resources even though the image is supposed to be skipped. For example, a /FlateDecode image using TIFF predictor parameters that apply_tiff_predictor rejects will now abort rendering of the whole PDF, including text and paths; before this change image XObjects were ignored, and the nearby comment says non-JPEG codecs should just leave image_data empty. Check the filter chain for a pass-through DCT case, or catch non-pass-through decode failures, before decoding skipped images.
Useful? React with 👍 / 👎.
Stage 4.5: render image XObjects invoked by
Do, starting with JPEGs the browser decodes itself (ISO 32000-1 8.9 / 8.10.5). Stacked on #562 (4.4).What changed
DCTDecodepayload undecoded.parse_x_objectnow reads an image XObject's bytes at parse time and, for a non-/ImageMaskJPEG, keeps the raw payload +image/jpegmime on theXObject. Other codecs (Flate/LZW raster, masks) leave it empty for later stages, soDoskips them.ImageElementjoins the page-element variant: the CTM atDo(its unit square maps to user space), the snapshotted clip, and the encoded bytes.invoke_x_objectemits one for a pass-through image.<image>in the page<svg>(so it layers by paint order), placed byflip * CTM * to_box— the vertical flip accounts for the image's first row being its top — with adata:image/jpeg;base64href and the clip applied viaclip-path.Tests
Extractor-level: placement by the CTM, the no-pass-through skip, clip snapshot, paint-order interleaving. Verified end to end: the odr engine renders
speisekarte_helmarts.pdfwith four<image>tags carrying real JPEG (/9j/…) data URIs. Full suite green.🤖 Generated with Claude Code