6
votes

I have an NSView that contains an NSScrollView containing a CALayer-backed NSView. I've tried all the usual methods of capturing an NSView into an NSImage (using -dataWithPDFInsideRect, NSBitmapImageRep's -initWithFocusedViewRect, etc.) However, all these methods treat the CALayer-backed NSView as if it doesn't exist. I've already seen this StackOverflow post, but it was a question about rendering just a CALayer tree to an image, not an NSView containing both regular NSView's and layer-backed views.

Any help is appreciated, thanks :)

4

4 Answers

6
votes

The only way I found to do this is to use the CGWindow API's, something like:

CGImageRef cgimg = CGWindowListCreateImage(CGRectZero, kCGWindowListOptionIncludingWindow, [theWindow windowNumber], kCGWindowImageDefault);

then clip out the part of that CGImage that corresponds to your view with

-imageByCroppingToRect.

Then make a NSImage from the cropped CGImage. Be aware this won't work well if parts of that window are offscreen.

2
votes

This works to draw a view directly to an NSImage, though I haven't tried it with a layer-backed view:

NSImage * i = [[NSImage alloc] initWithSize:[view frame].size];
[i lockFocus];
if ([view lockFocusIfCanDrawInContext:[NSGraphicsContext currentContext]]) {
  [view displayRectIgnoringOpacity:[view frame] inContext:[NSGraphicsContext currentContext]];
  [view unlockFocus];
}
[i unlockFocus];

NSData * d = [i TIFFRepresentation];
[d writeToFile:@"/path/to/my/test.tiff" atomically:YES];
[i release];
0
votes

Have you looked at the suggestions in the Cocoa Drawing Guide? ("Creating a Bitmap")

To draw directly into a bitmap, create a new NSBitmapImageRep object with the parameters you want and use the graphicsContextWithBitmapImageRep: method of NSGraphicsContext to create a drawing context. Make the new context the current context and draw. This technique is available only in Mac OS X v10.4 and later. Alternatively, you can create an NSImage object (or an offscreen window), draw into it, and then capture the image contents. This technique is supported in all versions of Mac OS X.

That sounds similar to the iOS solution I'm familiar with (using UIGraphicsBeginImageContext and UIGraphicsGetImageFromCurrentImageContext) so I'd expect it to work for your view.

0
votes

Please have a look at the answer on this post: How do I render a view which contains Core Animation layers to a bitmap?

That approach worked for me under similar circumstances to your own.