代码之家  ›  专栏  ›  技术社区  ›  Rob Keniger

如何将包含核心动画层的视图渲染为位图?

  •  10
  • Rob Keniger  · 技术社区  · 14 年前

    我正在使用 NSView 宿主多个核心动画 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
    

    但是,使用此代码时,不会渲染核心动画层。

    我已经调查过了 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 为了将其呈现为位图,在本例中创建一个重复的层树是非常重要的。

    有其他方法可以得到 卡莱尔 s要呈现为位图?我在任何地方都找不到这样做的任何示例代码,事实上,我找不到 卡伦德勒 完全。

    2 回复  |  直到 14 年前
        1
  •  15
  •   Thomas Zoechling    14 年前

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

    基本理念是:

    • 创建CGContext
    • 使用 CALayer's renderInContext:
    • 从创建nsbitmapImagerep 语境(使用) cgBitmapContextCreateImage和 nsbitmapimagerep的initwithcgimage)

    更新:
    我刚读到 渲染上下文: 方法不支持Mac OS X 10.5中的所有类型的层。 它不适用于以下层类:

    • QC合成层
    • 草本色层
    • qtMOVIELLIER
        2
  •  4
  •   Brad Larson Code Synthesis    14 年前

    如果您想要一个示例代码来说明如何将Calayer层次结构呈现为nsImage(或iPhone的uiImage),您可以查看 Core Plot 框架的cplayer及其 -imageOfLayer method . 我们实际上创建了一个独立于正常渲染上下文的渲染路径:Calayer使用的过程,因为在生成层的PDF表示时,正常方法不保留向量元素。这就是为什么在这段代码中会看到-recursivelyrenderinContext:方法。

    但是,如果您试图从weichsel提到的任何层类型(qcompositionlayer、caopengallayer或qtmoviellayer)捕获数据,这将不会对您有所帮助。