Skip to content

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

Closed
bundolee wants to merge 1 commit into
veraPDF:jakartafrom
bundolee:fix/line-art-streaminfo-per-operator-jakarta
Closed

bundolee wants to merge 1 commit into
veraPDF:jakartafrom
bundolee:fix/line-art-streaminfo-per-operator-jakarta

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

  • The PR touches the same file as Give each line chunk only the operator that painted it #759, with the same diff. Codacy shows action_required here with no analysis output, but on Give each line chunk only the operator that painted it #759 it reports no issues. This looks like a Codacy setup for the jakarta branch, not a code finding.
  • 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

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

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3a63ca7a-35d8-4ea6-9a79-3ab61db1fa0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • 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

Copy link
Copy Markdown
Contributor

@bundolee The jakarta branch automatically pulls in changes from integration.

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