Skip to content

May 18, 2010

How to Print a PDF File Using Cocoa

by Dan

UPDATE 2014-03-13: @robwithhair created a command-line tool for printing PDF files based on this code which shows some additional options.

Mac OS X is well known for its great support for PDF files. You can create a PDF file from anything you can print. I thought that using Apple’s PDFKit framework would make it easy to program a way to print an existing PDF file. That turned out not to be the case.

Sending a file to a printer using the lp command is easy. However, this approach does not work for PDF files formatted for landscape printing. You can specify landscape orientation, but I wanted a way to detect the orientation automatically.

PDFKit has a PDFView object that has a printWithInfo:autoRotate: method. However, adding a PDFDocument to a PDFView and telling it to print doesn’t work. I eventually stumbled onto the fact that PDFDocumenthas a secret method that makes printing easy. So here is the code:

#import <Quartz/Quartz.h>

- (void)printPDF:(NSURL *)fileURL {

    // Create the print settings.
    NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo];
    [printInfo setTopMargin:0.0];
    [printInfo setBottomMargin:0.0];
    [printInfo setLeftMargin:0.0];
    [printInfo setRightMargin:0.0];
    [printInfo setHorizontalPagination:NSFitPagination];
    [printInfo setVerticalPagination:NSFitPagination];

    // Create the document reference.
    PDFDocument *pdfDocument = [[[PDFDocument alloc] initWithURL:fileURL] autorelease];

    // Invoke private method.
    // NOTE: Use NSInvocation because one argument is a BOOL type. Alternately, you could declare the method in a category and just call it.
    BOOL autoRotate = YES;
    NSMethodSignature *signature = [PDFDocument instanceMethodSignatureForSelector:@selector(getPrintOperationForPrintInfo:autoRotate:)];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setSelector:@selector(getPrintOperationForPrintInfo:autoRotate:)];
    [invocation setArgument:&printInfo atIndex:2];
    [invocation setArgument:&autoRotate atIndex:3];
    [invocation invokeWithTarget:pdfDocument];

    // Grab the returned print operation.
    NSPrintOperation *op = nil;
    [invocation getReturnValue:&op];

    // Run the print operation without showing any dialogs.
    [op setShowsPrintPanel:NO];
    [op setShowsProgressPanel:NO];
    [op runOperation];
}

I consider this code to be in the public domain. Please feel free to copy and paste. And let me know if you find any problems or have suggestions.

Comments are closed.