All of lore.kernel.org
 help / color / mirror / Atom feed
* [Printing-architecture] Use of filter functions in CUPS 2.x and 3.x
@ 2021-12-13 21:06 Till Kamppeter
  2022-01-20 13:53 ` Zdenek Dohnal
  0 siblings, 1 reply; 3+ messages in thread
From: Till Kamppeter @ 2021-12-13 21:06 UTC (permalink / raw)
  To: Open Printing; +Cc: Pranshu Kharkwal

Hi,

with the background of CUPS 3.x, planned to get released 2 years from 
now, not supporting PPD files any more and only considering driverless 
IPP printers I have changed the architecture of cups-filters, converting 
filter executables (CUPS filters) into filter functions (library 
functions doing a filter's task, with standardized call 
scheme/interface) so that the code of the filters is preserved but they 
get more universally usable.

https://openprinting.github.io/OpenPrinting-News-October-2021/#cups

In addition I have created some auxiliary functions (partially filter 
functions by themselves) to call filter functions in a chain, feed data 
into filter through a pipe, call classic CUPS external filter/backend 
executable wrapped into a filter function, save data stream between 
chained filter function calls into a file for debugging, ...

https://openprinting.github.io/news/
https://github.com/OpenPrinting/cups-filters

With this I was especially able to create Printer Applications 
retro-fitting classic CUPS printer drivers, an important step to be able 
to switch to a PPD-less and driverless CUPS without dropping support for 
legacy printers.

https://snapcraft.io/search?q=OpenPrinting
https://github.com/OpenPrinting/pappl-retrofit

Now I am also thinking about making use of the filter functions somehow 
in CUPS, both to get improvement in the upcoming 2 years where CUPS 
still supports PPD files and classic drivers and also in PPD-less CUPS 
3.x, where data-format conversions are still needed, as for example 
print jobs usually come in PDF but it is not required for a driverless 
IPP printer to support PDF. Also implementation of functionality like 
N-up or flattening filled PDF forms (both tasks currently done by 
pdftopdf) is needed in CUPS 3.x.

We should do our best to avoid duplicate code in OpenPrinting and not 
re-invent the wheel.


"universal" filter for CUPS
---------------------------

https://gist.github.com/pranshukharkwal/9413499a6744049ef549159948392023

As a first approach to improve PPDish CUPS 2.4.x and 2.5.x I have run 
the GSoC project of a universal CUPS filter, where one single CUPS 
filter executable does all the filtering for a job by calling filter 
functions, in a chain if needed. This reduces the number of external 
executable calls by CUPS vastly, as normally CUPS calls for each filter 
to run first the cups-exec helper program and cups-exec then calls the 
filter executable, making up 2 external executable calls per filter.

The filter function chaining in the universal CUPS filter still does a 
fork for each filter function though and pipes the print data from 
filter function to filter function. Also filters of printer drivers and 
CUPS backends are not part of the universal filter and need to get 
called separately by CUPS.

The disk space saved is low, as with cups-filters 2.x each filter 
executable in /usr/lib/cups/filters/ is only a little code stub calling 
the actual filter function in libcupsfilters,

Also the universal filter still needs a fix to work correctly with PPD 
files which use "cupsFilter2" instead of "cupsFilter" lines.

So it is a little bit of a question whether it is really worth the 
effort to replace the individual filters called by CUPS 2.4.x and 2.5.x 
by this universal filter, especially also that we have only more 2 years 
where CUPS uses PPD files.

So before I complete this (if not, the universal filter will at least be 
used to make cups-browsed's "implicitclass" backend use filter functions 
instead of external filters) I want to hear some opinions about this, 
especially also whether actually saving external executable calls is 
more resource-saving than for example saving forked parallel tasks and 
pipes between them.


Forking and piping vs. one filter after the other
-------------------------------------------------

In general if forking and piping for a filter chain consumes much more 
than calling each filter function one after the other directly and let 
them write their output into temporary files for the next filter 
functions in the chain reading from the previous filter function's temp 
file I am also thinking about adding a second mode to filterChain() to 
let it operate this way. WDYT?


Using filter functions directly in CUPS
---------------------------------------

And, finally, should we make the filter functions be directly used by 
CUPS, either that in CUPS 2.5.x in scheduler/job.c we call filter 
functions instead of external filter executables (at least for standard, 
non-driver filters), or that for CUPS 3.x we do the needed file format 
conversions by filter function calls (there are no driver filters)? 
Backends could also be converted to filter functions and be directly 
called. WDYT?

Also, do we need extra functionality in the filter function concept for 
using it directly in CUPS? For example add a field to the records of the 
filter functions called by filterChain() to tell as which user each 
individual filter function should get run?

Also, if we want CUPS to use filter functions, we need to do 
re-structuring to avoid circular dependencies, as libcupsfilters uses 
libcups and if a function in libcups would call a filter function of 
libcupsfilters, libcups is using libcupsfilters, ... The planned 
splitting of libcups, local CUPS daemon, sharing CUPS daemon of CUPS 3.x 
could help here as if the daemons call filter functions but not libcups, 
we will not get a circular dependency. WDYT?


It would be great if we could discuss these topics before finalizing 
cups-filters 2.x

    Till

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Printing-architecture] Use of filter functions in CUPS 2.x and 3.x
  2021-12-13 21:06 [Printing-architecture] Use of filter functions in CUPS 2.x and 3.x Till Kamppeter
@ 2022-01-20 13:53 ` Zdenek Dohnal
  2022-01-20 16:23   ` Till Kamppeter
  0 siblings, 1 reply; 3+ messages in thread
From: Zdenek Dohnal @ 2022-01-20 13:53 UTC (permalink / raw)
  To: Till Kamppeter; +Cc: Open Printing, Pranshu Kharkwal

[-- Attachment #1: Type: text/plain, Size: 7306 bytes --]

Hi Till,

I'm sorry for answering this late - HDD got wasted, Christmas, all new year
responsibilities and I'm not particularly strong on my feet regarding
filters, so I'm not sure whether my feedback will relevant, but so there it
is:

On Mon, Dec 13, 2021 at 10:07 PM Till Kamppeter <till.kamppeter@gmail.com>
wrote:

> Hi,
>
> with the background of CUPS 3.x, planned to get released 2 years from
> now, not supporting PPD files any more and only considering driverless
> IPP printers I have changed the architecture of cups-filters, converting
> filter executables (CUPS filters) into filter functions (library
> functions doing a filter's task, with standardized call
> scheme/interface) so that the code of the filters is preserved but they
> get more universally usable.
>

Kudos for doing that! I would propose to leave each filter binaries for
check/test target and use them in the test suite. IMO it would be great to
know that at least common use cases work the same way as with the previous
filter binaries.


>
> Now I am also thinking about making use of the filter functions somehow
> in CUPS, both to get improvement in the upcoming 2 years where CUPS
> still supports PPD files and classic drivers and also in PPD-less CUPS
> 3.x, where data-format conversions are still needed, as for example
> print jobs usually come in PDF but it is not required for a driverless
> IPP printer to support PDF. Also implementation of functionality like
> N-up or flattening filled PDF forms (both tasks currently done by
> pdftopdf) is needed in CUPS 3.x.
>

Agreed - IMO it is sensible to spread new features in the timeframe instead
of putting all changes into work at once and got hit by numerous possible
issues.


>
> We should do our best to avoid duplicate code in OpenPrinting and not
> re-invent the wheel.
>
+1

>
>
> "universal" filter for CUPS
> ---------------------------
>
> https://gist.github.com/pranshukharkwal/9413499a6744049ef549159948392023
>
> As a first approach to improve PPDish CUPS 2.4.x and 2.5.x I have run
> the GSoC project of a universal CUPS filter, where one single CUPS
> filter executable does all the filtering for a job by calling filter
> functions, in a chain if needed. This reduces the number of external
> executable calls by CUPS vastly, as normally CUPS calls for each filter
> to run first the cups-exec helper program and cups-exec then calls the
> filter executable, making up 2 external executable calls per filter.
>
> The filter function chaining in the universal CUPS filter still does a
> fork for each filter function though and pipes the print data from
> filter function to filter function. Also filters of printer drivers and
> CUPS backends are not part of the universal filter and need to get
> called separately by CUPS.
>
> The disk space saved is low, as with cups-filters 2.x each filter
> executable in /usr/lib/cups/filters/ is only a little code stub calling
> the actual filter function in libcupsfilters,
>
> Also the universal filter still needs a fix to work correctly with PPD
> files which use "cupsFilter2" instead of "cupsFilter" lines.
>
> So it is a little bit of a question whether it is really worth the
> effort to replace the individual filters called by CUPS 2.4.x and 2.5.x
> by this universal filter, especially also that we have only more 2 years
> where CUPS uses PPD files.
>
> So before I complete this (if not, the universal filter will at least be
> used to make cups-browsed's "implicitclass" backend use filter functions
> instead of external filters) I want to hear some opinions about this,
> especially also whether actually saving external executable calls is
> more resource-saving than for example saving forked parallel tasks and
> pipes between them.
>

IMO it would be great to have this before we fully switch to non-PPD
printing stack - this way we could test the filtering functions on more
places than just in printer applications, which still aren't widely used
for now.


>
>
> Forking and piping vs. one filter after the other
> -------------------------------------------------
>
> In general if forking and piping for a filter chain consumes much more
> than calling each filter function one after the other directly and let
> them write their output into temporary files for the next filter
> functions in the chain reading from the previous filter function's temp
> file I am also thinking about adding a second mode to filterChain() to
> let it operate this way. WDYT?
>

To be honest forking and piping sounds better for me - a file can stay on
system if something goes wrong, taking the resources, additionally
protective systems can complain about accessing/creating files in
unexpected location. AFAIK forking and piping sounds cleaner to me...


>
>
> Using filter functions directly in CUPS
> ---------------------------------------
>
> And, finally, should we make the filter functions be directly used by
> CUPS, either that in CUPS 2.5.x in scheduler/job.c we call filter
> functions instead of external filter executables (at least for standard,
> non-driver filters), or that for CUPS 3.x we do the needed file format
> conversions by filter function calls (there are no driver filters)?
> Backends could also be converted to filter functions and be directly
> called. WDYT?
>

I would prefer universal filter binary for the current CUPS 2.x, because,
as you wrote below, filter functions from libcupsfilters would cause
circular deps and the CUPS splitting is best done in CUPS 3.0.


>
> Also, do we need extra functionality in the filter function concept for
> using it directly in CUPS? For example add a field to the records of the
> filter functions called by filterChain() to tell as which user each
> individual filter function should get run?
>

I'm not sure if I am able to tell something relevant about this - how I
imagine the filter function is a 'in' pointer, 'out' pointer, ipp
attributes of the destination and array of CUPS options related to the job
(basically similar what current filter binaries take as parameters and
produce, with exception that instead of PPD we have IPP attributes). Maybe
to have some 'void' pointer for additional data, if some filter function
will need more info?


>
> Also, if we want CUPS to use filter functions, we need to do
> re-structuring to avoid circular dependencies, as libcupsfilters uses
> libcups and if a function in libcups would call a filter function of
> libcupsfilters, libcups is using libcupsfilters, ... The planned
> splitting of libcups, local CUPS daemon, sharing CUPS daemon of CUPS 3.x
> could help here as if the daemons call filter functions but not libcups,
> we will not get a circular dependency. WDYT?
>

As I wrote above, I would prefer an universal driver binary because of this
for now to prevent the circular dependency and pasting cups-filters code
into CUPS.



>
>
> It would be great if we could discuss these topics before finalizing
> cups-filters 2.x
>

Looking forward to cups-filters-2.0 :)

Zdenek


>
>     Till
> _______________________________________________
> Printing-architecture mailing list
> Printing-architecture@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/printing-architecture
>
>

-- 
Zdenek Dohnal
Software Engineer
Red Hat, BRQ-TPBC

[-- Attachment #2: Type: text/html, Size: 10125 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Printing-architecture] Use of filter functions in CUPS 2.x and 3.x
  2022-01-20 13:53 ` Zdenek Dohnal
@ 2022-01-20 16:23   ` Till Kamppeter
  0 siblings, 0 replies; 3+ messages in thread
From: Till Kamppeter @ 2022-01-20 16:23 UTC (permalink / raw)
  To: Zdenek Dohnal; +Cc: Open Printing, Pranshu Kharkwal



On 20/01/2022 10:53, Zdenek Dohnal wrote:
> Hi Till,
> 
> I'm sorry for answering this late - HDD got wasted, Christmas, all new 
> year responsibilities and I'm not particularly strong on my feet 
> regarding filters, so I'm not sure whether my feedback will relevant, 
> but so there it is:
> 
> On Mon, Dec 13, 2021 at 10:07 PM Till Kamppeter 
> <till.kamppeter@gmail.com <mailto:till.kamppeter@gmail.com>> wrote:
> 
>     Hi,
> 
>     with the background of CUPS 3.x, planned to get released 2 years from
>     now, not supporting PPD files any more and only considering driverless
>     IPP printers I have changed the architecture of cups-filters,
>     converting
>     filter executables (CUPS filters) into filter functions (library
>     functions doing a filter's task, with standardized call
>     scheme/interface) so that the code of the filters is preserved but they
>     get more universally usable.
> 
> 
> Kudos for doing that! I would propose to leave each filter binaries for 
> check/test target and use them in the test suite. IMO it would be great 
> to know that at least common use cases work the same way as with the 
> previous filter binaries.
> 

There are still filter binaries for calling the filters the classic way. 
To not duplicate code they are stubs which do not more than calling the 
corresponding filter function. The binaries are in filter/ (as the 
executables before) and the filter functions in libcupsfilter/. So 
filters can be called in 3 ways:

1. As individual executables
2. Filter function chains called by the "universal" filter
3. Filter functions directly

>     So before I complete this (if not, the universal filter will at
>     least be
>     used to make cups-browsed's "implicitclass" backend use filter
>     functions
>     instead of external filters) I want to hear some opinions about this,
>     especially also whether actually saving external executable calls is
>     more resource-saving than for example saving forked parallel tasks and
>     pipes between them.
> 
> 
> IMO it would be great to have this before we fully switch to non-PPD 
> printing stack - this way we could test the filtering functions on more 
> places than just in printer applications, which still aren't widely used 
> for now.
> 

The simple switch-over to cups-filters 2.x already makes the filter 
functions being used, called through the individual wrappers (see (1) 
above). By simply replacing a config file one can switch the universal 
wrapper calling filter function chains. So a quick switch-over to 
cups-filters 2.x will give us already a lot of testing before we get 
CUPS 3.x.

Also more use of the Printer Applications (for example in distros with 
snapped/sandboxed CUPS) will provide more testing.

> 
> 
>     Forking and piping vs. one filter after the other
>     -------------------------------------------------
> 
>     In general if forking and piping for a filter chain consumes much more
>     than calling each filter function one after the other directly and let
>     them write their output into temporary files for the next filter
>     functions in the chain reading from the previous filter function's temp
>     file I am also thinking about adding a second mode to filterChain() to
>     let it operate this way. WDYT?
> 
> 
> To be honest forking and piping sounds better for me - a file can stay 
> on system if something goes wrong, taking the resources, additionally 
> protective systems can complain about accessing/creating files in 
> unexpected location. AFAIK forking and piping sounds cleaner to me...
> 

OK.

> 
> 
>     Using filter functions directly in CUPS
>     ---------------------------------------
> 
>     And, finally, should we make the filter functions be directly used by
>     CUPS, either that in CUPS 2.5.x in scheduler/job.c we call filter
>     functions instead of external filter executables (at least for
>     standard,
>     non-driver filters), or that for CUPS 3.x we do the needed file format
>     conversions by filter function calls (there are no driver filters)?
>     Backends could also be converted to filter functions and be directly
>     called. WDYT?
> 
> 
> I would prefer universal filter binary for the current CUPS 2.x, 
> because, as you wrote below, filter functions from libcupsfilters would 
> cause circular deps and the CUPS splitting is best done in CUPS 3.0.
> 

OK.

> 
>     Also, do we need extra functionality in the filter function concept for
>     using it directly in CUPS? For example add a field to the records of
>     the
>     filter functions called by filterChain() to tell as which user each
>     individual filter function should get run?
> 
> 
> I'm not sure if I am able to tell something relevant about this - how I 
> imagine the filter function is a 'in' pointer, 'out' pointer, ipp 
> attributes of the destination and array of CUPS options related to the 
> job (basically similar what current filter binaries take as parameters 
> and produce, with exception that instead of PPD we have IPP attributes). 
> Maybe to have some 'void' pointer for additional data, if some filter 
> function will need more info?
> 

The call scheme of filter functions already has this void pointer, the 
"parameters" pointer. See use of filter functions in the source code of 
the universal() filter function and also in libpappl-retrofit, the 
job-processing part especially.

> 
>     Also, if we want CUPS to use filter functions, we need to do
>     re-structuring to avoid circular dependencies, as libcupsfilters uses
>     libcups and if a function in libcups would call a filter function of
>     libcupsfilters, libcups is using libcupsfilters, ... The planned
>     splitting of libcups, local CUPS daemon, sharing CUPS daemon of CUPS
>     3.x
>     could help here as if the daemons call filter functions but not
>     libcups,
>     we will not get a circular dependency. WDYT?
> 
> 
> As I wrote above, I would prefer an universal driver binary because of 
> this for now to prevent the circular dependency and pasting cups-filters 
> code into CUPS.
> 

OK.

    Till

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-01-20 16:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-13 21:06 [Printing-architecture] Use of filter functions in CUPS 2.x and 3.x Till Kamppeter
2022-01-20 13:53 ` Zdenek Dohnal
2022-01-20 16:23   ` Till Kamppeter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.