views:

294

answers:

2

I'm migrating Cocoa-Java code to Cocoa + JNI since Cocoa-Java is deprecated. The code prints an image stored in a file. The new Cocoa code is basically:

NSImage *image = [[NSImage alloc] initWithContentsOfFile:spoolFile];
if ( [image isValid] ) {
    NSImageView *view = [[NSImageView alloc] init];
    [view setImage:image];
    [view setImageScaling:NSScaleProportionally];

    NSPoint p;
    NSSize s;

    p.x = static_cast<float>( boundsX );
    p.y = static_cast<float>( boundsY );
    [view setBoundsOrigin:p];

    s.width  = static_cast<float>( boundsWidth );
    s.height = static_cast<float>( boundsHeight );
    [view setBoundsSize:s];

    NSPrintInfo *info = [NSPrintInfo sharedPrintInfo];
    [info setHorizontalPagination:NSClipPagination];
    [info setVerticalPagination:NSClipPagination];
    [info setHorizontallyCentered:NO];
    [info setVerticallyCentered:NO];

    p.x = static_cast<float>( boundsX );
    p.y = static_cast<float>( [info paperSize].height - boundsHeight - boundsY );
    [view translateOriginToPoint:p];

    NSPrintOperation *printOp =
        [NSPrintOperation printOperationWithView:view printInfo:info];
    [printOp setShowsPrintPanel:NO];
    [printOp runOperation];
}

Running this code eventually crashes with:

Thread 0 Crashed:
0   com.apple.AppKit   0x9484ac75 -[NSConcretePrintOperation(NSInternal) _tryToSetCurrentPageNumber:] + 345
1   com.apple.AppKit   0x948d88cf -[NSView(NSPrintingInternal) _printForCurrentOperation] + 524
2   com.apple.AppKit   0x948d85c5 -[NSConcretePrintOperation _renderView] + 358
3   com.apple.AppKit   0x9491f0c0 -[NSConcretePrintOperation runOperation] + 362

Why? How can I simply print an image that's stored in a file?

A: 

Is that a typo the second time you assign to p.y? It doesn't look like you define info until 2 lines later...

Also, wouldn't it be simpler to use NSMakePoint() and NSMakeSize() by passing ints, instead of constructing them by hand and using static_cast<float>? That seems like a very C++ approach...

For example, something like this could work?

NSImage *image = [[NSImage alloc] initWithContentsOfFile:spoolFile];
if ([image isValid]) {
    NSPrintInfo *info = [NSPrintInfo sharedPrintInfo];
    [info setHorizontalPagination:NSClipPagination];
    [info setVerticalPagination:NSClipPagination];
    [info setHorizontallyCentered:NO];
    [info setVerticallyCentered:NO];

    NSImageView *view = [[NSImageView alloc] init];
    [view setImage:image];
    [view setImageScaling:NSScaleProportionally];
    [view setBoundsOrigin:NSMakePoint(boundsX, boundsY)];
    [view setBoundsSize:NSMakeSize(boundsWidth, boundsHeight)];
    [view translateOriginToPoint:NSMakePoint(boundsX, [info paperSize].height -
                                                      boundsHeight - boundsY)];

    NSPrintOperation *printOp = [NSPrintOperation printOperationWithView:view printInfo:info];
    [printOp setShowsPrintPanel:NO];
    [printOp runOperation];
}
Quinn Taylor
Yeah, bad copy/paste job -- fixed.
Paul J. Lucas
As for the NSMakePoint, NSMakeSize() -- yes, but that's not my problem.
Paul J. Lucas
+2  A: 
NSImageView *view = [[NSImageView alloc] init];

That's invalid. You need to use initWithFrame: to initialize a view. You'll probably want to pass a frame consisting of NSZeroPoint and the image's size.

As for the use of setBoundsOrigin: and setBoundsSize:: I'm not sure those will work, assuming you mean to crop the image. You can try them (after fixing the above problem), but I would feel safer to create a new image from the desired section of the old one. You would do this by creating an empty image of the desired size, locking focus on it, drawing the correct section of the old image at the origin in the new image, and unlocking focus on the new image, then giving the new image instead of the old to the image view.

Peter Hosey
I don't mean to crop the image. I want to print the entire image.
Paul J. Lucas
I changed it to initWithFrame. It doesn't crash now, but it launcher the printer app with no window and no document -- even if I click Preview. Any ideas?
Paul J. Lucas
There's no need to set the bounds if you want the entire image.
Peter Hosey
What do you mean by “it launche[s] the printer app with no window and no document”?
Peter Hosey
@Hosey: What's supposed to happen is that Preview should launch and display a PDF preview of the document (in this case, the image); what actually happens is that the printer application (e.g., if my printer has been configured as "HP 2700"), then an application having that name (you know, the app that shows the print queue for that printer) launches instead -- except nothing ever prints because there's no document generated.
Paul J. Lucas
In that case, you need to set the job disposition in the `info` object to indicate that to the printing system. You need to ask for a print-preview in order to get one; the default is to simply print.
Peter Hosey
@Hosey: but I don't know what should happen. What should happen is whatever the user tells it to happen. The user is presented with the Print dialog. If the user clicks Print, then it should print; if the user clicks Preview, then it should generate a preview. How do I get it to do whatever the user asked for?
Paul J. Lucas
If you want it to show the Print panel, why are you setting `showsPrintPanel` to `NO`?
Peter Hosey
The Print panel is shown by another part of the code. Remember, I'm porting old Cocoa-Java code and that's the way it was written. Another function displays the panel only; then the print function simply prints what was previous chosen by the previously displayed panel. Just for laughs, I changed it to "YES" and a correct PDF was generated. So it seems that some information is not being passed via the sharedPrintInfo.
Paul J. Lucas
I should also add that changing it to "YES" means that there are 2 print panels shown. Oddly, the second panel (the one as a result of the "YES" change) doesn't include a Preview button.
Paul J. Lucas
So the question remains: why isn't the PrintInfo's jobDisposition being correctly preserved?
Paul J. Lucas