Graphics and Imaging • 1:02:49
The Common Unix Printing System (CUPS) forms the basis of the Mac OS X printing architecture. See how Mac OS X Leopard integrates CUPS to extend the capabilities and performance of the printing system. Learn ways for your application to interact directly with CUPS. Discover how PDEs, printer utilities, ICA modules, ICC profiles, and other modules and plug-ins fit together to support single and multi-function printers. Developers of advanced printing applications, printer drivers, and printer management software will not want to miss this session.
Speakers: Paul Danbold, Mike Sweet
Unlisted on Apple Developer site
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Good to see you. Yesterday we did a printing session covering the application side of printing. And this morning we're going to turn our attention to the world of printer drivers. Pretty much anything that happens between the Print Dialogue and paper coming out of the printer -- or not coming out of the printer, which sometimes happens.
And before Mike gets up on stage to tell you all about CUPS, all I want to do is take a minute to say thank you. Pretty much thank you to everybody in this room. Because these days you can hook up pretty much any Mac -- any printer on the planet to a Macintosh.
And it's through all your hard work that that's possible. And I want to say a special thank you to the folks in this room who have been working with us since the advent of Mac OS X, through the evolution of the printing system, to deliver a huge number of printer drivers.
And when I say huge, huge is the operative word. If you check out the Leopard build that you have, that you picked up on Monday, you'll find that you have three-and-a-half gigabytes of printer drivers. And that's -- that's a lot of code. A lot of resources. But it's all testament to the amount of work that's gone into supporting all the printers that you've done over the last few years.
The upside of those three-and-a-half gigabytes on everybody's hard disc is support for about 2500 printer models, and the number may even grow before we even ship Leopard. So again, thank you very much for all the hard work. Please keep up the work because we're not done yet with Leopard. But I know you've been working hard to make that happen. So, without any further ado, I am going to bring Mike up on stage, tell you all about CUPS in Leopard. So thanks very much.
( Applause )
- Thank you, Paul. Welcome, everybody. Congratulations on making it to Friday. My name is Mike Sweet, and I'm the creator of CUPS. And so -
- we're going to talk about CUPS today Now I'll mirror Paul's thank you. I've worked with some of you, I'm probably going be working with a lot more of you as time goes on.
CUPS is a really complicated thing in many ways, and printing, yeah, everybody says printing has to be simple. And it's nothing further from simple when it comes to actually developing a driver. So thank you for doing all the hard work. Thank you for reporting bugs if you have been reporting bugs. It has really helped to make CUPS the product that it is. And to start today with an overview of CUPS. And just give you an idea of what CUPS is, if you're not familiar with it.
Common UNIX Printing System. The acronym comes from CUPS. Provides printing services for most operating systems that you have out there. The major exception, of course, being Windows. And created it in 1997 while I was work for D C Software Products (assumed spelling), and the idea was wanted to come up with something to replace LPR. Because LPR, quite frankly, sucks.
So at the time we were able to develop something using a new Internet printing protocol. And that eventually got adopted by all the LINUX, it's available on all the commercial and BSD UNIXes, and obviously it's available on Mac OS X. If you go on CUPS dot org, you will find a lot of components you can use with Mac OS X. And also the developer forms. You go on there, ask questions. You generally get an answer pretty quickly.
Now CUPS got introduced into Mac OS X in 10.2. And as we've gone along, we've included newer and newer versions of CUPS. The Leopard beta that you have has a 1.3 snap shot from a view weeks ago. And you know, basically whatever you see going into 1.3 on the CUPS Web site is also going into Leopard. CUPS has been purchased by Apple. So I am now working for Apple. Woo whoo.
( Applause )
- But to -
- to allay any fears, nothing's going to change as far as CUPS is concerned with the license.
It's still going to be the new G P L and L G P L. We're still going to have to the site hosted at CUPS dot org. And it's still going to be developed. We're just doing it from Apple instead of from D C Software Products. So from your standpoint, nothing's really going to change except for the copyright notices that you'll see on the pages.
Now CUPS itself is based around a single program called the scheduler. If you look in the process list you'll see a program called CUPS D running. On Mac OS X, it started on demand by the Launchd service. If you have shared printers, it's running all the time. If you don't, it just gets run when you go to print something. It's a very light weight program. All it does is collect jobs and then run other programs to print them. So for the most part you won't see any massive memory use or C P use from the scheduler, just because it doesn't have to do much of anything.
Scheduler runs it's route. But most everything it runs to actually print stuff runs as an unprivileged user called L P. Now when you actually go to print from an application, that application goes through all the layers and it's talking to the scheduler via the IPP protocol. That also happens to run over HTPP, so you get a Web interface to go along with it.
Now if you show it graphically, you see the application -- in this case it would be a Cocoa application. Which sits on top of Cocoa, which sits on top of Core Printing, which sits on top of the CUPS API, which is the lowest level API to talk to CUPS.
The CUPS API sends the request over to the scheduler, via the HTTP and IPP protocols. And the scheduler uses that same API to read the request, do whatever processing is needed, and then send a response back to the application to say, hey, I printed your file. Or here's the list of printers you asked for. Or here's the printer description file.
Now once you actually submit a job for printing, the job gets filtered by one or more programs to actually get sent to the printer. So here we have a PDF document sent from a Cocoa application. And it's going to be run through one or more filters to actually get that converted into a form that can be used by the printer driver. So in this case we're going have a Raster printer driver.
So we're going to have a few filters in there to convert it to a CUPS Raster format. And along the way we're going to have any log or user messages that would get relayed to the user on the desktop sent to the standard error. The output from those filters gets piped into your filter driver, which again could send messages to the user.
That, in turn, sent into an optional port monitor program which handles any kind of encoding or protocol requirement that's your driver has. Typically, it using for things like USB, framing, and other sorts of things that are interface-specific. But you don't want to have to write a custom back in for. And then the output from that program gets sent into the back ends.
Now the back end is the actual program that talks to your printer. CUPS comes with USB, serial, parallel, network, and various protocols back ends. There's Apple Talk, there's Bonjour Back End. Basically, any kind of protocol you're generally going to use, we already have something for. Nice general purpose back ends that you can then interface with to do specialized stuff for your device.
Now of course sometimes these printers talk back. And something that's new in Leopard is support for back channel data. So that back end, whatever it gets from the printer, relays it back to the port monitor and the driver so they can do something with it. See what the tonner levels are, see if it's printed to page; that sort of thing.
Now also new in Leopard is the ability to actually talk to the back end and do some control commands and query commands on the interface itself. So there's a side channel API that allows you to communicate between the driver and the back end to do things like soft reset and, you know, what's the status of the device.
Now, once all this goes through, you actually get something out in the printer. And if you don't, it's a driver bug. And when that happens, you're going see messages in the log files of the now these messages -- and you saw those little arrows going up there -- are just messages you sent with F Print F or NS log, or whatever you happen to use, to the standard error file.
And those messages generally get relied to the user with a few exception, and we'll cover those in a little bit. All of the filters, drivers, and port monitors are running as the L P user. The back ends may run as L P or route. And we'll talk about how you can control that at runtime. And this is also different from previous releases.
Now when you put that message out to standard error, it's going get logged somewhere. Typically, anything you're putting out for user messages, like, I'm printing page one, I'm printing page two; those just go straight to the user on the console. Various other errors and so forth will end up in that error log file. Any page accounting information is going into the page log file. And finally, any access information for applications, printing jobs, checking the status of printers and so forth gets logged in the access log file. These are all available from the console application.
You can also see via the CUPS Web interface, access log file in particular is standard Apache format so you can use Webalizer (Phonetic) and other tools to analyze that information. And then page log, there's several utilities for processing that data as well so you will Address Book able to see John printed 50 pages to our existing color printer, and now we have to go track him down.
So that's a little bit about CUPS in general. I am going talk a little bit now about what's new in Leopard compared to what you had in Tiger. Now CUPS itself, we've kind of skipped the release. So we've actually accumulated over 100 new features since Tiger. And along with that we've also gained a lot of performance improvements. Previously, there were a lot of things with job history and printer attributes that would use up a lot of memory and use up a lot of CPU when you first start up the system.
We've really leaned things down so the scheduler doesn't keep all that in memory all the time, and also cache the information so we don't have to reprocess it all the time. So you see a lot better performance from the scheduler itself. But while we've done all this stuff, we've kept it 100 percent binary compatible. So many of your drivers or applications aren't going to notice any difference.
Now one of the major new category of features we have in CUPS is the networking support. And we've added quite a few new features to that. And this is a highlight of a few of them. I know a lot of you asked for this before. We have I P version six support throughout.
There are two limitations with that. One is that CUPS browsing protocol doesn't work with I P Version Six. And the other is we don't currently use I P Version Six for S M N P browsing. So that's basically the extent of the limitations. Everything else, shared printing, printing to network printers all work over I P Version Six. We've added support for curb rows. So now if you have a curb rows environment, you can use that for authentication and single sign on and all that goes with that. I'll talk about that in a sec.
You can now have shared printers that have user name and pass word requirements. So you don't want somebody printing to it, some expensive printer, you can actually require a user name and pass word, and then only authorized users can print to that. And then finally, in Tiger we added the ability to do printer discovery via Bonjour. That's great for newer printers. But the older printers that a lot of you have don't support that. But they do support the older S N M P protocol. And we've added support for our printer discovery via that protocol.
Now curb rows authentication isn't enabled by default. Basically, because not everybody uses curb rows. The way we've implemented is we're taking the credentials that are cached by curb rows when you sign on and sending them on to wherever you're doing a print job. So it can then authenticate against your key distribution center.
So basically one sign on, one -- one set of credentials can be used all across the network. The limitation with this is that we only support single domain. If you have a multi domain environment, please see me and we'll talk about what things we can do to support that in the future. So it's not enabled by default There's a one-line change that you can make to the scheduler configuration file, which you can also do via the Web interface.
And that -- you go on to HTTP colon, slash, slash, local host, colon, 631. Click on the administration tab. And you'll see under the server column there, there's a setting, a little check box that says use curb rows authentication. So just check that. And click change settings. And all of a sudden your system is set up for curb rows. So -- about as easy as we can make it, I guess.
Now on the administration front, we've added some things, a lot of people have been asking for over the years and have finally worked their way in. We have support for the IPP notification spec. Basically allows asynchronous notifications of any event that happens on the scheduler. And you'll see that in a sec.
The Web interface compared to what was in Tiger is vastly improved. There's searchable help, there's paging of the individual printer and job pages. If you use that Web interface at any -- any time -- you'll find it's a lot easier to use now. Similarly, the logging -- we've standardized a lot of the messages.
The access log actually shows you for IPP requests what the IPP request was rather than just seeing a post and not knowing what the application was doing And in page logging you can actually see some of the attributes that are coming through for the jobs. And finally, previously, all you could do is have the standard CUPS policies for what users can do and what users can't do. You can now customize them at the individual IPP operation level. Also for printers. When there's an error that occurs you can tell CUPS what to do. If you want to retry, or if you want to just abort or -- or whatever.
Now for the event notifications you basically can find out anything about a job, printer, or server that happens. So if a printer gets stopped, you can get an event. If a job is completed, you can get an event. Service restarted or somebody does something that triggers the security alarm, you can actually get notified that something happened and here's who did it, and when it happened. There's two main notifiers that come with CUPS. There's mail 2 for e-mail notifications that requires a mail server in order to function. You can't just have it attach to your pop account.
And an RSS notifier for RSS feeds. So you can actually create an RSS feed and subscribe to it and do all that fun stuff. You can add your own notifiers very easily. Like any other program in CUPS, you just have a simple command line program and it reads all the information it needs on the command line. And that's standard input. And then you just process things.
Notifiers are run on demand so they don't use up system resources when there's no events. And basically can do anything you want with it. If you have a driver, you can actually trigger events for printers through a state message. And you'll see that in a little bit. And you know, basically get something to happen on the UI.
So again, if you go on the CUPS Web interface you'll see that you can actually click on a button that says add RSS subscription. You get this form and this allows you to set up an RSS feed right on your print server that you can then subscribe to from any other system. And you know, for example at my office I have all my printers set up in this.
And then I have the screen saver pointed at the feed so I can know what's happening with the printers. You can control how many events are showing up in the list, and all the -- the news items in the feed actually take you to the corresponding page on the CUPS Web interface.
Now if you're a developer, and particularly a driver developer, we've added a lot of new stuff in Leopard. Biggest one I think you're going to see is the support for multi language PPDs. Previously, if you supported ten languages for a particular printer, you needed to have 10 PPDs with the corresponding sides increase. We now have all encoded into one PPD if you want, and then you can just have one PPD file instead of 10.
If you have constraints in your drivers where you can not print, say, duplex on transparency media, those are actually supported by the Print Dialogue, and you can use them in PPD files, and we'll show that in a sec. And you know, basically it eliminates the need for a PPD in a lot of circumstances.
The back channel, side channel interfaces we showed on the slide before that will allow you to actually communicate with a printer more effectively -- there's a new CUPS driver interface that you can use , instead of PPD files. And we'll show that in a sec. If you have a printer that has a lot of different options and you can't configure via postscript theory or S N M P look ups, you can actually provide a program that goes out and automatically configures the printer once it's been detected. And finally, if you're doing a photographic quality printer, the print path is now fully 16-bit all the way through. So you wouldn't any artifacts depending on the type of quality printing.
Now those constraints I was talking about before -- input script -- printer description files, you can basically say this option conflicts with this option. So the duplex option for two-sided printing is incompatible with transparency media. Or letter sized pages can't be printed on an envelope feeder. The very simple constraints, a lot of printers can make use of these and have sufficient safeguards in there. If you have multiway constraints, though, you're going to need a custom Print Dialogue pane, or PD P, with your printer driver to implement those.
And how it shows up in the Print Dialogue is pretty straight and simple. Here I am -- got my document. I go to print. And I bring up the -- the paper feed section -- and I select envelope feed. But if you look there, you also see I had of the paper size set to U.S. letter. And you can't print U.S. letter on the envelope feeder.
So when I do that, I'll get a dialogue that pops up and says media source option envelope feed is not available with the destination paper size. So you have the option either of continuing and using that setting and having it resized down to it will fit on to an envelope, or you can cancel and revert back to the previous paper source.
Now for the back channel and side channel interfaces, the back channel APIs is simple. It's two functions. One to read and one to write. If you're writing a back end you use CUPS back channel right to write the data back to the -- to the driver. And if you're writing a driver, you use CUPS back channel read to read the data from the back end.
Side channel API is a little more complicated. There's three functions. The one that you use in the printer driver is a CUPS side channel do request. And that will allow you to do five different things. Reset during the out put or get the very status information that you can get from the back end. And uses in conjunction with the back channel to do synchronization and configuration of your driver when you actually print the job.
So now I'm going to kind of go over how you would actually develop the printer driver for CUPS and Mac OS X in particular. It's fairly simple. But coming from a Tiger era, you may not be familiar with some of the terminology. Basically, there's three different kinds of drivers. And this is kind of a broad class. But three different kinds of drivers for CUPS.
There's a post-script driver, which is a -- a driver that doesn't have any extra filters. And you just provide the PPD file for the printer and everything just works. There's a CUPS Raster driver which is for Raster printers, and it's the easiest way to support a non post script printer, just because it's the simplest interface. And you just need to provide one filter to actually convert the Raster data to something that your printer can take.
Last but not least, there's the custom driver. Custom drivers will typically have two or more filters, and they -- if they do vector processing and all sorts of fancy stuff that will get the data into an optimal format for the printer. But to caution you, a lot of times you'll implement these things only to realize a 5 percent improvement in speed or even a loss in speed. Because you're spending so much time on the computer, the printer's just sitting there waiting for data, whereas the Raster driver might just go straight through and print just as fast.
Now every printer driver has some common components. Number one component is the postscript printer description file. Which despite the name, PPD files are used for post postscript and non postscript printers. And in Leopard, you also have the option of using a CUPS driver interface instead of the PPD files. But ultimately, that driver interface is going to create a PPD file for your print queue.
Along with PPD time you'll have any driver files. This is the filters, prefilters, port monitors and back ends that you have with the -- with the driver. There's plug-ins that you use, auto set up tool, which is something new in Leopard. Any custom Print Dialogue panes or PD Es that you use in your -- in your driver to provide driver-specific options. A monitoring tool which is -- needs to be called (Inaudible) tool, allows you to monitor the printer while jobs are printing so that you know, hey, I'm low on ink or Paper Tray 2 is empty.
And finally, the printer utility for doing things like head alignment and cleaning and so forth. Last but not least, there's support files. These are things that a lot of users don't even know are there. But there's online help, there's color profiles, mime files, if you have custom file types that you're using. And the printer icon, which shows up on the desktop.
Now these all go in specific locations. If you're doing PPD files they go under library printer. PPDs contents, and so forth. Any of the driver interfaces, back ends notifiers, or port monitors need to go under the corresponding CUPS directory. And you'll see there user, lib exec CUPS (assumed spelling) something. If you're doing any custom file formats, they need to be defined in the private et cetera CUPS directory. That's where CUPS looks for those -- that information. And finally, anything else you threw into your own directory under library printers and your vendor name.
Now of all those components, the PPD file is basically the most important. And that's the file that actually defines what your printer can do. What options are available. You know, what paper sizes and what the margins are. How to identify it as that particular printer. All that information comes from that file.
Now all the features that you have in that file, like double-sided printing and media type and so forth, are organized into groups and options in the PPD file. A group would be finishing features, and then the options themselves would be, you know, staple and punch and so forth.
All of those choices that you make map to actual postscript code. And if you're doing a CUPS Raster driver, that postscript code is actually the sub postscript that we support for CUPS Raster drivers. And if any of you have been involved with the Leopard testing, you may have noticed since we introduced CUPS 1.2 that the allowed postscript code has changed very slightly because we're actually interpreting the post script code rather than just looking for keys and values.
So if you're having problems like that please see me and I can direct you to the right documentation. The PPD files in Leopard can actually contain multiple languages. If you're using and shipping a driver for previous releases you'll still want to be able to deliver PPD files with one PPD for each language.
And then finally, if you're developing and distributing drivers use the CUPS test PPD utility that comes with CUPS to test your PPD files. It's very important that you at least pass those basic tests. Ensures that the format's right and that you don't have any obvious conflicts in the file.
Now the alternative to developing PPD files is to do a CUPS driver interface. And the advantage here is that you can actually programatically generate your PPD files depending on the printer that's attached or the type of system that you're using. So it's optimized for the user. And there's other advantages I'll talk about in a sec. Now basically you have this program that you install in -- in -- in the user lib exec CUPS driver directory.
And it either takes a list command or a cat command (assumed spelling). List lists all the drivers that you can generate PPD files for, and cat actually tells you to generate the PPD file for that particular driver. If you look in the CUPS source code you'll see a test driver dot C file in the driver sub directory that will give you an example of how to implement one of these things. It's super-simple. So it's not necessarily the best thing to base an entire driver interface on. But it will show you the basics.
Now when deciding whether to ship PPD files or driver interfaces, there's a couple of simple questions. Number one, how many drivers are you shipping? If you're shipping one driver there's no sense using a driver interface, because you're not going to notice any savings. And also if you're only providing drivers that will work on older releases of OS X all the way through the current release then you probably don't want to use the driver interface there either because you're not going to be able to access the drivers in older releases. But if you are developing something where you're going to be distributing on Leopard and you can provide some back compatibility thing in your post install to generate the PPDs if you're on older releases, you may find some significant improvements.
And I'll use Good Print here as an example, which has, as of a few weeks ago, 17 languages and 819 printer models defined in it. If you generate all the PPDs with all the languages, it's 212 megabytes compressed. If you use the driver interface, it's 1.1 Megs. So significant savings in certain circumstances.
It's entirely up to you to decide which way to go. But, you know, if you see that you're in the same boat as, say, the Good Print folks, you probably see a significant savings. And that will help you, you know, for downloading files and it will help us for distributing the files on their install DVD.
Now once you've got the PPD file you're going to identify certain filters and programs that are going to be used with that PPD to support your printer. The first one that you're going to do is the printer driver filter, which is defined in the PPD file using the CUPS filter attribute.
And basically the CUPS filter attributes defines a file format this filter accepts, a cost associated with running the filter, and then the full path to the filter that you want to run. So, in this case, as an example we're going to run a filter from library printer's vendor name Raster to Foo (assumed spelling), and we're giving the cost of 100 because it's a Raster filter. It's doing dither (assumed spelling) and color management, and all that stuff in it. And it's going to use a lot of CPU and a lot of memory, and we just want to let CUPS know that it's going to be an expensive operation.
When you actually go to print something, the default on OS X is not to limit the number of simultaneous jobs that are printing, but if you have somebody with one hundred printers in a lab, they may have configured the system to only print up to, say, ten jobs simultaneously.
So the limit that you put in there, the cost that you put in there, is going to be used to limit the number of jobs that are printed simultaneously in certain circumstances. So it's important. Put a reasonable value in there. If you know your driver is heavy duty, put in 100. If it's just a pass through, you can put a zero. But just put in something that matches the kind of work its doing.
Now in some cases you want to know what's in the original spool file before you actually run your driver. And so in Leopard we have added support for prefilters. And what this basically allows you to do is when somebody prints a PDF file I want to have first look at it so I can know what's in the PDF file. Or somebody prints a postscript file, you know, I want to look at that first before you do anything with it.
So you can specify that with a CUPS prefilter attribute in the PPD file. It's the same format as the CUPS filter. But in this case it's put in front of rather than after the corresponding type. Again, that cost there is used to limit the number of jobs that are printed at any given time. And you know, if you're just a pass through, you can put zero. But in most cases I would put something at least like 50. Because you're going to be doing something with the data that's going through.
Now after everything and before the back end, you have these port monitor programs. And as I mentioned before, they're used to do the protocol and encoding kinds of things with the data that your driver is sending out. It's a way to have the advantages of a back end without having to write a back end.
It's only supported on Leopard. And we provide the BCP and TBCP for port monitors for postscript printers. So if your printer needs TBCP encoding to do binary printing, just tag that in the PPD file and you'll see here CUPS port monitors, the attribute you define. And back end name. In this case, USB. Defines that when I'm printing to a USB interface I need to use this port monitor. And we have a human readable name so that we know what that port monitor is doing. And then the name of the port monitor. In this case, TBCP.
All the way at the end of the print chain you have the back end. This is the one that communicates with the printer. It's like any other filter, but, you know, it's the last one in the chain. So there's nobody else it needs to talk to but the printer.
Back ends also perform another function in that they list the available devices or printers that are supported by that back end. And you find some back ends, like in CUPS, the S N M P back end, actually don't do any printing. All they do is discovery. So there's a lot of possibilities there if you have a specify device and you need to discover it. But once it's discovered you can use the standard protocol. You can act as a proxy for that protocol. You register these not in the PPD file, but by putting them in the back end directory.
And unless you set them to mode 700, they're going to be run as the L P user. This is different from previous releases. We've done this to enhance the security of CUPS. Because most back ends don't need to run as root. And I'll caution you, if you're using running as root so you can read from the user's home directory , that's really not a good thing to do. Because the user's home directory might be on somebody else's machine.
So keep that in mind. If you have something that depends on running as root you will need to change the permissions to 700 and then it will run as root on Leopard. And as far as previous releases go, they won't care. They will just see the back end and run it as root regardless. So make sure to check that in your own back ends if you have them.
Now the last thing, I kind of lumped it into printer drivers. But you could actually develop these separate from printer drivers, is the notifier. And the notifier is a program that's run to notify the user of some event. You install them and user lib exec CUPS notifier, and then you can subscribe to events for that particular notifier via the CUPS API or various other programs that are available on the net. They're run on demand. And you read any I G P messages that you need to forward on to whatever protocol you're using. From standard input.
And send them out. And if you look at the example notifiers in the sample source code, you will see that the -- the loop for that is very simple. You just -- wow, I can read a message. I can send a notification. And when I end a file I exit.
We've got two helper functions for you to give you human readable text. CUPS Notify Subject and Cups Notify Text. They take the message that you received and process it and give you sometimes that you can then display to the user. It's localized for the language that's -- that's set. And just very simple messages and everything. So if you're doing anything that don't require any detailed responses, use those functions.
Now on the Leopard side, we now actually have support for this auto set up tool. Use register in N A PD file with A P auto set up tool. And provide the path to your tool, which would be under library printer's vendor name. This gets run when you add the queue.
And it will be able to configure the printer and the PPD file with whatever installable options are in there, an even set the defaults for media, size and paper tray if that information is available from your printer. Custody Print Dialogue panes, which used to be called PD Es, provide extra panes in the Print Dialogue for printer specific options.
So the general rule of thumb is use a custom Print Dialogue pane if what you can do in a PPD file is insufficient. So if you're doing something where you need to have 5-way dependencies between 50 options, P you might want to do a custom Print Dialogue pane to handle that and to provide the user with a useable interface rather than pick from a bunch of lists and resolve a lot of those constriction dialogues.
It's important when you compile these that they are full way fact, and also have Garbage Collection enabled. There's a little check box in Xcode for that. So that they will work with all applications. If you have a Carbon pane, that will not work with 64-bit applications. And similarly, if you have a -- a 64-bit pane but it's not Garbage Collection enabled, it's won't work for a Garbage Collection application. So it's important when you compile these things make sure that they have those options enabled. And then they'll work everywhere.
Another thing to keep in mind is these don't get invoked if you don't use the standard Print Dialogue. So if you're printing from Microsoft Office or you're printing from the command line, those options that you're expecting from your custom PD E won't actually be coming to your driver because they were never generated.
So keep that in mind. Have some defaults that you can use in case there aren't those options, or, you know, fail accordingly. You register all your -- your dialogue panes with the A P dialogue extension attribute. You can have one or more of those. And they'll appear in that order in your Print Dialogue. And there's an output PINs example that you can look at. Believe it shows all the basics. And build your own custom panes from there.
Now the monitoring tool, again, is something where you can monitor the of ink levels, what paper trays are empty -- any kind of monitoring you need to do for your device. You register it in the PPD file with A P printer low ink tool attribute. And again, library printer vendor name whatever the application is.
And it will get run and show you the -- the status of the queue as needed. The last thing is the printer utility. You have A P printer utility paths specifies where to find that. Again, this is where you do your printer maintenance. Clean the print heads, align the print heads, anything that you need to do with that.
On the support files front -- there's A P book file. Which defines your help file. So when somebody clicks on help and says, hey, what do I do with this error message, it will forward you to your page so that they know what to do. The color profiles for your particular printer are defined with CUPS ICC profile. And there's a whole bunch of selectors that go along with that. If you look in the CUPS documentation under the PPD specification you will find a nice verbose description of this. There's also a tech note off the Apple developer's site.
On the same subject. And basically allows you to define the color profile that will be used when ripping the data for your printer. And then the icon is API icon path. And then you're sending it to a Tif file or an ICNS file or whatever -- whatever you happen to use.
Now if your driver needs to define custom file times and the vast majority of them don't, you define them in the private et cetera CUPS directory. And you create a dot types file to define the file type. And a dot com file to define the filters that are used for that file type.
More typically, this is used if you're developing an application or some sort of a service that's converting some custom file types, say, an XML document, into something printable. You would use this to define the filter that's used for that data. The convention is you use the vendor name, dot application name, dot types for the types file, and then again, vendor name dot app name dot coms for the conversion file.
Now I'm going it talk a little bit about writing a CUPS Raster driver. Because by far we get the most questions about this. CUPS Raster drivers are very simple. You have to a Raster filter, which converts CUPS Raster data, which is essentially a page header that says this is the page size and the media source. And the other options you use are selected for this page, and then the image for that page. And then the next page header and the next page image, and so on. Until you reach the end of the file.
So you have this filter that reads that Raster data and converts it into something that can be printed. And then you can optionally provide a command filter. And this is something that we've added new in Leopard. Basically to have basic control commands instead of having your own custom printer utility, if all you need is print a self-test page or clean print heads, you can implement that via the command filter. Again, both of these get done with the CUPS filter attribute in the PPD file. And then you just point them to library printers, run your name, an then the filter name.
Now in the main loop for your Raster driver you're going to open up a stream for the Raster data. And in this case we're using CUPS Raster open. We're reading from file descriptors zero, which is standard input. And then we just do a wild loop. While we can read a page header we send out a message to standard error saying we are printing a page, and please do this, otherwise paper counting doesn't work. We allocate memory for the line of -- each line of data we're reading from the Raster page. And then we do whatever Page Setup commands we need to do for our printer.
Once we've done that we loop through every line in the page image. We give the user some status information. Hey, I'm printing page 1 and I'm at 53 percent. And then we convert that Raster data into something the printer can take. So PCL, NACP -- what have you. Once we're done reading the page we'll free the buffer that we had. We'll send out any end of page commands that we need to for the printer. And then we'll go and do that again.
Once we get to the last one we don't have any more page headers. We close the stream and we exit. And we're done. So very simple to do this Raster driver. It's meant to go a line at a time. But there are drivers that buffer up into bands and so forth. However works best for your device. You just read the data from the standard input.
Now as you're going along and you're notifying the user of what's happening, you're sending messages to standard error. And there's little prefix strings that we use to tell the scheduler what kind of message it is. So if you have info on the front of it, it's just general information for the user.
And it gets sent to the user but not generally to the error log file. Because if you're seeing 500 messages that say printing page 1, zero percent, it's not all that useful for debugging. So we don't put info messages into the error log file unless you set it to the highest log level.
Error messages do get logged in the error log file. But they also get sent to the user. And you use error on the front of it. And again, if you're developing this, it's kind of straight forward once you kind of look at the code. Debug messages don't normally go into the error log file unless you enable debugging.
But if you're providing tech support, it's very useful to have some debug in there so that when somebody calls you up and said I can't print to your printer, you can say, okay, turn on the debug logging, an then let's look in that error log file and we'll see what messages are coming from the driver.
Those page messages that I mentioned earlier are very important. If you don't put them out then page accounting doesn't work, and you don't see anything in the page log file saying that your driver printed anything. Without the page messages, you don't get any kind of accounting on the system. So make sure you put them out if you're a Raster driver. Because you're the only one that's going to do it.
And finally, there's a state message, this is something new in Leopard. And it allows you to set the printer state reasons values that are being reported for that printer. This is how you can actually notify somebody via the notification mechanism we talked about earlier that something's happened on the printer. So you can say state paused.
And that will actually stop the queue and alert the Admin that something really bad has happened. Or you can -- if you're monitoring the ink levels as you're going through, you can say state marker low. And it will notify the user that hey, you're low on ink. So those are the general messages that you'll send. They all go to standard error, and the scheduler sorts them out.
Now, we get a lot of messages from people on the CUPS forums that I cancelled my job and the printer keeps printing. The reason for this is because a lot of drivers don't actually implement a signal handler to know when they're being stopped. So what you need to do is use the signal function to register a function to call when the scheduler cancels your job. We send sig term (assumed spelling).
Once you get that, you want to set a flag. Because the signal handler can't really do a whole lot. And then in your main loop you can check to see if that flag's been set. And then you can clean up gracefully and, you know, eject the last page and you know the printer's in a good state. If you don't do that, it will probably just terminate your driver, an then the next job that comes through will be printing to the printer in an unknown state, and it's probably going to spew garbage -- and user will be angry.
Now when you're writing all this Raster data sometimes you need to communicate with the printer and know what state its in. So this is where the batch handle comes in. If you're sending out a command to the printer, okay, tell me what's going on. You also want to flush standard output if you're using the buffer output. So that the data does get to the back end.
And then use the back channel read function to read that data back. And here I use the example of a five second time out. Whatever it appropriate for your device is what you should use. Five seconds is a general rule of thumb for most devices. And what you'll get back is either the number of bytes that the printer provided you, or zero, indicating that -- that nothing came back.
The time out there helps you avoid a dead lock situation where you send something, expect something back, and the printer doesn't respond. Not all interfaces support by directional IO. So it's important to find out that before you do this. There's a side channel API to actually query this. And we'll show that here in just a sec.
So the side channel APIs, as I mentioned before -- it's a little more complicated that than back channel API. There's three functions. The one you use in your drivers is going to be CUPS Side Channel Do Request and you're going to send one of five commands. And the one in particular for the buy directional support is CUPS C S command get by die to get back whether or not the back end support is bidirectional.
And if you're doing this, keep in mind that of those five commands, not all of them are supported by all back ends because they're not all supportable on all back ends. So check the status that you get back from the back end as to whether it's supported that operation or not. There's actually a status code for that. And just keep in mind. Most of them are going to support drain output, which gets everything out to the printer. And get bidirectional capabilities. But most will not support the others.
So we want to check for bidirectional support. There's a header file include CUPS slash side channel dot H. And then you initialize this buffer to hold the response. In this case it's going to be a 1 byte response. So you can do care data and then we pass that through to CUPS side channel do request. And we ask for the bidirectional capabilities.
And you notice we check -- we get the status back. And if the status is okay and we got 1 byte of data back, then we know we can use that value. Otherwise we're just going to assume that bidirectional is not supported because we got some response we didn't understand.
Now that's the CUPS Raster driver path there. And you know, a lot of you are doing those. But more generally, if you're developing a printer driver, there are tools available to do all of the heavy lifting. CUPS driver development kit. It's available on CUPS dot org. It's free. There's source code and the universal binary for Mac OS X. It's not included with Leopard.
But you can install it on Leopard, and you'll see that in a second on the demo machine. If you're going to be developing drivers you're going to need CUPS 1.2 or higher. Which means Leopard to do the driver development. But what you create can be used on any version of Mac OS X back to panther's 10.3.
There's three major components. The PPD Compiler, the support tools for PPD files, and last but not least, there's some sample drivers that you can use. These sample drivers are much more functional than what comes with CUPS. And we've used them for anything from a little ink jet printer all the way up to big copiers.
Now the PPD Compiler is equivalent to, like, a C Compiler. And if you're ever developed a PPD file it's a bit like machine language. You know, you can develop it and you know, put in all the attributes and everything, write it by hand, but it's really hard to maintain.
And I know from experience looking at PPD files, it looks like there's a lot of cut and paste that goes on in order to keep these maintained and move up to new drivers. We've been using this particular tool for many years internally to create the PPD files we use.
And basically it allows you to use a higher level description of the device to generate PPD files programatically, rather than doing it all by hand. There's a lot of advantages with this. If you're developing drivers for a lot of similar devices, or if you want to have a separate PPD for every variation of a device, you can define those differences in the file that you use for the PPD Compiler. And generate from that one source more multiple languages and multiple platforms.
So if gives you a lot of advantages over just doing everything by hand. So please do use it. You can generate single or multi language PPD files with a DDK PPD Compiler. They can be compressed or uncompressed, depending on the platform you're shipping for, an you can control the line endings. So if you've got a postscript printer and you want to support this on multiple platforms that will get you into that situation very quickly.
When you actually run the PPD Compiler, it's very simple. You provide the file that you're going to convert on the command line. And it creates by default a PD sub directory that contains the PPD files defined in there. If you wanted to add additional languages to that PPD file that you create you can just list them on the command line there. In this case, we'll do French and German in addition to the English. And you've got PPD files that contain English, German, and French without any -- any extra development time.
And then finally, if you want to generate compressed PPD files, which is not the default in the current release, use them to the Z option and then you get nice compressed files for distribution now a lot of you have existing PPD files you don't necessarily want to go to the trouble of creating new PPD files to use with the PPD Compiler.
There's a merge application that can merge single language PPD files into multi language ones. And a lot of you have been using that to great effect. If you want to use the PPD Compiler you can actually import those existing PPD into a dot DRV file that the PPD Compiler uses. And then regenerate them as needed after you've made your changes. So if you've got existing stuff you can use this, and start using the PPD Compiler for your generation of PPDs in the future.
If you have people that are doing the localization for you separate, you can actually take the options that are defined in your -- in your DRV file into a message catalog. (Inaudible) new text format. They then edit that, provide it back to you, an then you can incorporate it into the PPDs that you generate.
And finally for the managers here, if you want to see what drivers are being supported by a particular dot G R V file, you can generate this HTML file that gives you a nice little summary of the printers and the options that are available in there. And last but not least, the Raster drivers we've included. There's two main drivers. A PCL driver for basically any HP or HP compatible driver in existence. And an E S C P 2 driver for all of the Epson ink jet printers.
Both of these drivers are completely customizable through the PPD files. So you don't have to do any changes to the drivers themselves unless you really want to incorporate something custom to your driver. They provide dithering and ink limiting and color management functionality in them, so that you can actually set things up in the PPD file and the driver will behavior accordingly. And we include command filters to do the basic head cleaning and self-test page.
Now the PC L driver supports all the major PC L variants, as well as H P R T L for the plotters. It supports P GL device commands. So if you have a device that supports stapling, punching, finishing, folding -- all that stuff -- and using P GL for that, you can actually set that up in the PPD file and it will use those.
And we support gray scale and color printing, and various color spaces. Similarly, with the E S C P 2 driver, we support the two main commands that are used for the older an the newer Epson ink jets. We support the publicly documented remote mode commands. And various color spaces, up to 7 color. And we'll have 8 color at some point.
We handle all of the weaving code that's necessary for the Epson printers so that if you're printing at a higher resolution it will actually work on the printer rather than generating some sort of error. So without further ado, we'll do a quick demo on the demo machine here.
And I've got the -- from the DDK there are several examples. And the R 300 basic example is the one we're going to start with. And I actually have an R 260 Epson photo printer up here. And we're going to modify this R 300 driver so that it works with the 260 as well. Now that DRV file is a plain text file. I have it open in Xcode right now. And starts off with some standards includes. Font definitions for standard fonts on the system, and media definitions for standard media sizes that are defined in the PPD section.
Since we're using the Epson driver we're going to include the header for that. We're going to say we're using that driver. And that will define the CUPS filters that are associated with that driver. And then we're going to do the model number for the printer. And in the case of the sample drivers, we're using the model number as kind of a capabilities number for the driver. So in this case, we support various command sets.
We put them all inside parentheses, and we're using constants that are defined in that E S E P dot H header file. And they're orred together by using the parentheses there. So if you have a driver that supports multiple devices you can actually identify which device you're going to be write for with this model number. And this gets in the PPD file and the CUPS model number attribute. Since we wanted to include support for all the fonts that are on the system, we do font star. We identify the manufacturer and the driver version.
And then we list out all the paper sizes that we support. And you notice there's a hardware margins command there that tells you what margins to use for each size. And if you have different margins for each size you can just put the new margin that you need before the media size. And then since this printer supports variable sizes, we tell the PPD Compiler we support various sizes, and then the size range. So the minimum size and the maximum size. And width and height.
This particular printer supports black and white and color printing. So we have four different color spaces we're defining here. There's gray scale and RGB, which correspond to screen color. And then there's black and C M Y K, which correspond to a linear device color space that you would use for profiling.
This particular printer supports a number of resolutions. This sample driver does 360, 720, and 1440 D P I. And the numbers there actually mean something. And you'll find in the DDK documentation what each one of them means. In short, it's the -- the second number there is the number of lines that the print head prints. And then the last number here is what you need it do in order to print at that resolution. And -- a little complicated, but there's a nice description of it in the documentation.
Because this is a color printer we need to tell it how many channels of color are actually are. In this case, it's a six-color printer. And how much ink to put down on the page at any given page. At 1.0 means 100 percent, 2.0 means 200 percent. So in this case we don't want to put more than 200 percent ink. There's some basic mapping for the -- the light inks. You can define it with custom look up tables or this stuff, since we're using the basic example, we're going to use this.
And then dithering constants to use for the various resolutions. These will vary depending on the printer that you're using. Last but not least, we've got the dot sizes that are going to be used for the printer. And then we'd actually define the printer that we want and the PPD that we want to create.
So in order to add support for the 260, it's a similar printer to the 300, but it's a little bit different. So I am just going to bring up and highlight the differences everything up to this point has been the same. But what we're going to do is break out the resolution dot size and model name information into two separate groupings.
You see, we have the curly braces -- this is how you do nesting in the driver info files. It allows you to create multiple PPD files from a single dot DRV file. So here we have the 260. We've changed the numbers there, the last numbers (Inaudible) for the resolutions. We've changed the dot size constants, and then obviously the model name and the PPD is changed.
The original one here is exactly as it was from the example from the DDK manual. And when we run the PPD Compiler, we'll actually get two PPD files. The first one there is the -- the PPD for the R 260, and the second one for the R 300. And we can create a print queue.
Using that PPD, using the L P Admin command or you know, if you were distributing this driver they would just use the standard printer sharing and printer effects set up pane. An then we can print something out on the printer. And as they do on the cooking shows -- here's what it looks like when it comes out! Basically --
( Applause )
So basically you get the output on the printer. And it is doing its work. And as ink jets go it's fairly fast. But not fast enough for this demo.
As you can see, you can create new drivers very easily. Typically, these are going to be used for the Epson printers. For any kind of drivers that you'll do custom ink sets. But for the PC L driver you will probably find a lot for applicability for copiers and other H P compatible devices that don't necessarily have postscript capability. So if we can switch back to the slides.
Now that you've seen all this you can look at the documentation that goes into much more depth than I can possibly do in the amount of time allotted. There's the original CUPS book. It's still available in stores. Amazon dot com and so forth. It covers everything in the previous versions of Mac OS X and also covers some stuff from CUPS 1.2 that's in Leopard. Particularly notifiers and some of the back channel stuff you find documentation for. They were designed but not actually implemented at that point when I wrote the book seven years ago.
And so it's still a really good reference. If you need information about the current release, you can look on the CUPS Web site or on your local system, local host colon 631 slash help. And search for whatever it is you're looking for. You will find information on doing operation policies, error policies and so forth, to actually do stuff in your own environment. Much more in depth than what you're going to get in the CUPS book. Because those topics didn't even exist then.
There's also a printing page Apple provides on the developer site. That gives you all of the stuff that's specify to Leopard and all other Mac OS X releases. They have all the tech notes that are useful for your CUPS Raster drivers in particular. So take a look at there, and if you have any questions, please do get onto the CUPS forums, or the Apple printing list and ask them, because we're here to answer your questions.
If you go on the CUPS dot org site you will also be able to also subscribe to those forms via your news reader or post them on line. We've got a little Web interface for that. And there's a bug reporting page there. So if you actually have a bug that's in CUPS, report it there. If you have a bug that's specific to Mac OS X, please report it through the radar.