Skip to content

feat: expose PDF embedded-file attachments on SegmentedPage - #313

Draft
yonikremer wants to merge 1 commit into
docling-project:mainfrom
yonikremer:feat/pdf-attachment-extraction
Draft

feat: expose PDF embedded-file attachments on SegmentedPage#313
yonikremer wants to merge 1 commit into
docling-project:mainfrom
yonikremer:feat/pdf-attachment-extraction

Conversation

@yonikremer

@yonikremer yonikremer commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Extract PDF embedded-file attachments and expose them on the parse-level page model (SegmentedPdfPage), exactly per the maintainer's direction to split the attachment feature into small PRs.

  • PdfDocument.get_attachments() -> list[PdfAttachment]eagerly decodes each attachment's binary payload into PdfAttachment.data, capped at 200 MB. Attachments above the cap (or that fail to decode) are still reported with their metadata but data=None, plus a warning.
  • PdfDocument.get_page() / get_page_with_timings() / iterate_pages() populate page.attachments — each page carries the PdfAttachments anchored to it via FileAttachmentAnnotation (page_no + bbox). Unanchored attachments (from Catalog/Names/EmbeddedFiles) live only at document level.
  • C++ (qpdf) extraction of name / MIME / size / per-page annotation positions is kept from the earlier attempt.
  • The streaming/spooling APIs (get_attachment_stream, _AttachmentDeletingFile) are deferred to the docling PR and are NOT part of this one. get_attachment_data(index, *, max_size) stays as the internal decode primitive.

⚠️ Depends on docling-core PR #1 — not mergeable until it ships

This PR hard-depends on docling-project/docling-core#734 — "page-level attachment types".

  • Core PR Add and fix cli #1 adds FileAttachmentAnnotation, PdfAttachment (including the data: bytes field), and the attachments list on SegmentedPdfPage / ParsedPdfDocument in docling_core.types.doc.page.
  • This PR imports those types directly and sets PdfAttachment.data and SegmentedPdfPage.attachments; it does not compile/run against any currently-released docling-core.
  • The pyproject.toml dependency is therefore bumped to docling-core>=2.92.0,<3.0.0 (the release that ships core PR Add and fix cli #1). CI will not pass until that release exists.

Landing order: core #734 → this PR (parse #313) → core AttachmentItem PR → docling integration.

Testing

  • tests/test_attachments.py (10 tests): binary data on PdfAttachment, 200 MB cap behavior (data=None + warning above the cap), per-page page.attachments (anchored vs unanchored), iterate_pages wiring, empty doc, caching, get_attachment_data primitive contract.
  • Smoke regression: test_attachments.py + test_parse.py — 31 passed.
  • ruff format/check clean.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

DCO Check Passed

Thanks @yonikremer, all your commits are properly signed off. 🎉

@mergify

mergify Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 Merge protection satisfied — ready to merge.

Show 1 satisfied protection

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?(!)?:

@yonikremer

Copy link
Copy Markdown
Contributor Author

@PeterStaar-IBM Hey, can you review the PR? I think it would be a great feature for docling.

Comment thread docling_parse/pdf_parser.py Outdated


class FileAttachmentAnnotation(BaseModel):
"""Position of a FileAttachment annotation on a page (0-based).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think the convention is that in C++ we use 0-based (since vectors are zero based and all memory is stored there), however the python interface should be 1-based (following the PDF convention). The goal of the python is to translate the 1 based to the 0 based.

Comment thread src/parse/qpdf/attachments.h Outdated
@PeterStaar-IBM

Copy link
Copy Markdown
Member

@yonikremer Thanks for the addition, can you:

  1. run the styling: uv run pre-commit run --all-files
  2. I would like to see if we need to migrate up the PdfAttachment to docling-core (we dont want to double define it)

@yonikremer

Copy link
Copy Markdown
Contributor Author

I wrote a PR for defining those classes in docling core: docling-project/docling-core#713. Do I need to wait for a new version of docling core or just for the PR merge?
I will run the styling

@yonikremer

Copy link
Copy Markdown
Contributor Author

@PeterStaar-IBM I updated the PR
Now it has a dependency on the pull request to docling core, which I didn't get any feedback for

@PeterStaar-IBM

Copy link
Copy Markdown
Member

@PeterStaar-IBM I updated the PR Now it has a dependency on the pull request to docling core, which I didn't get any feedback for

good, please fix the CI: docling-project/docling-core#713

Extract embedded-file attachments (name, MIME, size, page annotations, binary data) from PDFs via qpdf, and expose them through docling-core's FileAttachmentAnnotation/PdfAttachment types. get_attachments() returns PdfAttachment with eagerly-decoded data (200 MB cap; data=None + warning above), and get_page()/iterate_pages() populate page.attachments with the attachments anchored to each page. Requires docling-core >=2.92.0 (core PR #1).

Signed-off-by: yoni kremer <yoni.kremer@gmail.com>
@yonikremer
yonikremer force-pushed the feat/pdf-attachment-extraction branch from b6739d3 to 4a5fdb8 Compare August 31, 2026 19:50
@yonikremer yonikremer changed the title feat: PDF attachment extraction (metadata, bytes, streaming) feat: expose PDF embedded-file attachments on SegmentedPage Aug 31, 2026
@yonikremer

yonikremer commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Retrimmed to the small scope agreed with the maintainer (see core #734 design):

  • FileAttachmentAnnotation + PdfAttachment (with binary data) wired onto SegmentedPdfPage (types from core PR).
  • get_attachments() populates data eagerly (200 MB cap; data=None + warning above the cap).
  • get_page() / iterate_pages() populate page.attachments — each page carries the attachments anchored to it via FileAttachment annotations; unanchored attachments live only at document level.
  • Streaming/spooling APIs (get_attachment_stream, _AttachmentDeletingFile) are deferred to the docling PR. get_attachment_data stays as the internal decode primitive.
  • The dormant C++ write_attachment_data binding is retained (part of the C++ extraction layer; consumed by the deferred streaming PR).
  • Requires docling-core >= 2.92.0 (core PR).

Diff is now one commit, 7 files.

@yonikremer
yonikremer marked this pull request as draft August 31, 2026 20:10
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