Media • 1:15:45
The Mac OS X printing system integrates key technologies such as Quartz and CUPS to produce high-quality printed output. Learn how to deliver flexible printing capabilities and provide exceptional printed output in your application, and learn best practices for enhancing your customers' printing experience. Whether you create applications that print, create printer management software, or develop printer drivers, you'll learn about the latest printing advances in Mac OS X at this information-packed session.
Speakers: Howard Miller, Mike Sweet
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Okay, welcome to the Mac OS X printing session. For those who haven't met me, my name is Howard Miller. I'm the engineering manager for the printing team. Before we get started here, let's see if we can wake people up a little bit. I know you guys got the party tonight, so everybody was trying to sleep in this morning, so I thank you for being here.
I see a lot of people out there that I know to be printer driver, printer developers. How many of these guys do we have? A lot, many from around the world. Thank you for being here. How many people are brand new to the Mac platform?
[Transcript missing]
Ad printers changed. We've exposed some power of CUPS. There'll be access control lists, users and passwords per printer queue. The queue window, we've added an inline preview, which lets you see your job in flight, which is great. We've done some stuff to integrate more tightly with multifunction devices. Major changes and improvements to our SDK. I mentioned the driver thing, and then of course CUPS 1.4.
Everybody's seen the system preferences. Everybody knows about the little plus to add printer, and everybody knows on Leopard you get this floating window that you can lose. It's now a sheet. You will not be losing that anymore. Look at it closely. We've also greatly simplified it. No 47 different tool items to pick across the top. Bad news is it's in your seed, but you can't see it. So you'll see the old one for right now, but in a future seed we'll get that one turned on for you.
In the... In the sharing controls, there's always been printer sharing. Now you'll notice that you can actually add access control. So you can select a printer and hit the plus button in terms of who can use the printer, and then you can add users or groups. So now on a per-printer basis, you can provide user password.
Howard Miller, Mike Sweet In our desktop printer, this is in your seed, We have the view of print jobs, so you can hit the View button, and you will get the quick look view of items that are in your print queue. We're going to try to do more with this, but we'll see how far we get as we progress through the OS, but at least now you can see your print jobs.
Also in the printer proxy, though not in your seed, you'll be able to scan directly from the desktop printer. The support that we're trying to build in, the concept is grab any handful of pictures, throw them on your scanner. We will find them, identify their bounds, straighten them, crop them, and give you individual pictures. You should be able to scan directly into preview so you can see them. You should be able to scan to your desktop or iPhoto. Howard Miller, Mike Sweet This sheet, this capability is also being exposed system-wide. Every application will be able to pick this up.
So scanning is no longer a corner case hidden item. We think it's going to be mainstream. Of course, if you're making printers, you know that half or three-quarters of all printers sold are multifunction, so there's a scanner there anyway. So if your printer driver developer, many of them are in the room, provide an ICA-compatible driver, this functionality becomes almost free for your application.
Let me talk a little bit about some of the things that are changing. AppleTalk was invented before many people I know were born. It has been an absolutely wonderful protocol. It has served everyone extremely well. It is no longer in Snow Leopard. It goes and it ends. It will not be there. The first printer I worked on at Apple was the LaserWriter 16600. Does anybody in the room still have one of those? Yeah, they're very reliable. They're great printers. They're officially done.
Companies, you know, Lexmark, Brother, sell great printers. HP will give you a rebate or discount right now. So for about $300, you can replace that 16600 with a great PostScript printer by a manufacturer, many of them, higher resolution, higher speed. Howard Miller, Mike Sweet Apple Talk is dead.
If somebody thinks they have a customer installation where this is a big problem, send us mail. We'll try and work through. Howard Miller, Mike Sweet But our official answer is bonkers. Howard Miller, Mike Sweet Bonjour. Bonjour has officially been in the OS since 10.3. In 10.2, it had a different name, which we won't talk about. But virtually every PostScript and most network printers do support Bonjour with an underlying IP print transport layer. So that's our official answer. You will not find Apple Talk. It is not a bug.
A few other things, and I put gradients on these. Tioga printer drivers. This is where we introduced with DP4, was part of Mac OS X, the original. We integrated CUPS many years ago in X2, and we've been encouraging people to move to CUPS drivers. Starting in Tiger, we felt that every driver could be created with CUPS. We are now removing all the Tioga header files. You will no longer be able to build Tioga technology drivers on Snow Leopard.
Likewise, Carbon PDEs, again, introduced at the beginning of Mac OS X, and we have switched to Cocoa PDEs officially in X4, and we are removing all of the headers for this. This would include application panes and print dialogues. So anybody who's adding those and you're still using the old Carbon PDEs, be aware you will no longer be able to build them on Snow Leopard. That said, Tioga drivers that are well-written, Mike will talk later about what may be not well-written, but well-written Tioga drivers should continue to run on Snow Leopard. A well-written Carbon PDE will run on Snow Leopard.
One problem, Carbon PDEs will not run in 64-bit applications. On your seed today, you will find many of the Apple applications have already been converted to 64-bit. Preview, for example. Customers do not have a switch to say run 32-bit, run 64-bit. So if you've provided Carbon PDEs, many of the applications your users have on Snow Leopard are going to be 64-bit, and so your Carbon PDEs will not run. So yet another reason to move to Cocoa.
Okay, so I mentioned a little bit about image capture. For those interested, there is an image capture session later on today. There is a lab directly following this meeting. It's always been the tradition to meet in the hallway, but this year we got smart. We scheduled the lab right after the printing session. So just move on down. We're the second to the last on the right, the media lab. Most of the engineering team will be there. Developer support will be there. Evangelism will be there. We should be able to answer just about any question that you've got.
So we're going to talk about today, which I kind of hinted at. We're going to cover application printing. We're going to start from the basics. We're going to start with the most fundamental APIs, and we will move through the printing stack and show you the APIs of importance. We're going to show you how to customize the print dialog. We will give you some pointers and tips as to how to produce high-quality output. And then there's a few header file changes, which I alluded to. We'll show you in detail what we're doing.
Howard Miller, Mike Sweet After that, we're going to talk about CUPS, and we'll go through the background for those who haven't been fully familiar with CUPS. We'll show you its architecture, and then we'll spend some time on exactly what's new in Snow Leopard, which is CUPS 1.4. So with that, I want to introduce Alan Beck, who's going to talk about application printing.
Thank you, Howard. So today, well, actually, first I want to say it's great to be up here again this year. It's a great WWDC, and I am going to basically be talking about the application printing and how it relates basically to Cocoa applications. So we're going to start talking about the basics of how do you get your application to get output onto your paper.
Then we'll just move on to how to customize the print dialog, and not just the print dialog, how do you customize the printing experience for your user. Howard Miller, Mike Sweet Then we'll go on to how to produce high-quality output, and finally, utilizing print core printing. So here are the basic APIs that application developer sees. On the very top, we have your application. Then we move down to the Cocoa Printing classes.
This is the basic API that your application should be using. Then underneath that, the Cocoa Printing Classes are built on the core printing APIs. And finally, we have the CUPS, the Common Unix Printing System, which is CUPS, which basically does all the real work for the printing system. So right now, we're gonna dive a little more into the Cocoa Printing Classes.
There are basically only five classes in all of the Cocoa stack that deals with printing, and they're basically very easy. First, we have NS Printer, which basically encapsulates Information about the printer, like what options it has, is it duplex, what options are installed, what list of papers does it support? It's just basically your access to information about the printer.
Next we have the NS Print Info, which basically contains information about a print job, like how many copies you have, whether you want NUP, and then we get into some of the page setup information, what page size was selected, and the scaling that the user may have chosen.
Then we have the NSPrintPanel and NSPageLayout, which is basically it's the print dialog or the page setup dialog. It's how they get onto the screen. And finally, we have the NSPrintOperation, which basically grabs all of those together and puts them in one object that you can get access to and get the information out that you need.
These classes basically provide all the information that you need as an application developer to print. They're very simple, they're really not that complex, and they're very easy to use, as I will show you. As I said before, these classes are built upon core printing, so you as the application developer should never really need to go down to the core printing API except for certain cases, which I'll explain later.
And if you base your application on the NS document model, a lot of this is done for free. The Cocoa printing system handles adding the print dialog, running the print dialog. There's just a very few operations that you would need to override to get basic printing to work.
So let's talk about what's the minimal set that an outpatient would need to use to get the user to be able to print. There's basically three easy steps. There's only three steps that you need to get your application to print. First of all, you'd create an NSPrint operation, then you'd run the operation, which basically put the print dialog up on the screen, and then you would draw the content and your views draw erect. So here's some basic sample code.
So in your Views Draw Rect, what's passed in is the rect of the page that you're printing. And you would use the Core Graphics APIs to draw the content for your application, whether it be lines, text, whatever you need to draw. So, and one other thing is this is the same draw rack that is used to draw to the screen. So there is no difference between drawing on paper and drawing to the screen. The same methods are called.
Okay, now let's say your user selects the print command from the menu. This is what you would need to do. First of all, you'd create a print operation. And one of the, yeah, it just basically has two parameters. One of them is the view, is my print view, basically is the view that you want to print. And the second parameter is the print info. Basically, it's the encapsulation of the information that we need to actually print the job, like I said, copies, pages, and all the other stuff that the user may select.
And finally, you run the operation. There are two ways to run the operation. One of them is as a sheet on your document window, which is the preferred way of presenting the print dialog. And the other one is just run operation, which basically runs it as a modal dialog for your application. So here we're doing it as a sheet. So we're calling the print operations runOperationModalForWindow. We give it our document window.
We tell it which delegate to use, which is ourself, and then we pass in the did run selector, which basically is this method will be called when the dialog goes away. So you will know... You will know when the dial goes away and if you need to do any cleanup after that point.
And then when the dialogue goes away, the printing system, the Cocoa Printing classes will then call your view sequentially, page by page. We'll do a draw rock for page one. You will go ahead and draw your page one information. We'll call draw rock again for page two with a different rectangle, basically going down, stepping down your view on a per-page basis. So it's very simple. You draw on your draw rect, you create a print operation, then you run the print operation.
So now that we've talked about how you get, how your application draws, let's talk about more, a little bit about how do you customize your printing experience. There's multiple ways you can do that. First of all is you customize the print dialog. This basically allows you to present information to the user that you think is important. You can customize the printing experience by doing custom pagination. And finally, you can use the core printing APIs to do some other stuff as well. So let's talk a little bit more about customizing print dialog and ways that you as an application developer can do this.
You can add page setup functionality to the print dialog. If your application creates, draws, and formats data on the fly, there really is no need for a page setup menu item. There is no document that is associated with that page setup information. So you can actually add these items to the print dialog. As you can see right here, Use applications can specify which of the page set of items you want. You can have page size, orientation, and/or scale. You can pick any combination of these.
Say you only want to allow orientation to change in your application. You can just say, "I want to add the orientation." Then if you do this, if you do add it to the page setup, print dialog, go ahead and remove the page setup menu item from your file menu. There is no need for it.
The user, if you're going to do it at print time, the user doesn't want to have to decide which one do I do? Do I want to do in the page setup dialog, or do I want to do it in the print dialog? So just remove the page setup item if you think it's appropriate for your application. I want to say this is very easy to do.
Here again, basically you have two steps. First of all, You create your printer operation like we did before, so there's no change there. And then from the print operation, you go ahead and get your print panel out. This is the encapsulation. of the print dialog for your application. So basically, you get the print panel out of the print operation.
And lastly, what you do is you set the options that you want for your print panel to show. In this case, We want to show just the paper size and orientation. So what we do is we call in the print panel, we tell it to set its options to. We get the current options, which basically is the default options. It says I want copies, I want page range, basically I want preview, and all that stuff.
You get the current operations, then you just orient the options that you want, which I'm orienting in to show paper size and show orientation. So again, it's very simple. There's basically two steps. You get the print panel from the print operation, your current print operation, then you just set the options for the print panel to what you want to show.
Another way your application might want to customize the print dialog is to not show our copies or our page range. They're not needed. Say your application always wants to print five copies of every document that prints. Therefore, you would just remove the copies field from the print dialog.
And it wouldn't show. Same thing with page range. But here it's like, if your application do a better job of page range, go ahead and do it. Don't show ours and show yours. In this case, They're not showing ours, and they're doing their own page range, which allows them to do the textual version of page range, one to three, five, seven, and nine. That's one way of doing it.
So basically, if your application can do a better job than what we're doing, go ahead and don't show ours and show yours. And again, here again, it's very easy. It's just like the page setup. Adding the page setup items, you just basically, it's an option that you set in the print panel's options, basically taking away the page range or the copies.
Print selection. This has been Instance Leopard. For some applications, basically we're providing a common UI to allow your users to only print a selection. Windows users have had this for a long time, and we're just allowing you to have the common UI to say, only let the user print the selection.
You have to opt in for this functionality just like everything else, but the problem is, we as a printing system, we don't know what your selection is. So what we're going to do is we're going to set this key in the NS Print Info, we're going to set the KPM Print Selection Only key in the NS Print Info.
Then when it comes time to draw, it's up to you, the application developer, to read the value out of the print settings and decide, "Do I want to draw my whole document or just only selection?" So here it is. You have the pages. We have the all from, and we added a third radio button, which is just selection. So I'm going to do a quick demo of how easy it is to add print selection to your application.
So I have a version of Sketch, my favorite sample app. I've done, it's the basic Sketch that is on your WWDC DVD, with just a few minor changes. I will get to them soon. Okay, so let's just open, this is a document-based application. So I'm going to open up NSDocument, their Sketch's document override, or subclass. I'm going to go down to Print Operation with Settings.
Here we are. This is where we create the print operation. The only change I've made to this is, in the rendering view, it used to just pass An array of your graphics that you have. Actually, before I do that, let's go ahead and run it so you can see what Sketch looks like. So basically, it has a bunch of, you can have squares, circles, and lines, and text, and whatever you want.
And so basically, it's just an array of these graphics objects. And you can select, you know, multiple selections and stuff like that. So the basic version of Sketch, Basically, it used to pass in the adjacent array of the graphics. For dealing with print selection, we need more than just the array of the graphics, we need the array controller, which basically gives us the graphics and the current selection in the array. So basically, I'm just passing the array controller versus just the basic array.
So here's the print operation. They've created the print operation. That hasn't changed. And we just come down here a little bit. And you might recognize this code, because I just showed you it for adding the page setup stuff. So basically, here I am. I'm getting the print panel out of the print operation.
And secondly, I set the options. I have the print panel set the options to the current options, and I'm lowering in the NS Print Panel Shows Print Selection. So that's all there is to getting the print selection to show in the print dialog. So now let's go to your actually drawing code. So let's go down to the rendering view, and we're at the draw rect.
So in Sketch's DrawRect, first thing we're going to do is we're going to get the print operation by just asking for the current operation that's going on. And from the print operation, we go ahead and get the print settings out of the operation. We get the print info, and from there we get the dictionary, which is the print settings.
And from there, we go ahead and read the value of the K print selection only key. So basically what I'm doing is I'm asking the print settings to get the object for key, and I'm passing in which key I'm looking for, which is the K print selection only key. And if it's true, I'm saying the user wants to print the selection only. Now let's... Okay, so we have that. Next is the index set. Basically, here's the getting the, out of our graphics controller, getting the graphics.
And now we're out of the same graphics controller, we're going to get the set of the selection indexes. Basically, it's the objects that have been selected in the window, the user has selected in the window. So now we have all that stuff, it's time to draw. So in our draw, we're actually going to do the draw. Let's go ahead and get rid of both of these comments.
Okay, we have a graphic right here. If we're not printing selection only, we're always gonna draw it, which is fine. But if the user has selected print selection only, we say, ask, is this graphic in the selection index? And if it is in the index, Then we will go ahead and draw that. If it's not in the index, we won't draw. Let's just go ahead and run and see how this works. Add some objects again, here we go.
And let's add some lines. Okay, for you guys to see a little bit better, let's go ahead and... Color some of these. Green, let's get a red, and a blue. Let's get a pink. Thinking of my nine-year-old daughter, she loves pink. Okay, so let's go ahead and print this. Actually, let's make sure we have some, let's say I have a couple items selected.
Let's go ahead and print. As you can see, we now have the print selection item available to the user. And as you, you know, slick between printing all pages or just printing selection, the... Our draw record is being called, and we are determining whether we should draw, go through and determining whether we should draw these.
Okay, so that's basically how you add print selection. It's very easy. As you can see, we just added the option to say we want to show print selection to the user, and then in a draw rect, we determine whether we need to draw the selection or not, and then we... When it's time to draw that object, we check the value and we draw it or not.
One last thing I want to do just to show you how easy it is in Cocoa to do some of the other stuff I talked about earlier. We are in the Print Panel, we are set options. Let's go here, let's go and see what we have. Let's go ahead and add an orientation. Let's just orient. orientation here, and let's try just running this one. We're going to stop that.
And here again, brings the print dialog. As you can see, we added orientation, and with just that one little oaring in, Everything just works. The printing system takes care of the Cocoa classes, and the printing system takes care of that the orientation is changing on the printer. You, as the application developer, didn't have to do anything. So that's basically all for the demo. It's just to show you how easy it is to add, to customize the print dialog. Let's go back to the slides.
So I said, there's only basically two actions that you need to do to add print selection to a print dialog. First of all was ORing in the flag to the print options, and then in your draw rect, only checking the value of what was set in the print info, and then choosing whether you need to draw the selection or not.
Adding application panes. That's another way that your application can customize a user's experience. The application panes are always the first panes that are shown in the dialog. As you can see here, preview is the first item in the pop-up menu list. And it brings the important print options to the front. So basically, if your application has items or has options that the user needs to select at print time, this is how you would add them would be through an application pane.
This is a little more difficult than oaring in a flag in the print options, but it's really not that difficult to add an accessory view to the print dialog. Basically, here's the basic steps. You subclass the NSViewController, that's what the application panes are based off of, they are a view controller, and you adopt the NSPrintPanelAccessorizing protocol, which basically adds some methods that you can implement To make the preview work and do other things to make your accessory view work correctly. Then you create a nib for your view, basically an interface builder, create the options that you need.
Next, you would implement the key pass values for affecting preview. What a, that's kind of a tongue twister. Basically, this allows the printing system, the Cocoa printing system, to watch for these values. You return a set of these. And so basically, when these values, they will sit and observe these key paths. And as these key paths change, the printing system will know that we need to update the preview. So it basically allows for the live updating of the preview as the user changes value.
The next two of these are optional. It's basically implement the localized summary items. Basically, this allows your application pane to have an entry in the summary panel of the print dialog to allow the user to see in one quick glance all the print settings that the user is going to be printing with. The next is title. This is the title of your pane in the panel pop-up menu. We give you the default title of your application name. If you want something else, just go ahead and override this method.
to To add your own title. Then you add the accessory view to the print panel. And that's basically, then you run the dialog, and basically that's it. The old-style version of adding accessory views is deprecated. So we're basically asking developers, application developers, to use this new view controller method to add application paints to the dialog.
So here's, I'm going to go through some code samples of basically showing you what is needed to add an accessory view to the print dialog. First of all, you declare your class. We are declaring a PrintPanelViewController and a subclassed OffaViewController. Then we adopting, and then we have the little brackets, which means we're adopting the NS Print Panel Accessorizing Protocol. And there's only one public method, which is basically creating our shared controller, which we do right here.
Basically, this method just basically creates a shared controller. If we have a static version of our shared controller, if it's nil, we go and create it. We do an alloc of it, and we init it with our nib, which is basically the nib that we created, the NSD print accessory view, and we give it no bundle, and we return it, return our shared controller.
The next thing we do would be go ahead and create your nib. Sample I've here is basically it has one checkbox. It's basically do we want to print a frame around the page for every page that prints. And in this example, I use bindings in Interface Builder. I bound the checkbox to modifying the file's owner print page frame key path.
Okay, now dealing with the KVO stuff, dealing with how do we get the preview to know that you've changed stuff and how to redraw it, it needs to be redrawn. So basically we have the key value, key paths for values affecting preview. Basically we're asking you to return a set of all the key paths that you will be, the user has the option of changing that needs to be reflected in the preview of the print dialog.
Then we have the KVO methods, which is basically dealing with those key paths, the set and get methods. Basically, the get method, the print page frame, and the set page frame. For this example, we're just reading it out of the NS user defaults and the print page frame preference key. We're either getting it or we're setting it in NS user defaults.
Then we have the summary and the title that I talked about. For localized summary items, basically we're asking you to return a localized summary item The Mac OS X printing system is a very complex array of summary dictionaries. It's kind of long. Basically, we want you to return us an array, and the array should contain dictionaries of lines that you want to show on the summary dialog. In this case, here we have the print page frame, which is basically the name of the item.
Then we have the description of that item, which is the NS Print Panel Accessory Summary Item Description Key, which is basically whether we want to print the, if we check to see are we printing the page frame or not, and we just set it to be on or off, and we return the array.
So it's really not that hard to add summary items to the summary pane. Then we have the title, for the title of your pane. Basically, we turn in a string, and this one is basically my sample application. You only need to do this if you want something different than your application name as the name of your panel.
Now we're almost done with this. Basically, kind of like setting the other options for the print dialog, you take the print panel and you add your accessory controller to the print panel. And that's basically it. Then it will be added when the dialogue is brought up, the operation is run, your panel will be the first panel shown. And lastly, in your view method, You basically read the value out of the preferences file. If it's set, say they want to print the page frame, we just set the color and frame the rect of our views bounds.
So basically here's a little example. It's Sketch again. We have the print page frame. User clicks it. The frame is put around. Page in the preview. So everything, because we did the KVO stuff that I talked about, we know that the preview needs to be drawn when the user clicks the button. So if you are going to be adding a panel to the print dialog, here's a few guidelines that we have.
We ask that you shouldn't be providing formatting options. It's just print time options that the user needs to change, that you feel the user needs to set, or options the user needs to have to affect what gets printed on the page. Howard Miller, Mike Sweet And not every application needs one.
There are plenty of other panels that will show up in the dialog, whether it be our panels like layout and all the print panels for setting quality and stuff. So just don't add a panel just for the sake of adding a panel. If it's not needed for your application, don't add one.
Suggested width, we have 420 pixels as the maximum. If you go beyond that, we will need to grow the print dialog, resize it, and move it when your panel is selected. So basically, we're asking that you keep it to 420 maximum. Another thing we're asking is, you saw my nib that I created, my view was the smallest view I have around my checkbox.
We, the printing system, will take care of centering that and centering it in the space available for the print panels. You don't need to worry about going to the full width of the 420. So we're asking you to make it as small as possible, and we will take care of the centering of your panel in the print dialog.
Suggested height, 380 scanlines. Think about the MacBooks and MacBook Airs. They have a maximum height of 800 scanlines. So if you go beyond a certain amount, the print button falls off the bottom of the print dialog, and the users are like, oh no, what do I do now? I can't print. So we're asking you to... The maximum is 380 scanlines to allow all users of all of our different computers to be able to see the print button at the bottom of the dialog.
Application view versus inline preview. As you know, in Leopard, we added the inline preview, but that doesn't mean your application should not have the viewing of the of the printing in your application. WizardWig is still very important to our users. What the user sees on the screen is what they want to see printed on the paper. So don't rely on... This little preview to show the user what they're going to print.
They may want to see what it's going to look like before they hit the print dialog. If it's a format that the user likes to view it in on the screen, why not have it for the print view as well? There again, WYSIWYG is very important to our users. And here's a great example of what we're talking about with the print view. In iPhoto, we have the print card calendar and book views. As you can see, this is what's going to be shown. This is what is going to be... Printed on the paper.
We have the user can change layout, they can change borders, they can change a lot of the options to change what happens on the paper, but they can all do it right here and the user sees exactly what is going to be printed on the
[Transcript missing]
So in summary, customizing the print dialog, it's easy. Basically, that's what I wanna say. It's very easy for you to get what you want.
If I could summarize in one item, it'd be my last item, you get to specify what is shown in the print dialog that makes sense for your application. If you wanna do page range, Hide ours and do yours. If you want to add options to the print dialog, add it and add your own print panel. It's very easy for you to get the options that you want and to create the printing user experience that makes sense for your application.
Now let's talk a little bit about the print driver developers. Print driver developers, they don't have access to the NSView controllers or anything like that. But we do have the Cocoa-based print dialogues. So basically you have the whole bindings in the interface builder to create your nibs and stuff like that.
So it is a much richer experience for the developer to use their Cocoa print dialogue plugins. They work all the way back to Mac OS Tiger and later. And basically we're saying don't create the old Carbon CF plugin-based dialogues. They were deprecated in Tiger, and as Howard said, they only run in 32-bit mode, in 32-bit applications.
If you are a driver developer, you have to worry about the architectures that you are building. On OS X, The application is in charge of the architecture, whether it be PowerPC running in Rosetta, Intel 32, or Intel 34. So we're asking our drivers and developers to make sure you build your plug-ins three-way FAT. We have PowerPC for the PowerPC apps running in Rosetta. We have Intel 32 and Intel 64.
So basically, the processors have to match the application and the plug-in, and the 32 versus 64-bit has to match. As well as, we have to make sure you have garbage collection enabled in your, or aware in your plug-in. So basically, add your finalized methods to your plug-in, and the system will basically turn on or off garbage collection for your plug-in based on if the application you're running in is garbage collected or not.
Howard Miller, Mike Sweet So basically, if you don't do this, you're going to get this, and a lot of your print-- your users are going to get this, and a lot of the print dialogues they see, basically, The architectures don't match. We couldn't run your plugin. We couldn't run your print panel, so those options are not available to the users to select.
Custom pagination. Let's move away from the print dialog and start dealing with your actually drawing code. Custom pagination allows you to basically stop that line being split between page three and page four. You just cut off right in the middle. So basically, it's very easy to do in Cocoa. There's basically two methods that you worry about.
We have the Nose Page Range, which basically tells the printing system, hey, I know my page range. And yes, I will be able to tell you what you need to know. So basically, here we go. We have Nose Page Range. It passes back a range, and whether you basically know your page range or not. So in this case, we get the bounds of our view, and then we go ahead and get the print page height, which is basically how high is the single page height.
for this print job. And then we go and set our range. Basically, we have starting at page one, and we have, say, five pages. Basically, we get the height of our bounds and divide it by the print page height. That tells us how many pages we need plus one because of the zero.
And the second method you need to do is basically a rect for page. You told me how many pages you have. You told the printing system how many pages you have. Now we're going to go through, as each page is about to be printed, hey, we're going to ask you what rect you want for this page. So we say we pass in page one. You tell us what rect of your view you want us to call your draw rect with for page one. We continue doing that for page two, three, four.
So when we get to page four, we tell you, okay, what's the rect for page four? You do your calculations that you need to do, and you tell us the rect that... He tells the rect for that page. This example is a very simple example. We get our bounds, we get our page height, then we make our rect. Basically, the left and the right are the size of our bounds.
The only thing that really matters is the... is the origin. Basically, we take our bounds minus the page number that's being passed in times the page height. So it's very easy to add custom pagination to your application. So basically, users don't get stuff, you know, a little end on page three and the other part of it on page four.
Producing high-quality output. So we're done with a lot of the print dialog stuff, and we're moving on to high-quality output. So I'm gonna talk about things as your drawing, as your application is drawing, what you need to consider, things you need to keep in mind as you're printing.
[Transcript missing]
And then when dealing with the print quality, basically, how do you get the smooth color gradients to show up on the printed output that I see on the screen? How do I get the best quality I can get for the images that I print? So Mac OS X has built-in color management. It's a great system.
We do our best to make sure that the color that the user sees on the screen or the original picture or scanned item or anything like that is faithfully reproduced on the other end when it comes off the printer. The problem is we can't do it by ourself. We need you. We need you to give us device-independent color. How do you do that, you ask? Draw and calibrated color spaces.
That is the easiest way to ensure the quality of the image color will flow through the system correctly. So basically, your picture on your...
[Transcript missing]
You have the nice yellow. When you're drawing with just device color, basically tying it to a specific device, you get this orangish color.
So what do you need to do to get this? Basically, device color is tied to a specific output device. Say you have an RGB color 50% red for a specific device. That red for that device is not going to be the same 50% red on a different device, whether it be laser, going from a laser to an inkjet.
So basically, We don't want you to be tying your colors to a specific device. Do it in a calibrated color space. That allows us to basically create an intermediary color that can be translated. You draw to a calibrated color space, we can then create this intermediary color, and then when it comes time to print, we can take that intermediary color, and with the help of the printer using their profile, we can create the color that matches.
So basically, we're asking you to draw with calibrated color. For any Windows developers out there, you're probably drawing in sRGB already. That's the default Windows color space that you draw in. You may not even know it, because Windows doesn't require you to declare a color space. On Mac OS X, we do require that you declare a color space, and you're already drawing in sRGB. We're just asking that you declare it as sRGB, and not generic RGB. That way, you have your drawing code already, it's already in sRGB. Just declare it as sRGB, and that will create the device-invented color that we need.
So this is what happens when, a little full chart of what happens with the color management on the system. Your app generates color, your app generates the color for printing in one or more calibrated color spaces. One or more is basically, say on a page you have, or a document you have, three different images from three different cameras. You're going to have, probably having two or three different images, the images are going to be tagged with three different profiles on how that image was captured.
Then we, printing system, will create the spool file. If you've drawn in your calibrated color spaces, you're done. The application, the printing system takes care of the rest and draws it. And then with the help of the drivers, we get the color sync profile from the driver, from the printer, and we render into the actual device color space.
Drawing with fidelity. This is basically resolution and bit depth of your images. We're asking that you don't assume the destination printer characteristics. Don't assume that you're always going to be printing to that black and white laser printer. Don't assume that you're going to be printing to a little label printer.
The user may be printing it out to a PDF, and we don't want to lose the data that is present in the image. Draw up full resolution. Don't downsample. Don't ruin the data that is already there. The printing path handles the full 16-bit per color data path. So what happens, Safari, let's say Safari encounters one of these deep images, which are becoming more and more prevalent because of the, you know, aperture and the raw and the, you know, using all the raw formats of pictures, we are getting a lot more of these deep data images.
And so basically, Safari will encounter one of these images, and it will pass it through the printing system. When it gets out to paper, you will get that full high-quality resolution for that image. And also you can see, on some of the pro-sumer printers that are now shipping, you can see the difference between the deep data pixels that are out there.
So how do you maintain the image quality? Basically you use Quartz. Quartz preserves all the quality. CG image source, image curate, context image, context draw image. They all preserve the quality. NS image preserves the quality as well. During printing, they will pass the full resolution image. There's one caveat with NS image, is basically if you're going to modify the image, by basically locking focus on the image, at that point, the image is going to be down-sampled to basically the resolution of the backing store for that window.
So basically, if you're not going to modify the image, you're fine. If you're locking focus on the image, then you have to beware. Then the image processing stuff, basically core image preserves the quality. If you're doing your own image processing, preserve the quality of the images that are going through.
Okay, so now we've learned basically all the Cocoa ways of printing, you know, everything you need from the creating, customizing the dialogue, printing out the paper, maintaining image quality. For 95% of you, you're done. That's all you need to know. But for the other 5%, there are a few cases where we need to dive into core printing. So that's a little blue box that the Cocoa printing is based on.
Core printing is an application framework. It resides in application services framework. It's a residual C interface that provides no user interface. That's what Cocoa does. Cocoa provides the user interface. The core printing provides some of the lower-level functionality. It provides the basic opaque types. They kind of look familiar, don't they, with the NS printer and stuff like that. We have the PM printer, page format, paper, which basically defines the paper and the margins of such, the print settings, which is the settings for the print dialog and such, and we have the print session, which encapsulates the settings and the format.
It's available to all applications, but is rarely needed by a Cocoa application. There I said, it's that little 5%. What would you use it for? Not much for most applications. You can change arbitrary print settings like a job title, or as I said before, you always want to print 10 copies. So, you'd say, you know, PM set copies.
PM print settings set copies. If you want to set the page size programmatically, and lastly is basically the direct submission of PDF or PostScript. If you're dealing with a PDF as your document format, why re-render it? just do a direct submission of that PDF to the printing system.
As I said, it was available in Leopard and later. There's a few things you need to know about how to use it. The NS Print Info contains a session, a page format, and the print settings. So basically, if in NS Print Info, you can call these methods to get these low-level objects. One thing we ask is once you've modified those objects, you need to let the NS Print Info know that you've changed those objects. So we're going to go and sync back.
It will basically re-sync the information that has in the NMS Print Info with the settings that are down in the PM Print settings that you changed. So basically you'd call update from PM page format or update PM Print settings, which allows a sync to happen. And we have examples for you on your DVD. As Howard alluded to, there are a few header file changes.
One of them is PM Print Settings Key replaces PM Ticket. So if you have a include print core/pmticket.h, we're asking that you will need to replace that with the PM Print Settings Keys. That's how it says you cannot build Tioga components. New development of the Tioga drivers should be used, should be done using CUPS filters and backends. Cannot build the old style Carbon print dialog plugins. New development should be Cocoa Print Dialog plugins for drivers and the Anis Accessory View Controller for Cocoa apps. As Howard said before, well-written components will still run on Snow Leopard.
Then we had to move some files around, some of our headers around. On Leopard, PDE plugin interface and pnprintdialoguextensions.h resided in the print framework, which was under the Carbon framework. They really weren't needed to be at that high of a level inside the Carbon framework. As a Cocoa app, you should not need to be bringing in Carbon. So we moved them. Those files are now in the application services framework under the print core framework. So basically we have conditionally, we have show examples of how to conditionally compile this.
Basically replace print in your include file with print core. So it's very easy to do. As I said, we have examples for you. So now we're done with the printing system. From the user perspective, let's have Michael come up here and talk about where the real work gets done.
Thank you, Alan. As he said, my name's Mike Sweet. I'm the person that created CUPS in the first place, and I'm going to talk to you a little bit about what we have in Snow Leopard and what the whole thing is. So, about 10 years ago, I came into the need of creating this printing system to support our customers at the time, and it's kind of taken off since then.
You find all of the major Linux distributions, it's available on all the BSDs and the commercial Unixes, and of course Mac OS X are using CUPS as a standard printing system. If you go onto the CUPS webpage, you go on CUPS.org, you'll see a lot of compatible add-ons and the developer and user communities that you can use when you're developing printing that needs to access something in CUPS.
Now, CUPS first showed up in Mac OS X in Jaguar, that's the 10.2, and we went on for about five years doing a licensing deal, and then last year, Apple actually purchased CUPS. And, you know, it was a little bit of an uproar when the news hit the net, but things have been actually working out pretty well.
We still have the same license agreement, still the same website, and still the same group of people developing the software, just we're developing it on the West Coast instead of the East Coast. And it's kind of interesting, we've actually had more releases in the last year than we had in all the previous years as an average.
Now, as I said, in Jaguar, we first introduced CUPS. And that brought, in addition to the CUPS architecture, it brought printer sharing that was missing from previous releases. Panther added Bonjour-based printing and printer sharing, and that was the first time that Bonjour really got a lot of exposure that way. Tiger added per-printer sharing, so you can actually share individual printers, but not all printers. It was very much requested. And as you notice, all of the previous Mac OS X releases were all based on CUPS 1.1.
In Leopard, we actually bumped up to CUPS 1.3, and that got us a lot of interesting stuff. Kerberos, IPv6 support, the full support for deep color printer drivers, and some enhancements to the security model that was available. And then Snow Leopard and the seed that you've got has a lot of new features for security, but also incorporates some of the other components that have previously been separately provided.
Howard showed you the user interface for the access control list and the sharing preference pane. There's some stuff with sandboxing that we're doing for enhanced security. I'll talk about that a little later. And then the driver development kit, which gives you additional printer drivers out of the box, and a lot of tools for driver development.
Now, I did a little retrospective, if you will, of what it's been like for the last year at Apple, and I noticed something interesting. On the CUPS website, we have this bug database, and we get a lot of contributions from the community, but I wasn't sure what that actually was like. And when I looked at it, it turned out that three-quarters of all the contributions and bug fixes to the software actually came from the open-source community.
We have all the Linux vendors, the people at Sun with their open Solaris, are contributing fixes and improvements to CUPS all the time. And so, you know, last year alone, we've only had a quarter of those contributions coming from Apple internally. So it's been really exciting to see that the project continues to go on very strong, both internally and outside of the company.
So I'm going to talk a little bit about how CUPS works and give you a little peek into what actually happens after you hit the Print button. So CUPS is based around this central server called the scheduler, and it basically manages all the printers and jobs that are in the system.
If you look in the activity monitor, you'll see the CUPSd process running, usually. It's something that's run on demand by LaunchD, so if you don't have any print jobs going and you're not sharing any printers, you're not actually going to see that process there. But as soon as you hit that print button in the application, it'll get fired up.
And it's a very lightweight process. It just does a few simple things, and then anything more complicated, like printing a file to the printer, actually gets farmed out to other helper applications so that it doesn't have to manage a lot of internal state and use up a lot of memory. Because it deals with a lot of security-related things and secure ports, it has to run as root.
So we have to do a lot of stuff internally to make sure that we don't expose the system. So we have to do a lot of stuff internally to make sure that we don't expose the system. But whenever we run the helper programs, we run them with another account called LP, which doesn't have all those system privileges. When we're actually talking to the scheduler from your application, you go down through the stack.
The CUPS API talks to the scheduler using IPP messages. IPP is the Internet Printing Protocol. And that's layered over top of HTTP, which is the same thing that your web browser uses. So I have to do a lot of stuff internally to make sure that I'm not getting a lot of data. So anytime the application needs to send a print job or get the information about a printer, it's talking over those protocols through the CUPS API. I have a little slide here to show that.
CUPS API sits at the bottom of all the print APIs. And you'll notice that the scheduler uses the same CUPS API. The APIs are written so that they can be used both by client and server. And they're very lightweight, so we can talk very quickly and not use up a lot of resources just to get something done. and print it out.
Now, once you actually bring up the print dialog and you print, several things happen. One is the print frameworks will generate this PDF file from your application. Your application has done all its drawing and everything. We get this PDF file, hopefully with calibrated colors, and that will get fed into the printing system to actually get printed out on the printer. You'll notice here we have a PDF file, but there's also this other file out there, this PPD. It's a PostScript Printer Description File.
That used to be just for PostScript printers. In CUPS, it's also used for non-PostScript printers, and it describes what the printer can do, what features it has, what drivers to use, and so forth. So CUPSD, the scheduler, is going to take that file and take the PPD file that describes the printer and figure out what programs to run to get the job to print.
So we start off with a series of what we call filter programs. Depending on the job, there may be a pre-filter that's applied by the driver manufacturer to actually convert or examine the print data before it goes into the rest of the print filters. And Apple provides several standard print filters for going, say, from PDF to PostScript or PDF to Raster. And then that all goes into the printer driver, which is typically provided by the printer manufacturer.
It will take that, create printer-ready data, And then we have an optional component called a port monitor that handles any protocol level conversion. So you may need to take the data from just a raw binary format and put it inside these frame packets to go out to the printer. That's where you would handle that.
And finally, there's a program called the back-end, which actually communicates with the device, and it takes all the print data that the port monitor, the printer driver, has supplied and feeds it out to the printer. Now, of course, the printer often has something to say about that, so any status information comes back over a back channel, which those programs can read.
And starting in Leopard, we added a side channel interface so that you can actually have the driver communicate with the back end. It's typically used to find out what the capabilities of that interface are. Does it support bidirectional data transfers? What's the 1284 device ID? Other information about the printer.
Now, as I mentioned before, a lot of the stuff comes from us. The PDF file we create, the standard filters we provide, the port monitors typically we provide for PostScript printers at least, and all of the standard backends for USB and network printing. And when you got your printer from the manufacturer, obviously they provided the printer, they provided all the driver components, which means the PPD file, the driver filter, any pre-filters, and color profiles, icons, all the things that go along with the printer driver.
Now, as all these programs are running, they're feeding status information back to the scheduler to say what it's doing. All those messages go across to standard error, so they're just plain text messages. And, you know, basically, it'll be things like printing page one, printing page two, out of cyan ink, any sort of status information. Also handles things like page accounting.
Howard Miller, Mike Sweet So, as I mentioned before, we like to run these programs as an unprivileged user, the user LP. But the backends, in some cases, have to run as root to access security information, to use privileged ports or interfaces. So you'll see sometimes the backends are run as LP and sometimes as root. We like it when backends can run as LP.
[Transcript missing]
So, you've got this seed of Snow Leopard, and it's got a new version of CUPS in it. We've done a lot of tuning in that new version of CUPS, but there's also some security improvements, and as driver developers, you need to be aware of those things. I'm going to talk about that in a little bit.
The driver development kit, which used to be a separate download on CUPS.org, is now a standard part of CUPS. So, if you're developing add-ons for those sorts of drivers, or you're developing drivers, those tools will be available on every Snow Leopard system. The CUPS test PPD command, which we've asked every driver vendor to use, because we use it internally when we're testing the drivers you send us, that's been improved again, and we'll continue to improve it as we go on to add features to it.
In order to better support printer utilities and supply-level monitoring, we have a new interface. It's actually an old interface from CUPS that's just being adopted in Snow Leopard. We added the operation to support the job preview in the printer proxy. It allows us to securely allow any user that submitted a job or an administrator to actually view the contents of a job. And finally, we always update the web interface. It's been updated again. And even better, we've added a new interface to the printer. better online documentation.
So, on the security front, last WWDC, if you were here, we introduced something for Leopard called Seatbelt. It's now just officially known as Sandbox, and it basically allows us to control what a program can do. So, we looked at that, and we said, we want to use this at some level in CUPS to further secure the printing system.
So, what you'll see in Snow Leopard is we've used it to limit your write access to the file system and the read access to the print job files. From the standpoint of a printer driver, it means that you can no longer write files to library printers, or to user home directories, for that matter.
And for the print job filters themselves, they can only access the files that are associated with the job you're printing. So, previously, if you were to install a malicious piece of printer driver software, it could actually collect all of the spool files on your system and then email them to somebody or, you know, send it somehow, so that that potentially confidential information would be exposed. So, this new security improvement prevents that from happening.
Now, the CUPS DDK, if you're not familiar with it, it's the driver development kit for CUPS. It includes several components. One of them is a PPD compiler for creating PPD files for your printer drivers. That's been improved. You can now localize with strings files, which are the standard for Mac OS X. We've added support for conditional directives, long file names, and a test mode.
Howard Miller, Mike Sweet And then we've added in all of the drivers from there so that they can be used in a standard Mac install. If you provide driver information files, which are the files that the PPD compiler consumes, you can actually install them in library printers, ppds.drv, and the printing system will be able to use them. Howard Miller, Mike Sweet
[Transcript missing]
"It gets out to the printer, the printer can feed back the information that you need, and then you can feed that back up to your utility.
So instead of talking directly to the device, you just talk through CUPS." The web interface here, just a quick little blurb, the online help is the most common page to use. Fully searchable, has additional information for driver development and application development if you need to go to the CUPS level.
And for additional information, we've got some links here. If you have bugs that you find, report them, please. Please report them. Bugreport.apple.com. The developer website has a page on printing. There is a mailing list for printing. There's also CUPS mailing list, CUPS website that have resources there, so please do use those.
If you have any questions for this, Mr. Paul Danbold is our technology evangelist for this. And for developing your user interfaces, we do have the human interface guidelines that you can use. And finally, a reminder, later this afternoon we have image capture. And we'll see you all in a few minutes down in the printing lab.