Skip to content

Add opt-in physical page records for PDFs - #2693

Draft
Paul Wood FRSA (paultendo) wants to merge 1 commit into
microsoft:mainfrom
paultendo:proposal/pdf-page-records
Draft

Paul Wood FRSA (paultendo) wants to merge 1 commit into
microsoft:mainfrom
paultendo:proposal/pdf-page-records

Conversation

@paultendo

Copy link
Copy Markdown

I need to be able to take extracted text back to the PDF page that printed it. That needs a record for each physical page, including pages with no native text, and a failure when the parser cannot establish those readings.

This is a PDF-only implementation built directly on current main. extract_pages=True adds result.pages, containing PageInfo(page_number, content). The numbers start at 1 and refer to positions in the file, not printed numbers or PDF page labels. Normal Markdown stays unchanged, including when records are requested. An empty record does not establish that a visible page is blank or that a scan has been read.

The change keeps the normal table/prose decisions. Prose and fallback records come from pdfminer's page iterator in one pass, rather than splitting text on form-feed characters. Numbering cleanup stays within each record. A failed partial pass is discarded, recovered records must match a known page count, and page extraction errors propagate. Records are not character offsets into the flattened Markdown.

This builds on the structured API proposed in #1263 and the boundary work in #2451 and #2576. #2576 already handles physical boundaries and empty pages well; this proposal returns structured records without adding source links or changing the Markdown. It can be reviewed and merged on its own, without taking on another PR's rebasing, other formats or CLI output changes.

The synthetic comparisons reproduce specific pitfalls rather than treating every earlier approach as defective: #1263 at 7fe25ad can label the whole document as page 1 after a page-parser error; #2272 at cbf5aa4 can move text into a blank page when an embedded form-feed character is split as a page boundary. Tests here cover those cases alongside tables, repeated pages, leading/interior/trailing empty positions, page-label differences, terminal numbering, lowercase continuations, fallback cardinality and resource cleanup.

Validation: 77 PDF tests passed, with one remote test skipped. The full core-package suite passed 1,091 tests, with 57 existing remote, credential, tool and platform cases skipped. Default, explicitly disabled and enabled Markdown match unmodified main for all 16 public/synthetic PDFs, both before and after public-result normalisation. Pre-commit and diff checks pass. This was tested on macOS with Python 3.13; the other Python versions and Windows have not been run locally.

There are no new dependencies. OCR, other document formats, printed labels, links, geometry, offsets and new CLI output are outside this change.

Relates to #122 and #1317. Other related approaches reviewed include #1375, #2272, #1398, #2689 and the closed service proposal #2109. The exact-head comparison and reproduction notes distinguish executed tests from static review. This proposal does not claim to be the first provenance work or to replace every other approach.

Return immutable PageInfo records with one-based physical page numbers while preserving normal Markdown. Keep empty positions, page-local cleanup, honest fallback failures and known page-count checks.

Builds on the structured API proposed in microsoft#1263 and the page-boundary work in microsoft#2451 and microsoft#2576. Includes synthetic fixtures and regression tests; no OCR or new CLI output.
@paultendo

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

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