Printing Stack with Mobile in Mind

Registered by Till Kamppeter on 2013-03-04

Printing should not only work on desktop machines but also on mobile devices. We must especially have in mind that with mobile devices getting more popular for many people the mobile device is their only computing device and also that under iOS you can print from practically any application.

Mobile devices have significantly reduced resources. They do not have the space to hold a large printing stack, especially not for hundreds of megabytes of printer-model-specific drivers and PPD files. So we need to concentrate on the most important bits, ideally wit a stack not using model-specific drivers nor a printer setup tool, like AirPrint on iOS. It simply auto-discovers compatible network printers via Bonjour and users can print on them. Inspired by this I am working on splitting the printing stack to allow installation of three different levels: Level 1: Only CUPS daemon and cups-browsed, no filters, no web interface, no printer setup tool, prints only on remote CUPS queues (1MB); Level 2: Level 1 plus filters to print on IPP Everywhere (CUPS Raster), PDF, PostScript, and PCL printers, discover supported network printers automatically and just print on them (some two-digit amount of MB); Level 3: The full printing stack which we always shipped for the desktop (200-300 MB). Done in cups-1.7.1-4 and in cups-filters 1.0.44-1.

In addition, we will add functionality to cups-browsed to auto-discover IPP network printers with known page description languages (IPP Everywhere/CUPS Raster, PDF, PostScript, PCL) via Bonjour, request the printer´s capabilities from the printer via IPP, generate an appropriate PPD file and create a local CUPS queue, fully automatically, without the user needing to do anything with interactive software like a printer setup tool. This all looks like AirPrint on iOS but does not use the proprietary URF data format of AirPrint. The concept is similar: Printers get auto-discovered on the fly and appear in the print dialog and users can just print on them. Done in cups-filters 1.0.44.

Printing-related daemons (cupsd, cups-browsed, avahi-daemon) should be started on-demand instead of keeping them permanently running. cupsd is only communicated with via a socket (port 631 or /var/run/cups/cups.sock) so it could be started socket-triggered by upstart and one could easily patch it to automatically shut down when it runs out of jobs. avahi-daemon and cups-browsed should be started by the print dialog when it is opened (cupsd could be started this way, too).

When a user opens the print dialog, avavhi-daemon and cups-browsed should be started (can get called explicitly, cups should be started socket-triggered by Upstart), as cups-browsed will get D-Bus signals from avahi-daemon when printers appear or disappear and it will send requests to cupsd (gets started via Upstart socket bridge) to create or remove print queues pointing to these printers. The dialog is now supposed to watch the print queues appearing and to update the user-visible list appropriately, until the user clicks a printer. Then printer capabilities should be polled via IPP (using libcups) and if the user clicks "Print", the job is sent to CUPS (also using libcups).

When the dialog is closed, we check whether other instances of the dialog (or other avahi-daemon-using apps, how do we identify them without having an explicit list?) are still running and if not, we kill avahi-daemon. cups-browsed and cupsd keep running, we modify cups-browsed that it keeps running when avahi-daemon appears and disappears and let it remove the job-less (empty) Avahi-discovered queues if avahi-daemon disappears. cupsd closes by itself 30 sec after there are no jobs any more and cups-browsed closes by itself if it runs 30 sec without having any cups-browsed-generated print queues, meaning that all but the queue which is printing the user's job get removed when avahi-daemon is killed by the dialog closing and the remaining queue gets removed when the job finishes, if within 30 seconds no new print dialog gets opened (which starts avahi-daemon) cups-browsed closes. These non-permanent (auto-closing) modes of cups-browsed and cupsd we trigger by a special command line option or by a signal which we will introduce to the daemons and use it when calling from the print dialog (or when calling cupsd socket-triggered by Upstart).

We will also keep cups-browsed running when there are no cups-browsed-generated queues as long as avahi-daemon is running (= dialog open), so that if we open the dialog and no printers get detected we have can turn on a printer or move into a network with printer without cups-browsed terminating in the meantime.

So we will modify cups-browsed (done in cups-filters 1.0.45):

- Keep running independent of avahi-daemon running, simply remove the empty avahi-detected queues if avahi-daemon disappears and recover to avahi use if avahi-deamon reappears.
- Command line option/config file option/SIGUSR1/2 to stop if 30 sec without cups-browsed-created queues and without running avahi-daemon.

and cupsd (done in cups 1.7.1-4ubuntu1):

- Support for Upstart-induced startup:
- Command line option/env variable/config file option for stopping when 30 sec without jobs and without shared printers (default when Upstart-socket-induced).

Related Blueprints:

Wiki page about PDF renderers:

Blueprint information

Sebastien Bacher
Till Kamppeter
Till Kamppeter
Series goal:
Accepted for saucy
Good progress
Milestone target:
milestone icon ubuntu-13.07
Started by
Till Kamppeter on 2013-03-04


tkamppeter, 2014-03-06:

Packaged cups-1.7.1-5ubuntu7 with the fix to make socket activation via Upstart working (not perfectly but probably sufficiently for a phone, thanks, xnox). cupsd also supports on-demand use of avahi-daemon now. It simply starts broadcasting as soon as avahi-daemon appears and after stopping and restarting avahi-daemon it recovers.

tkamppeter, 2014-02-14:

Packaged cups-1.7.1-4ubuntu1 with patches to run cupsd on-demand, first to support starting by the Upstart Socket Bridge and second to let cups terminate after a given time being idle (no jobs, no shared printers).

tkamppeter, 2014-02-13:

Released cups-filters 1.0.45 upstream with cups-browsed prepared for on-demand use. The new cups-browsed starts keeps running with avahi-daemon being stopped and started (avahi-daemon on-demand) and has an auto-shutdown feature now, letting cups-browsed terminate when all its queues have emptied out and disappeared.

Added concept for on-demand use of the printing-related daemons (avahi-daemon, cups-browsed, cupsd) to this Blueprint.

tkamppeter, 2014-02-03:

(After discussion with xnox on Desktop Sprint) For on-demand starting of daemons (avahi-daemon, cups, cups-browsed) instead of using Upstart bridges (which can get rather complex and is still buggy in Upstart) let them get started when the user opens the print dialog. Queues in the network get all visible within around 5 seconds. Stop daemons when dialog is closed, but let CUPS keep running for printing the job(s). CUPS has then to remove temporary queues and close by itself when queues empty out.

tkamppeter, 2014-01-17:

Done the binary package splitting for the level 2 printing stack in cups and cups-filters.

For a level 1 setup (only use of remote non-raw CUPS queues) install avahi-daemon, cups-daemon, cups-browsed, and the libraries pulled in by these.

For a level 2 setup (level 1 plus automatic setup of IPP printers which understand PDF, PostScript, PWG-Raster, or PCL) install avahi-daemon, cups-daemon, cups-core-drivers, cups-browsed, cups-filters-core-drivers, poppler-utils, and the libraries pulled in by these.

For a level 3 setup (everything) proceed as before. The new split-out binary packages will be pulled in by dependencies.

tkamppeter, 2013-10-31:

Released cups-filters 1.0.41 upstream with cups-browsed auto-creating PPD-less print queues for IPP network printers which advertise themselves via Bonjour. Supported printer languages are PWG Raster (in IPP Everywhere printers), PDF, PostScript, PCL-XL, and PCL 5c/e. Still needs polishing but principally works.

seb128, 2013-05-29: changing the milestone to 13.06, there are open items that will not get done by end of this month so moving them to the next one

tkamppeter, 2013-05-17:

Photo display/management/manipulation apps should send PDF with embedded JPG when printing, to keep the size of photo print jobs small. Find existing code in desktop photo apps and perhaps also in the imagetopdf filter of the cups-filters package.

tkamppeter, 2013-05-15:

Fedora patch for on-demand triggering cupsd via domain socket:

Upstart can also trigger daemons on-demand via domain socket. See "man socket-event". This also needs modifications on the daemon.

James Hunt (jodh) on #ubuntu-devel IRC: cupsd would need to be modified such that it does not call socket() et al itself - it would simply need to call accept(2) on the socket fd passed to it via the UPSTART_FDS env var. I believe systemd requires something similar.

Robie Basak (rbasak): Looks like the patch is very systemd specific, but the general mechanism is the same.

Martin Pitt (pitti): you usually don't want cups to stop and you usually don't want to start cups at the time when you need it first, but much earlier as remote printer detection will just take a while (DNS-SD announcements are only sent every 30 seconds or so)

Robie Basak (rbasak): Although from that patch it looks like systemd provides a library as a general mechanism. It might be worth considering if it's worth implementing an equivalent compatibility library that supports upstart's socket bridge that could be used in place of it and support the same API. I'm not sure how likely systemd upstream are to change the API though. But it would be nice to easily support anything that supports systemd socket activation in this way.

Martin Pitt (pitti): yes, I think starting on demand on a mobile device is an acceptable compromise (the first time you want to print you just have to wait a bit) I just wouldn't do it on a desktop; I think "start cups after one minute or when requested" keeps it out of the boot path, and yet has it ready when you realistically need it. I guess on a mobile phone we actually do want to shut it down after some time, too. On a desktop one usually has swap, so if it's not being used, it just gets swapped out.

tkamppeter, 2013-05-14:

OpenPrinting Summit: On-demand CUPS daemon start possible with simple program triggered by CUPS domain socket (/var/run/cups/cups.sock) access, starting cupsd.

Mike Sweet got CUPS patches to make CUIPS stopping when idle.

Fedora triggers CUPS on-demand with systemd.

cups-browsed can perhaps be replaced by DNS-SD browsing in the mobile print dialog (like the GTK+ 3.8.x print dialog does).

tkamppeter, 2013-05-14:

UDS session moved to May 16 (Thursday) 6pm UTC as at the original schedule no one joined.

tkamppeter, 2013-04-18:

Added Blueprint:

tkamppeter, 2013-03-20:

Discussion with Robin Watts and Henry Styles from Ghostscript on #ghostscript on Freenode and after that with Robin Watts and Michael Hall (mhall119) and Gerry Boland (greyback). Ubuntu Touch did not decide yet on a PDF renderer and we suggested MuPDF which is fast and lightweight and has good form filling and reflow functionality (try Android version). It should also get the print renderer and Ghostscript developers are willing to write the print output backends. I am also planning to open GSoC student projects for CUPS wrapper filters and printer output devices.


* printing stack uses too many resources for mobile devices (storage for PPD files and printer drivers)

* first (minimum) approach: only print on remote CUPS servers (a cups-daemon of one MB)
  * requires a linux or mac os machine with shared printers, i. e. a server which has the drivers for the actual printer
  * probably not enough according to Till

* second (intermediate) approach: detect IPP printers in cupsbrowsed
  * no need for a printer setup tool anymore (printing just works)
  * only printers set up by cupsbrowsed
  * cups-browsed will discover IPP network printers with known languages (PWG Raster/IPP Everywhere, PDF, PostScript, PCL) and printers shared from CUPS machines
  * Apple's AirPrint cannot be emulated fully (defines a proprietary raster format, the URF raster format, in contrary to IPP Everywhere which uses only open formats)
  * formats supported by IPP Everywhere: PWG-(CUPS)-Raster, PostScript, PDF, JPEG
  * keep filters (pdftopdf, pdftops, pdftoraster, rasterto*) for the most common printer languages, no need for PPD database (PPDs generated by cups-browsed)

* Apps should not use PostScript anymore (so that we don't need Ghostscript)
* use poppler for pdf rendering
  * doesn't have color management (yet)
    * that's okay, we don't have color management in MIR yet
   * We [poppler] have patches waiting for [knowledgeable] people to review them :-)

* Can we start CUPS on demand?
  * cups-browsed has to run all the time for discovery, listening to avahi events
  * but cupsd itself?
  * we could listen for Avahi/bonjour printer events from some desktop  (gnome-settings-daemon or its future equivalent), and once it discoveres one, start cups and cupsd ?

* SDK should ship a printing dialog  -> for sure Qt has one? or is that KDE only? -> Qt does, but is it optimized for mobile?


Work Items

Work items:
[tkamppeter] find out whether we can start cups-browsed on demand: DONE
[tkamppeter] find out whether/how cupsd can be started on demand: DONE
[tkamppeter] find knowledgable people to review poppler's color management (Mailed to Richard Hughes and to OpenICC mailing list): INPROGRESS
[tkamppeter] work with SDK people to get a nice printing dialog: TODO
[jnick-tait] help design a print dialog (some work for the desktop was already started by mpt): TODO
[tkamppeter] Document tradeoffs between our PDF renderering options on wiki page: INPROGRESS
[tkamppeter] Send QML mockup of printing app with Touch and Convergence in mind to design team: TODO
[tkamppeter] Measure storage and memory budgets for a trimmed down CUPS for mobile: TODO
[tkamppeter] Patches to start CUPS and with upstart from printing app and stop it when all print jobs are done: DONE
[xnox] Fix cups to properly inherit socket-activation: DONE