Skip to content

Give each line chunk only the operator that painted it - #759

Merged
MaximPlusov merged 1 commit into
veraPDF:integrationfrom
bundolee:fix/line-art-streaminfo-per-operator
Oct 20, 2026
Merged

MaximPlusov merged 1 commit into
veraPDF:integrationfrom
bundolee:fix/line-art-streaminfo-per-operator

Conversation

@bundolee

@bundolee bundolee commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

ChunkParser.processLineArts copies the window's full paint-operator StreamInfo list onto every line chunk in the window. A window is everything painted between two text or XObject boundaries, so this makes L lines × P operators objects. A chart drawn without text in between reaches thousands of both:

  • A 55-page arXiv paper (one form with 7,500 strokes) made 56 million copies. It ran out of a 2 GB heap in parseChunks.
  • A 2.6 MB document made 325 million copies. It failed at 5 GB.
  • Over a 200-document corpus, 5 documents needed more than 2 GB for these copies alone.

The copying came in with 5d59d2d (integration) and e4ddb18 (jakarta).

Change

  • processLineChunk: when MCIDs are ignored and data-loader mode is on, a line chunk gets one StreamInfo, for the operator that painted it.
  • processLineArts: the L × P copy loop is removed. The window's LineArtChunk still gets the full list, once.

Memory goes from L × P to L + P. Validation mode is unchanged (StaticContainers.isDataLoader gate).

Dependency

The change alters what a consumer sees on a line chunk. One consumer relies on the old shape: odl-pdfua's SemanticMapper builds figures from lines and needs the whole window. opendataloader-project/odl-pdfua#171 changes it to find the window's LineArtChunk through the line's operator. That PR is merged and released in odl-pdfua 0.2.15, so this change can ship.

Evidence

The diff was applied to v1.31.200 and jakarta-v1.31.177, and only ChunkParser.class was replaced in the runtime jars. Runs used OpenDataLoaderPDF.processFile with a tagged-PDF config, in a 4 GB container.

Document Before, -Xmx2048m After, -Xmx2048m
arXiv paper OutOfMemoryError OK, ~220 MB peak
0.7 MB form-heavy document OutOfMemoryError OK, ~190 MB peak
2.6 MB document OutOfMemoryError (also at 5 GB) OK, ~1 GB peak (~600 MB at -Xmx1g)
  • 14 documents passed after the fix, plus 5 two-at-a-time runs.
  • On the 11 documents that also completed before the fix, the opendataloader-pdf tagged PDFs are byte-identical. That tagger does not read line art stream infos.
  • Two independent verifier rounds re-ran the reproduction and passed.

Review notes

  • Line chunks now carry their own operator only. Any other consumer that expects the window's list on each line must use the LineArtChunk instead.
  • wcag-validation has no test module, so no regression test was added.
  • On the parseLineArts path (MCIDs not ignored), line chunks now also get their own operator. Nothing reads them there.
  • Not changed: parseLineArts still copies the stream's unmarked operators onto every separate box (boxes × operators).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Corrected line-art metadata handling during data loading when MCIDs are ignored.
    • Metadata is now associated with the appropriate processed line rather than being duplicated across all lines.
    • Region-level metadata remains available on generated bounding-box records, improving the accuracy and consistency of extracted document structure.

processLineArts copied the window's whole operator list onto every line
chunk in it: L lines times P paint operators StreamInfo objects. A window
is everything painted between two text or XObject boundaries, so one chart
drawn without text in between reaches thousands of both. A 55-page paper
(one form with 7,500 strokes) made 56 million copies and ran out of a 2 GB
heap in parseChunks; a 2.6 MB document made 325 million and failed at 5 GB.
Over a 200-document corpus, 5 documents needed more than 2 GB for these
copies alone.

A line now carries one StreamInfo, for its own paint operator, and the full
list goes once onto the window's LineArtChunk, as it already did. Memory is
L + P instead of L x P.

This changes what a consumer sees on a line, and one relies on it:
odl-pdfua's SemanticMapper builds a figure from a region's lines and needs
the whole window, curves and fills included. It is changed alongside to find
the window's LineArtChunk through the line's operator, and through the box
when the key is ambiguous (a form drawn twice, or two forms sharing a
resource name). Land that change before this one ships.

Only data-loader mode is affected (StaticContainers.isDataLoader), so
validation is unchanged. opendataloader-pdf's own tagger does not read line
art stream infos: its tagged PDFs are byte-identical before and after on
the documents that completed before, and the two that did not now complete
in under 300 MB.

Not changed here: parseLineArts, used when MCIDs are not ignored (core's
--use-struct-tree), still copies the stream's unmarked operators onto every
separate box, boxes x operators.

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

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d487fcbb-8f84-41a0-86e0-6509ed6f7bb3
📥 Commits

Reviewing files that changed from the base of the PR and between 587e98f and 9d14769.

📒 Files selected for processing: 1
  • wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/ChunkParser.java

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

When data-loader mode is enabled and MCIDs are ignored, each processed line records its painting operator’s StreamInfo. Region-level pending stream metadata is no longer copied to every line chunk and continues to be applied to generated bounding-box artifacts.

Changes: Line-art stream metadata

Layer / File(s) Summary
Record stream metadata per line
wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/ChunkParser.java
processLineChunk records the painting operator’s StreamInfo under the specified conditions. processLineArts no longer copies region-level pending metadata to every line chunk; it continues to apply that metadata to generated bounding-box artifacts.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: maximplusov

Merge Risk: ⚪ Minimal · up to 9d147

No actionable merge-blocking risk is established; downstream release coordination remains external to this repository.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 1 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: each line chunk receives only the operator that painted it.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@bundolee
bundolee marked this pull request as ready for review October 20, 2026 09:39
@MaximPlusov
MaximPlusov merged commit eb9b71f into veraPDF:integration Oct 20, 2026
8 checks passed
bundolee added a commit to opendataloader-project/opendataloader-pdf that referenced this pull request Oct 21, 2026
1.31.206 adds one commit to 1.31.200 (veraPDF/veraPDF-validation#759):
each line chunk carries only the operator that painted it, instead of a
copy of every paint operator in its window. The copy was lines x
operators StreamInfo objects and ran out of heap in parseChunks on
documents with large vector charts.

wcag-algorithms stays pinned at 1.31.47; 1.31.206 changes only
ChunkParser in wcag-validation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants