2009-12-30 80 views
10

我正在使用一個NSView來承載多個Core Animation CALayer對象。我想要做的就是將視圖當前狀態的快照作爲位圖圖像抓取。如何渲染包含Core Animation圖層的視圖到位圖?

這是一個正常的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中分離圖層樹以將其渲染爲位圖,並且在這種情況下創建重複圖層樹不重要。

有一些其他的方式來獲得CALayer s到渲染成位圖?我無法在任何地方找到任何示例代碼,實際上我根本找不到CARenderer的任何示例代碼。

回答

15

上有「可可是我的女朋友」關於錄製核心動畫一個偉大的職位。作者將整個動畫捕捉到一部電影中,但您可以使用他抓取單幀的部分。
跳轉到 「獲取當前幀」 一節中的:
http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/

的基本思路是:

  • 創建一個CGContext上
  • 使用CALayer'srenderInContext:
  • 創建從NSBitmapImageRep在 上下文(使用 CGBitmapContextCreateImage和 NSBitmapImageRep的initWithCGImage )

更新:
我剛纔讀,該renderInContext:方法不支持所有類型層的在Mac OS X 10.5。 它不爲以下幾層類工作:

  • QCCompositionLayer
  • CAOpenGLLayer
  • QTMovieLayer
+0

非常感謝,這正是我所需要的,完美的作品。我希望早些時候注意到'-renderInContext:'方法,'CARenderer'把我帶到花園的路上。 – 2009-12-31 02:32:41

+0

這是否爲元素的工作是離屏?例如。我的CALayer包含一些不在視圖框架中的元素,但我需要滾動才能看到它們。 – Tudorizer 2011-07-12 15:34:35

+0

有沒有人得到這個與[UIView animateWithDuration:...]開始的動畫一起工作?它不適合我。 – Isak 2013-07-01 19:52:26

4

如果你想要如何呈現一個CALayer的層次結構,以一個NSImage中的示例代碼(或的UIImage對於iPhone),您可以查看Core Plot框架的CPLayer及其-imageOfLayer method。實際上,我們創建了一個獨立於CALayer使用的正常-renderInContext:過程的呈現路徑,因爲在生成圖層的PDF表示時,常規方式不會保留向量元素。這就是爲什麼你會在這段代碼中看到-recursivelyRenderInContext:方法。

但是,如果您嘗試從weichsel(QCCompositionLayer,CAOpenGLLayer或QTMovieLayer)提到的任何圖層類型捕獲,這將無濟於事。

+0

感謝這個,它比來自weichsel的答案要全面得多,但在這種情況下比實際需要的要多。 '-recursivelyRenderInContext:'代碼確實非常好。 – 2009-12-31 02:34:47