OpenPrinting / OpenPrinting/libcupsfilters

pdftopdf (cfFilterPDFToPDF) no longer generates soft copies with `*cupsManualCopies: True` — regression in libcupsfilters 2.2.x

Open
#226 1 comment 0 reactions 0 assignees View on GitHub

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

  1. Set up a CUPS queue with a classic raster driver whose PPD contains
    *cupsManualCopies: True and a single *cupsFilter: "application/vnd.cups-raster 0 <vendor filter>".

  2. Submit a job with more than one copy, e.g.:

    lp -d Xprinter_XP-420B -n 3 /usr/share/cups/data/testprint.ps
    
  3. 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:

  • pdftopdf is added to the chain and exits cleanly, but the document handed to Ghostscript
    evidently still contains a single copy.
  • The Ghostscript command line carries -dcupsManualCopies but 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.