[Printing-architecture] Filter Functions - Getting years of development in cups-filters into Printer Applications
till.kamppeter at gmail.com
Mon Aug 3 13:27:22 UTC 2020
TL;DR: Another step towards cups-filters 2.0: Filter functions
we are currently in the middle of the development of the new concept for
printer and scanner drivers, the Printer Applications. Thanks to Michael
Sweet for introducing this concept and for creating the base library for
Printer Applications, PAPPL:
Also thanks for all the contributors, especially our GSoC students.
A first example of a PAPPL-based Printer Application got posted:
Looking into it I have started thinking about how to create Printer
Applications to port classic printer drivers (consisting of filters and
PPD files) and PostScript PPDs (special case of classic printer drivers)
into Printer Applications.
See also the former threads here:
Printer Applications: Retro-fitting classic drivers:
PostScript printers without PPD files?:
Canceling jobs in Printer Applications:
The Printer Application for PostScript printers has to output
PostScript, with code snippets from the PPD file embedded and the
PostScript generated primarily from PDF as applications usually send
jobs in PDF and going through an interim Raster state would make
everything very awkward and also cause problems on older PostScript
So the Printer Application has to accept PDF as main input format and
turn it into PostScript, then embed the code snippets from the PPD.
On this process we have worked and optimized for years, in the
cups-filters project, especially flatten filled in forms and annotations
in PDF input files, work around many PostScript interpreter bugs in
printers, assure correct page geometry for the output, printing only
selected pages, reverse order, number-up, ... So the best is to use the
filters of cups-filters or at least their code also in Printer Applications.
But Printer Applications have a different filter concept than CUPS,
having one filter turning the input data in printer-ready output, this
done by a function in the code of the Printer Application, in contrast
to CUPS which calculates a chain of filters needed for the job and calls
these as external executables.
Therefore I have started working on a new filter concept for
cups-filters 2.0 (coming soon), the filter functions. The plan is to
turn every filter into a filter function, available in libcupsfilters.
The functions have a common interface and a common data structure to
supply job and printer properties to them. Additional functions will be
created to call a given chain of filter functions or to find out a
suitable filter chain for a given job.
To continue support for CUPS wrappers will be supplied which allow the
call of each filter by the usual external executable in
You find a working example in the GitHub of cups-filters;
The filter functions reside in the libcupsfilters library. All
definitions regarding them you see in the cupsfilters/filter.h file:
The filter functions have the following properties:
- They take an input stream and produce an output stream, specified by
- They take all printer and job properties in a data structure
(filter_data_t), in case of chaining filters each filter is supposed to
get the same structure
- Job and printer properties can be supplied as IPP attributes but also
with option lists and PPDs (for retro-fits), dpending on what is more
- They are all called with the same scheme (filter_function_t), so one
can simply put together chains of these functions by supplying an array
fo filter functions to a filter chain execution function (not yet
- Logging is done through a callback function (filter_logfunc_t), so it
can be easily adapted to the environment.
As a working example and as part for a PostScript printer support
Printer Application I have converted the pstops filter of CUPS into the
filter function pstops(). See cupsfilters/filter.h,
cupsfilters/pstops.c, an cupsfilters/filter.c:
The behavior of the function is exactly the same as the original filter,
I only changed its interfaces for input, output, and logging.
I also created a logging function for CUPS logging (cups_logfunc()), so
that if the filter function is used for a CUPS filter one easily gets
the logging needed by CUPS,
Making a CUPS filter from a single filter function is easy. See the
wrapper which I have made for pstops(), filter/pstops.c:
Note that this filter does not get compiled and installed by default, so
that the standard installation of cups-filters does not clash with CUPS.
To try it out you need to run
Note that this pstops filter needs the current libcupsfilters, as its
"dirty work" happens there.
I have also modified the pdftops filter which used to call pstops of
CUPS as an external executable, Now it calls the pstops() filter
function instead, which made handling of options much easier.
My plans are to get all the filters of cups-filters turned into filter
functions, to make cups-filters an easy-to-use filter repository also
for Printer Applications.
Non-PPD-only filter functions (probably all except pstops and
foomatic-rip) should also work with only IPP-based job and printer
In addition I want to add more conditional compiling and ./configure
options to make special lightweight builds of cups-filters for Printer
Application Snaps, for example leaving out all PPD-dependent (which uses
libppd), all QPDF-dependent, Raster-only Printer Application, ... and
naturally also leaving out cups-browsed.
Any contributions are highly welcome.
More information about the Printing-architecture