如何将包含Core Animation图层的视图渲染到位图?

时间:2009-12-30 03:50:35

标签: objective-c cocoa core-animation bitmap rendering

我使用NSView来托管多个Core Animation CALayer对象。我想要做的是抓取视图当前状态的快照作为位图图像。

使用类似这样的正常NSView相对简单:

void ClearBitmapImageRep(NSBitmapImageRep* bitmap) {
    unsigned char* bitmapData = [bitmap bitmapData];
    if (bitmapData != NULL)
        bzero(bitmapData, [bitmap bytesPerRow] * [bitmap pixelsHigh]);
}

@implementation NSView (Additions)
- (NSBitmapImageRep*)bitmapImageRepInRect:(NSRect)rect
{
    NSBitmapImageRep* imageRep = [self bitmapImageRepForCachingDisplayInRect:rect];
    ClearBitmapImageRep(imageRep);
    [self cacheDisplayInRect:rect toBitmapImageRep:imageRep];
    return imageRep;
}
@end

但是,当我使用此代码时,不会渲染Core Animation图层。

我调查了CARenderer,因为它似乎做了我需要的事情,但是我无法让它渲染我现有的图层树。我尝试了以下方法:

NSOpenGLPixelFormatAttribute att[] = 
{
    NSOpenGLPFAWindow,
    NSOpenGLPFADoubleBuffer,
    NSOpenGLPFAColorSize, 24,
    NSOpenGLPFAAlphaSize, 8,
    NSOpenGLPFADepthSize, 24,
    NSOpenGLPFANoRecovery,
    NSOpenGLPFAAccelerated,
    0
};

NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:att];
NSOpenGLView* openGLView = [[NSOpenGLView alloc] initWithFrame:[self frame] pixelFormat:pixelFormat];
NSOpenGLContext* oglctx = [openGLView openGLContext];

CARenderer* renderer = [CARenderer rendererWithCGLContext:[oglctx CGLContextObj] options:nil];
renderer.layer = myContentLayer;
[renderer render];
NSBitmapImageRep* bitmap = [oglView bitmapImageRepInRect:[oglView bounds]];

然而,当我这样做时,我得到一个例外:

CAContextInvalidLayer -- layer <CALayer: 0x1092ea0> is already attached to a context

我猜这一定是因为图层树托管在我的NSView中,因此附加到其上下文中。我不明白如何从NSView分离层树以便将其渲染为位图,在这种情况下创建重复的层树非常重要。

还有其他方法可以让CALayer呈现给位图吗?我无法在任何地方找到任何示例代码,事实上我根本找不到CARenderer的任何示例代码。

2 个答案:

答案 0 :(得分:15)

关于录制核心动画,有一篇关于“可可是我女朋友”的文章。作者将整个动画捕捉到一部电影中,但你可以使用他抓住一个画面的部分 跳转到本文中的“获取当前帧”部分:
http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/

基本理念是:

  • 创建CGContext
  • 使用CALayer's renderInContext:
  • 从中创建NSBitmapImageRep 上下文(使用 CGBitmapContextCreateImage和 NSBitmapImageRep的initWithCGImage)

<强>更新
我刚才读到,renderInContext:方法不支持Mac OS X 10.5中的所有类型的图层。 它不适用于以下图层类:

  • QCCompositionLayer
  • CAOpenGLLayer
  • QTMovieLayer

答案 1 :(得分:4)

如果您需要有关如何将CALayer层次结构呈现给NSImage(或iPhone的UIImage)的示例代码,您可以查看Core Plot框架的CPLayer及其-imageOfLayer method。我们实际上创建了一个独立于CALayer使用的正常-renderInContext:进程的渲染路径,因为在生成图层的PDF表示时,常规方法不会保留向量元素。这就是为什么你会在这段代码中看到-recursivelyRenderInContext:方法。

但是,如果您尝试从weichsel(QCCompositionLayer,CAOpenGLLayer或QTMovieLayer)提到的任何图层类型中捕获,这将无法帮助您。