The AppKit Printing API

The AppKit framework publishes the programmatic interface that supports printing in your app. The API includes five classes and one formal protocol. Objects of these classes and the delegate implementing the protocol have the runtime relationships shown in Figure 2-1.

Figure 2-1  The classes and protocol in the AppKit printing API

These classes are in a layer above Core Printing, which is a C API used to create command-line tools or to perform printing tasks that don’t display a user interface. The NSPrintInfo class provides direct access to Core Printing functionality. In Cocoa apps, Core Printing can be used to extend the functionality of the AppKit printing classes. However most apps shouldn’t need to use the Core Printing API, so it is not discussed further in this document. If you want to find out more about Core Printing, see the sample code project Cocoa Printing using Core Printing and the technical note Using Cocoa and Core Printing Together.

Overview of the Printing Classes and Protocol

Objects of the AppKit printing classes have specific roles and responsibilities.

NSPrintOperation Manages a Print Job

An NSPrintOperation object is central to printing; without it, your app can’t print. It displays the Print panel, optionally spawns a new thread to process the print job, sets up the print environment, and tells the NSView to print itself, and hands off the resulting content to the CUPS layer of the system. It can also generate Portable Document Format (PDF) data instead of sending the results to a printer.

NSPrintOperation works together with two other objects: an NSPrintInfo object, which specifies how the code should be generated, and an NSView object, which performs the actual code generation. You must specify a view when you create an NSPrintOperation object. You can optionally specify an NSPrintInfo object.

NSPrintInfo Stores Options That Control How a Print Job is Performed

Print information includes the paper size, number of copies, print margins, whether to use a header and footer, and so on. The printing system automatically creates a shared NSPrintInfo object that holds defaults settings used by other objects of the printing system.

Normally you don’t set NSPrintInfo attributes directly—this is done by instances of NSPageLayout and NSPrintPanel. The NSView that generates the printing content might also supersede some NSPrintInfo settings, such as the pagination and orientation attributes.

Your app should not create an NSPrintInfo object unless it needs to modify the default settings or save and restore custom settings. See Managing Print Information Objects.

NSPrintPanel Creates and Displays the Print Panel

This class manages the standard system Print panel. Your app does not need to create an NSPrintPanel object unless you want to manage the printing workflow yourself or add custom print settings for your app (using an accessory view). If you create an instance of NSPrintPanel you need to display it and subsequently initiate the desired printing behavior.

If you add an accessory view to the Print panel to display app-specific options, you must adopt the NSPrintPanelAccessorizing protocol. See Managing and Extending the Print Panel.

The NSPrintPanelAccessorizing Protocol Manages a Custom Accessory View

The NSPrintPanelAccessorizing protocol declares two methods that the NSPrintPanel class uses to get information from a printing accessory controller. You are required to implement the localizedSummaryItems method, which returns an array of dictionaries that contain the localized summary strings for the setting in your accessory view. It is optional for you to implement keyPathsForValuesAffectingPreview.

See Managing and Extending the Print Panel.

NSPageLayout Displays the Page Setup Panel

This class manages the standard system Page Setup panel. Your app does not need to create an NSPageLayout object unless you want to manage the printing workflow yourself. If your app really needs to mange the Page Setup panel, it must display the Page Setup panel and subsequently initiate the desired printing behavior.

It is not typical for apps to create NSPageLayout objects. See Managing Page Layout Objects.

NSView Draws the Content Your App Prints

As with screen-based drawing, the NSView class provides the underlying canvas for drawing printed content. If you have an app that already uses views to draw in your app’s windows—which most Cocoa apps do—then you already have the basic code you need to draw printed content. By default, the printing workflows handle printing by taking the same views embedded in your windows and simply redirecting the output to a different destination.

In addition to drawing your custom content, the NSView class has methods for:

  • Drawing header and footer content

  • Paginating content

  • Specifying alignment marks or virtual sheet borders on each logical page

  • Specifying drawing crop marks or fold lines on each printed sheet

For more information on drawing content to NSView objects, see Cocoa Drawing Guide.

If your app supports printing text, you also need to be familiar with using the Cocoa Text System (see Cocoa Text Architecture Guide). If you want to control text layout on the page, you need to use the NSLayoutManager class (see Text Layout Programming Guide).

Basic Printing Workflow

In a Cocoa app, printing is generally initiated by the user choosing the Print menu command, which usually sends either a print: or printDocument: message up the responder chain. Which message is sent depends on whether or not the app is document-based. The app receives the message either in a custom NSView object (if it has the keyboard focus), a window delegate, or an NSDocument object.

After receiving the message to print, the general workflow is as follows:

  1. Create an NSPrintOperation object to manage the print job, providing the view that contains the content to print.

  2. (Optional) Add an accessory view to the job’s print panel.

  3. Run the print operation.

  4. (Optional) For a multipage job, override how the view is divided between multiple pages by using the methods of the NSView class.

The view’s drawRect: method draws the view’s contents.

Implementing printing in your app can be as easy as writing these few lines of code:

- (IBAction)print:(id)sender {
      NSPrintOperation *op;
      op = [NSPrintOperation printOperationWithView:self];
      if (op)
           [op runOperation];
      else
          // handle error here
}

OS X printing also provides support for custom formatting and layout. When you add those tasks, the workflow is a bit more complex, but straightforward. See Printing From Your App and Laying Out Page Content.