Skip to content

pdftopdf QPDF: Ghostscript transparency performance optimization#147

Open
ValdikSS wants to merge 2 commits into
OpenPrinting:2.1.xfrom
ValdikSS:qpdf-performance-2.1.x
Open

pdftopdf QPDF: Ghostscript transparency performance optimization#147
ValdikSS wants to merge 2 commits into
OpenPrinting:2.1.xfrom
ValdikSS:qpdf-performance-2.1.x

Conversation

@ValdikSS
Copy link
Copy Markdown
Member

@ValdikSS ValdikSS commented May 25, 2026

Forward-port of the same changes for cups-filters 1.x: OpenPrinting/cups-filters#669
Original issue: OpenPrinting/cups-filters#569


When pdftopdf moves all the Page option definitions into wrapping XObject, moving Transparency Group into XObject declaration prevents Ghostscript from detecting fake transparency (when the transparency is defined but not used), which slows the document rasterization.

Keep Transparency Group in Page declaration unless two or more pages with different transparency options are printed:

  • no number-up: TG is in Page
  • number-up=X, same TGs in each page: TG is in Page
  • number-up=X, different TGs: fall back to TG in XObjects

See OpenPrinting/cups-filters#569 (comment) and https://bugs.ghostscript.com/show_bug.cgi?id=707523#c6 for more information.

Test case

price.pdf file has /S /Transparency group defined for each page, pages 1-3 have fake transparency with only text, and only page 4 has a picture.

$ ./pdftopdf-original 1 1 1 1 'PageSize=A4 fitplot' price.pdf > price_original.pdf
$ ./pdftopdf-patched 1 1 1 1 'PageSize=A4 fitplot' price.pdf > price_patched.pdf

# Non-processed PDF file
$ time gs -dQUIET -dBATCH -dSAFER -dNOPAUSE -sDEVICE=cups -sOutputFile=%stdout -sstdout=%stderr -r600 -dDEVICEWIDTHPOINTS=595 -dDEVICEHEIGHTPOINTS=842 \
 -f price.pdf > /dev/null

INFO: Start rendering...
INFO: Processing page 1...
INFO: Processing page 2...
INFO: Processing page 3...
INFO: Processing page 4...
INFO: Processing page 5...
INFO: Rendering completed

real    0m0,362s
user    0m0,316s
sys     0m0,044s


# Processed with current pdftopdf code, Transparent Group is in each wrapper XObject
$ time gs -dQUIET -dBATCH -dSAFER -dNOPAUSE -sDEVICE=cups -sOutputFile=%stdout -sstdout=%stderr -r600 -dDEVICEWIDTHPOINTS=595 -dDEVICEHEIGHTPOINTS=842 \
 -f price_original.pdf > /dev/null

INFO: Start rendering...
INFO: Processing page 1...
INFO: Processing page 2...
INFO: Processing page 3...
INFO: Processing page 4...
INFO: Processing page 5...
INFO: Rendering completed

real    0m1,117s
user    0m1,036s
sys     0m0,076s


# Processed with patch, Transparent Group is in Page
$ time gs -dQUIET -dBATCH -dSAFER -dNOPAUSE -sDEVICE=cups -sOutputFile=%stdout -sstdout=%stderr -r600 -dDEVICEWIDTHPOINTS=595 -dDEVICEHEIGHTPOINTS=842 \
 -f price_patched.pdf > /dev/null

INFO: Start rendering...
INFO: Processing page 1...
INFO: Processing page 2...
INFO: Processing page 3...
INFO: Processing page 4...
INFO: Processing page 5...
INFO: Rendering completed

real    0m0,340s
user    0m0,306s
sys     0m0,032s

I've tested the patch accross my small collection of PDF files, and special transparency testing files (here and also this one), and all of them produce identical byte-to-byte rasterization result with and without the patch.
However I'm not versed in PDF at all, that's why think of this MR as a draft proposal, it need some additional validation that this approach is correct in all cases.

ValdikSS added 2 commits May 25, 2026 10:30
…age.

To adapt the PDF for printing, pdftopdf wraps each page of the PDF file
into XObject, moving all the page properties inside it, and defining new
MediaBox / Matrix for the Page.

However moving Transparency Group into wrapping XObject prevents Ghostscript
from detecting "fake transparency"—situation when the transparency is defined
but not really used or needed.
Transparency processing significantly slows down Ghostscript.

Keep Transparency Group in Page declaration, do not move it into XObject.

Fixes: OpenPrinting/cups-filters#569
Link: https://bugs.ghostscript.com/show_bug.cgi?id=707523
Link: OpenPrinting/cups-filters#569
If we're printing multiple PDF pages on a single physical page, and they
have different Transparency Group definitions (with different color spaces
or other parameters), fall back to the original code where we do not promote
Transparency Group into Page declaration.
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