OpenPrinting / OpenPrinting/libcupsfilters
pdftopdf (cfFilterPDFToPDF) no longer generates soft copies with `*cupsManualCopies: True` — regression in libcupsfilters 2.2.x
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 17
- Forks
- 71
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 13
Description
pdftopdf (cfFilterPDFToPDF) no longer generates soft copies with *cupsManualCopies: True — regression in libcupsfilters 2.2.x
Summary
After upgrading libcupsfilters 2.1.1 → 2.2.1, printing with copies > 1 to a raster-driver
queue produces exactly one copy. The queue uses a classic CUPS raster driver
(*cupsFilter: "application/vnd.cups-raster 0 rastertosnailtspl-xprinter") whose PPD has
*cupsManualCopies: True, so the copies must be produced in software by
pdftopdf / cfFilterPDFToPDF().
pdftopdf runs and exits with status 0, but the page count is not multiplied: Ghostscript is
subsequently invoked without any copy count (no /NumCopies), and only a single copy reaches
the printer.
Nothing else changed on the system: the same queue, same PPD and same vendor filter worked
correctly with libcupsfilters 2.1.1. Downgrading libcupsfilters back to 2.1.1 is the only change
needed to restore correct behaviour.
libcupsfilters 2.2.0 rewrote cfFilterPDFToPDF() from C++/QPDF to C/PDFio, which appears to be
where the regression was introduced:
https://openprinting.github.io/libcupsfilters-2.2.0
Environment
| Item | Value |
|---|---|
| Distribution | CachyOS (Arch Linux based), x86_64 |
| cups | 2:2.4.19-1 |
| cups-filters | 2.0.1-2.1 |
| libppd | 2.1.1-2.1 |
| libcupsfilters | 2.2.1-2.1 (broken) / 2.1.1-4.4 (works) |
| Printer | Xprinter XP-420B (203 dpi thermal label printer, USB) |
| Driver | xprinter-cups 3.13.55-2 (vendor CUPS raster filter rastertosnailtspl-xprinter) |
| Ghostscript | in filter chain via cfFilterGhostscript |
Relevant PPD lines:
*cupsManualCopies: True
*cupsFilter: "application/vnd.cups-raster 0 rastertosnailtspl-xprinter"
Exact upgrade timestamp from /var/log/pacman.log:
[2026-08-31T10:48:08+0300] [ALPM] upgraded libcupsfilters (2.1.1-4.4 -> 2.2.1-2.1)
The breakage was noticed the same day.
Steps to reproduce
-
Set up a CUPS queue with a classic raster driver whose PPD contains
*cupsManualCopies: Trueand a single*cupsFilter: "application/vnd.cups-raster 0 <vendor filter>". -
Submit a job with more than one copy, e.g.:
lp -d Xprinter_XP-420B -n 3 /usr/share/cups/data/testprint.ps -
Observe the output.
Expected behaviour
Three copies are printed. Because the printer cannot generate copies in hardware and
*cupsManualCopies: True is set, cfFilterPDFToPDF() should replicate the pages so that the
downstream raster chain rasterises three copies.
Actual behaviour
Exactly one copy is printed, regardless of the requested copy count. Reproducible both from
lp -n N and from GUI print dialogs, so it is not an application-side issue.
Debug log (cupsctl --debug-logging)
D [01/Sep/2026:00:08:54 +0300] [Job 414] rastertosnailtspl-xprinter (application/vnd.cups-raster to printer/Xprinter_XP-420B, cost 0)
I [01/Sep/2026:00:08:54 +0300] [Job 414] Started filter /usr/lib/cups/filter/rastertosnailtspl-xprinter (PID 65037)
D [01/Sep/2026:00:08:54 +0300] [Job 414] ppdFilterLoadPPD: Last filter determined by the PPD: rastertosnailtspl-xprinter; Final data MIME type: application/vnd.cups-raster => PDF filter will not log pages in page_log.
D [01/Sep/2026:00:08:54 +0300] [Job 414] ppdFilterUniversal: application/vnd.cups-raster 0 rastertosnailtspl-xprinter
D [01/Sep/2026:00:08:54 +0300] [Job 414] cfFilterUniversal: Adding pdftopdf to chain
D [01/Sep/2026:00:08:54 +0300] [Job 414] cfFilterChain: Running filter: pdftopdf
D [01/Sep/2026:00:08:54 +0300] [Job 414] Set job-printer-state-message to "cfFilterChain: Running filter: pdftopdf", current level=INFO
D [01/Sep/2026:00:08:54 +0300] [Job 414] cfFilterChain: pdftopdf (PID 65043) started.
D [01/Sep/2026:00:08:54 +0300] [Job 414] Set job-printer-state-message to "cfFilterChain: pdftopdf (PID 65043) started.", current level=INFO
D [01/Sep/2026:00:08:54 +0300] [Job 414] cfFilterChain: pdftopdf completed with status 0.
D [01/Sep/2026:00:08:54 +0300] [Job 414] cfFilterGhostscript: Ghostscript command line: gs -dQUIET -dSAFER -dNOPAUSE -dBATCH -dNOINTERPOLATE -dNOMEDIAATTRS -dUsePDFX3Profile -sstdout=%stderr -sOutputFile=%stdout -sDEVICE=cups -r203x203 -dDEVICEWIDTHPOINTS=288 -dDEVICEHEIGHTPOINTS=432 -dcupsBitsPerColor=8 -dcupsColorOrder=0 -dcupsColorSpace=3 -dcupsRowCount=8 -scupsRenderingIntent=auto -scupsPageSizeName=4x6.Borderless -dcupsManualCopies -I/usr/share/cups/fonts -c '<< /.HWMargins[0.000000 0.000000 0.000000 0.000000] /Margins[0 0]>>setpagedevice' -f -_
D [01/Sep/2026:00:08:55 +0300] [Job 414] cfFilterChain: pdftopdf (PID 65043) exited with no errors.
D [01/Sep/2026:00:08:55 +0300] [Job 414] Set job-printer-state-message to "cfFilterChain: pdftopdf (PID 65043) exited with no errors.", current level=INFO
D [01/Sep/2026:00:08:55 +0300] [Job 414] PID 65037 (/usr/lib/cups/filter/rastertosnailtspl-xprinter) exited with no errors.
Two things stand out:
pdftopdfis added to the chain and exits cleanly, but the document handed to Ghostscript
evidently still contains a single copy.- The Ghostscript command line carries
-dcupsManualCopiesbut no copy count, so no copies can
be produced downstream either — the copies are silently lost between the job attributes and the
rasteriser.
Workaround
Confirmed: downgrading libcupsfilters to 2.1.1 restores correct multi-copy printing with the
same PPD, same queue and same vendor filter, with no other changes to the system. Re-installing
2.2.1 brings the single-copy behaviour back.
pacman -U /var/cache/pacman/pkg/libcupsfilters-2.1.1-4.4-x86_64.pkg.tar.zst
systemctl restart cups
Additional notes
This configuration — a classic (non-driverless) CUPS raster driver relying on
*cupsManualCopies: True for software copy generation — may not be covered by the new
cupsfilters/test-filter-cases.txt CI cases added in 2.2.0. A regression test asserting that
cfFilterPDFToPDF() multiplies the page count when num-copies > 1 and
cupsManualCopies is true would catch this.
Happy to provide additional debug logs, the full PPD, or to test patches.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with cfFilterPDFToPDF() and the cupsfilters/test-filter-cases.txt cases added in 2.2.0. Reproduce a job with num-copies greater than 1 and cupsManualCopies true, then trace whether the generated PDF or Ghostscript invocation preserves the copy count. Done means a regression test covers the classic raster-driver configuration and multiple copies are produced again.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100