I ran across a problem in the latest betas of Seasonality where the graphs would show up blank when printing. It took me awhile to fix this issue, so I thought I would post my solution here in the hopes that it might save someone else time in the future. Here’s a screenshot of print output before the fix:

The problem is that the Seasonality graphs are drawn using Core Graphics routines instead of the higher-level Quartz routines. I did this to squeeze a little more speed out of the drawing code, and also gained more customization with transparency settings and layered drawing. Basically, I grab a CGGraphicsRef using [[NSGraphicsContext currentContext] graphicsPort], and use it to draw all the other elements.

From what I could find online, it seemed that the problem was that while printing, the context isn’t referenced until later than it is when drawing it to screen, so the context doesn’t stick around long enough for the printing code to pick up on it and draw. So either I could find a way to retain the graphics context long enough for the printing to complete, or I could find a new way to draw my view for the printer. I didn’t want to retain a graphics context object because I think that makes the code a little messy, so I tried to find a new way to draw my view.

The first thing that came to mind was to not use all the Core Graphics routines to draw the graphs when printing. That would be a very large code change, and it’s a lot of extra code that isn’t used too frequently. The better solution I found was to draw everything to an NSImage first, and then draw the NSImage to the printer. Here’s some code…

- (void)drawRect:(NSRect)rect {
NSImage *lockedImage;
BOOL printing = ![NSGraphicsContext currentContextDrawingToScreen];
if (printing) {
lockedImage = [[NSImage alloc] initWithSize:rect.size];
[lockedImage lockFocus];
}

// Get our graphics context.
CGContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort];

// Drawing code here...

if (printing) {
[lockedImage unlockFocus];
[lockedImage drawInRect:rect
fromRect:NSMakeRect(0, 0, rect.size.width, rect.size.height)
operation:NSCompositeCopy
fraction:1.0];
[lockedImage release];
}
}

Here’s a screenshot of the output after the fix:

This solution has a small disadvantage, you don’t get the ability to print using the printer’s full resolution. Since Seasonality users don’t print too often, this tradeoff is okay, but it might be an issue to consider for other applications.