Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate scaled image from off-screen NSView

I have a sequence of off screen NSViews in a Cocoa application, which are used to compose a PDF for printing. The views are not in an NSWindow, or visible in any way.

I'd like to be able to generate thumbnail images of that view, exactly as the PDF would look, but scaled down to fit a certain pixel size (constrained to a width or height). This needs to be as fast as possible, so I'd like to avoid rendering to PDF, then converting to raster and scaling - I'd like to go direct to the raster.

At the moment I'm doing:

NSBitmapImageRep *bitmapImageRep = [pageView bitmapImageRepForCachingDisplayInRect:pageView.bounds];
[pageView cacheDisplayInRect:pageView.bounds toBitmapImageRep:bitmapImageRep];
NSImage *image = [[NSImage alloc] initWithSize:bitmapImageRep.size];
[image addRepresentation:bitmapImageRep];

This approach is working well, but I can't work out how to apply a scaling to the NSView before rendering the bitmapImageRep. I want to avoid using scaleUnitSquareToSize, because as I understand it, that only changes the bounds, not the frame of the NSView.

Any suggestions on the best way of doing this?

like image 494
tomtaylor Avatar asked Jul 07 '12 17:07

tomtaylor


1 Answers

This is what I ended up doing, which works perfectly. We draw directly into an NSBitmapImageRep, but scale the context explicitly using CGContextScaleCTM beforehand. graphicsContext.graphicsPort gives you the handle on the CGContextRef for the NSGraphicsContext.

NSView *pageView = [self viewForPageIndex:pageIndex];

float scale = width / pageView.bounds.size.width;
float height = scale * pageView.bounds.size.height;

NSRect targetRect = NSMakeRect(0.0, 0.0, width, height);
NSBitmapImageRep *bitmapRep;

bitmapRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
                                                    pixelsWide:targetRect.size.width
                                                    pixelsHigh:targetRect.size.height
                                                 bitsPerSample:8
                                               samplesPerPixel:4
                                                      hasAlpha:YES
                                                      isPlanar:NO
                                                colorSpaceName:NSCalibratedRGBColorSpace
                                                  bitmapFormat:0
                                                   bytesPerRow:(4 * targetRect.size.width)
                                                  bitsPerPixel:32];

[NSGraphicsContext saveGraphicsState];

NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmapRep];
[NSGraphicsContext setCurrentContext:graphicsContext];
CGContextScaleCTM(graphicsContext.graphicsPort, scale, scale);

[pageView displayRectIgnoringOpacity:pageView.bounds inContext:graphicsContext];

[NSGraphicsContext restoreGraphicsState];

NSImage *image = [[NSImage alloc] initWithSize:bitmapRep.size];
[image addRepresentation:bitmapRep];

return image;
like image 116
tomtaylor Avatar answered Nov 02 '22 16:11

tomtaylor