Question

I'm trying to print a document. The document is an array of NSImageReps, or a single NSPDFImageRep, which has multiple pages. I'm having trouble figuring out how to use the NSPrintOperation class to print this.

The NSPrintOperation seems to need an NSView to print. Do I need to manually add each image into the view at a calculated position and then let it do the pagination? that seems like it isn't in the spirit of Cocoa... is there some technique that I'm missing?

Was it helpful?

Solution 4

For Future reference, I believe the answer is PDFViews. you can add a PDFPage all at once to a PDFView (Via a PDFDocument) and then you can print with printWithInfo:autoRotate:

In theory at least, I have gotten the view created, and the print dialog comes up, but when I hit "print" the dialog doesn't disappear...

But that's a different question.

OTHER TIPS

Despite this having an accepted answer, it doesn't really answer the basic question, just gives a work-around.

I just had a similar problem (I have an array of objects each rendered by the same NSView subclass, one per page). Here's how I solved it, without the baroque nonsense of creating one giant view that holds all the pages...

1) We have an NSView subclass that has a model associated with it (NSImage in your case, ModelData in my case)

class BaseView: NSView {
    var modelData: ModelData /* Whatever your view needs to draw */
    //...
}

2) We have an array var models: [ModelData] in your document controller.

3) Create a new subclass that will be the printer view.

class PrinterView: BaseView {
    var pageIndex: Int = 1
    var modelArray: [ModelData]

    init(frame: NSRect, models: [ModelData]) {
        self.modelArray = models
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        fatalError("invalid initializer")
    }

    override func knowsPageRange(_ range: NSRangePointer) -> Bool {
        range.pointee.location = 1
        range.pointee.length = self.modelArray.count
        return true
    }

    override func rectForPage(_ page: Int) -> NSRect {
        self.pageIndex = page
        return self.bounds
    }

    override func draw(_ dirtyRect: NSRect) {
        self.model = self.modelArray[self.page - 1] // Pages are 1, not 0, based
        super.draw(dirtyRect)
    }
} // That's it! That's all...

4) Do this in your document controller:

override func printOperation(withSettings printSettings: [String : Any]) throws -> NSPrintOperation {
    self.printInfo.horizontalPagination = .fitPagination
    self.printInfo.verticalPagination = .clipPagination
    let printView = PrinterView(size: self.printInfo.paperSize, models: self.models)

    return NSPrintOperation(view: printView, printInfo: self.printInfo)
}

You can't print something that can't be drawn. NSView is how you draw what you want to print. You can make an NSView subclass just for printing that decides how you want the printing to work (e.g. do you want one NSImageRep for page — ANY size page?) by using NSView's pagination methods. Just override knowsPageRange: to return YES.

You can create view that that displays what you want to print. Then you use it to create print operation.

You would typically created a view that displays your image. You implement an algorithm to figure out what image you want to display on which page. Then you return number of pages available to print and implement method to print specific page.

  • If you have 10 images and you want to print one per page that's easy.
  • If you want to print records per page and you have 100 records then you calculate how many records you can fit on a page (using current font size and number of lines per record).
  • Then you figure out from records per page how many pages you need to display all records - this is your number of pages (range of pages).
  • When requested to print specific range of pages you select the records that should be show on given page and display them.
  • See references below on how to implement these steps. See the custom pagination info for example how to implement these steps, it's not difficult.

See Print Programming Topics, or the full example I reference bellow from the book has pagination which I did not included here. Have a look at the custom pagination for more hints.

If you have Document Based application and a view that you want to dump to printer, then in our MyDocument (or whatever you call it) that extends NSDocument you would implement:

- (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)ps
                                           error:(NSError **)e

The view then uses standard drawRect: for drawing.

Example, here PeopleView just draws a table of people details, it takes a NSDictonary of people employees here:

- (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)ps
                                           error:(NSError **)e
{
    PeopleView * view = [[PeopleView alloc] initWithPeople:employees];
    NSPrintInfo * printInfo = [self printInfo];
    NSPrintOperation * printOp
        = [NSPrintOperation printOperationWithView:view
                                         printInfo:printInfo];
    [view release];
    return printOp;
}

You can look for more details in chapter 27, Printing, in Hillegass' Cocoa Programming For Mac OS X.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top