pdftopdf: Honor inherited MediaBox, CropBox and Rotate attributes - #252
Merged
tillkamppeter merged 1 commit intoSep 16, 2026
Merged
Conversation
The PDFio-based cfFilterPDFToPDF() read /MediaBox, /CropBox and /Rotate only from the page dictionary itself. These attributes are inheritable (ISO 32000-1, 7.7.3.4) and producers such as macOS Quartz PDFContext define the MediaBox on the /Pages node only. Such a page fell back to the output page size, so print-scaling and auto-rotation were skipped and an oversized page was printed at 1:1, cropped to its lower-left corner. The QPDF-based code handled this through pushInheritedAttributesToPage(); the PDFio port lost it. pdfioDictGetRect() also rejects an indirect reference to the rectangle array, which is what qpdf writes when it pushes inherited attributes down to the pages, so resolve that case as well. Add page_get_rect() and page_get_rotate() helpers that walk up the /Parent chain and use them for the input page boxes in copy_page() and for the /Rotate lookup in flatten_pdf(). Add a regression test: test_files/inherited_mediabox.pdf is a single 2970x2100 pt page whose MediaBox is an indirect array on the /Pages node. test-pdftopdf-inherited-mediabox.sh runs it through the testfilters harness for Letter and reads the output back with PDFio, checking that the page transform scales by less than 0.5 and rotates by 90 degrees. Fixes OpenPrinting#251 Assisted-By: Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #251.
cfFilterPDFToPDF()read/MediaBox,/CropBoxand/Rotateonly from the page dictionary. These attributes are inheritable (ISO 32000-1, 7.7.3.4) and producers such as macOS Quartz PDFContext define the MediaBox on the/Pagesnode only, so such pages were taken to be the output page size: noprint-scaling, no auto-rotation, and an oversized page was printed 1:1 and cropped to its lower-left corner. The QPDF code handled this throughpushInheritedAttributesToPage(); the PDFio port lost it (pclmtoraster.cgot the equivalent fix in #208).pdfioDictGetRect()additionally rejects an indirect reference to the rectangle array, which is what qpdf writes when it pushes inherited attributes down, so that case is resolved as well.Changes:
page_get_rect()andpage_get_rotate()helpers inpdftopdf.cthat walk up the/Parentchain (bounded to 64 levels) and resolve an indirect rectangle array.copy_page()and for the/Rotatelookup inflatten_pdf().cupsfilters/test-pdftopdf-inherited-mediabox.sh: runstest_files/inherited_mediabox.pdf(one 2970x2100 pt page whose MediaBox is an indirect array on the/Pagesnode) through thetestfiltersharness for Letter, then reads the output back with PDFio and checks that the page transform scales by less than 0.5 and rotates by 90 degrees. It fails on current master (0.969721 0 0 0.969721 ... cm) and passes with the fix (0 -0.258592 0.258592 0 ... cm).Not changed here:
pdf.chasdict_lookup_rect()/dict_lookup_rect1()with an unusedinheritableparameter, andcopy_page()still has theTODOabout inherited/Resources. Both are the same class of problem and could use the same helper if wanted. Also noticed while writing the test:testfilters.ccopies the case file names into 100-bytemalloc()buffers withstrcpy(), so the new test deliberately uses short paths relative to the build directory.Testing:
make checkpasses, including the new test, on x86_64 with pdfio 1.6.5.pdftopdf->pdftoraster->rastertobrlaser) on a Brother HL-L2300D: the page is scaled and rotated onto Letter exactly as with 2.1.1. PowerPoint-produced files with a direct MediaBox give byte-identical output before and after the change.The analysis, patch and test were written with the help of Claude Code; I reviewed and tested them.