Skip to content

pdftopdf: Honor inherited MediaBox, CropBox and Rotate attributes - #252

Merged
tillkamppeter merged 1 commit into
OpenPrinting:masterfrom
kk1987:pdftopdf-inherited-page-attrs
Sep 16, 2026
Merged

tillkamppeter merged 1 commit into
OpenPrinting:masterfrom
kk1987:pdftopdf-inherited-page-attrs

Conversation

@kk1987

@kk1987 kk1987 commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #251.

cfFilterPDFToPDF() read /MediaBox, /CropBox and /Rotate only 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 /Pages node only, so such pages were taken to be the output page size: no print-scaling, no auto-rotation, and an oversized page was printed 1:1 and cropped to its lower-left corner. The QPDF code handled this through pushInheritedAttributesToPage(); the PDFio port lost it (pclmtoraster.c got 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:

  • Add page_get_rect() and page_get_rotate() helpers in pdftopdf.c that walk up the /Parent chain (bounded to 64 levels) and resolve an indirect rectangle array.
  • Use them for the input page CropBox/MediaBox in copy_page() and for the /Rotate lookup in flatten_pdf().
  • Add cupsfilters/test-pdftopdf-inherited-mediabox.sh: runs test_files/inherited_mediabox.pdf (one 2970x2100 pt page whose MediaBox is an indirect array on the /Pages node) through the testfilters harness 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.c has dict_lookup_rect()/dict_lookup_rect1() with an unused inheritable parameter, and copy_page() still has the TODO about inherited /Resources. Both are the same class of problem and could use the same helper if wanted. Also noticed while writing the test: testfilters.c copies the case file names into 100-byte malloc() buffers with strcpy(), so the new test deliberately uses short paths relative to the build directory.

Testing:

  • make check passes, including the new test, on x86_64 with pdfio 1.6.5.
  • Verified with the original macOS-produced document through the full CUPS chain (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.

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
@tillkamppeter
tillkamppeter merged commit c5dc208 into OpenPrinting:master Sep 16, 2026
15 checks passed
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.

pdftopdf: inherited /MediaBox (defined on the /Pages node) is ignored since the PDFio port, pages printed 1:1 and cropped, no auto-rotation

2 participants