2009-12-30 4 views
10

NSView을 사용하여 여러 코어 애니메이션 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을 조사했지만 기존 계층 트리를 렌더링 할 수는 없습니다.

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

나는 레이어 트리 내 NSView에서 호스팅하고 있기 때문에이 있어야합니다 같은데요 : 나는이 작업을 수행 할 때이 예외가, 그러나

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]]; 

: 나는 다음과 같은 시도 그러므로 그것의 맥락에 붙어있다. 비트 맵으로 렌더링하기 위해 NSView에서 레이어 트리를 분리 할 수있는 방법을 이해할 수 없으며이 경우에는 중복 레이어 트리를 만드는 것이 중요하지 않습니다.

CALayer을 비트 맵으로 렌더링하는 다른 방법이 있습니까? 이 일을 위해 어디에서나 샘플 코드를 찾을 수 없습니다. 실제로 CARenderer에 대한 샘플 코드를 찾을 수 없습니다.

답변

15

코어 애니메이션 녹화에 대한 "코코아는 내 여자 친구"라는 훌륭한 게시물이 있습니다. 제작자는 전체 애니메이션을 영화로 캡처하지만, 단일 프레임을 잡는 부분을 사용할 수 있습니다. 이 문서의 "현재 프레임을 구하기"섹션
점프 :
http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/

기본 개념은 다음과 같습니다

  • CGContext
  • 사용 CALayer'srenderInContext:
  • 만들기 NSBitmapImageRep에서 만들기 컨텍스트 ( CGBitmapContextCreateImage 및 NSBitmapImageRep의 initWithCGImage 사용))

업데이트 :
가 난 그냥 renderInContext: 방법은 맥 OS X 10.5에서 레이어의 모든 종류를 지원하지 않습니다 읽기. 그것은 다음과 같은 레이어 클래스에 대한 작동하지 않습니다

  • QCCompositionLayer
  • CAOpenGLLayer
  • QTMovieLayer
+0

많은 분들께 감사 드리며, 이것이 내가 필요로하고 완벽하게 작동하는 것입니다. 앞에서'-renderInContext :'메소드를 발견했으면 좋겠다.'CARENDerer'가 정원 경로를 이끌었다. –

+0

요소에 대해이 작업이 오프 스크린입니까? 예 : 내 CALayer에는 아직 뷰 프레임에없는 요소가 있지만 스크롤해야 볼 수 있습니다. – Tudorizer

+0

누구나 [UIView animateWithDuration : ...]으로 시작된 애니메이션 작업에이 작업을 얻었습니까? 그것은 나를 위해 작동하지 않았다. – Isak

4

당신은 NSImage에있는 CALayer 계층 구조를 렌더링하는 방법에 대한 예제 코드를 원하는 (또는있는 UIImage 경우 iPhone의 경우) Core Plot 프레임 워크의 CPLayer와 -imageOfLayer method을 볼 수 있습니다.우리는 실제로 레이어의 PDF 표현을 생성 할 때 벡터 요소를 보존하지 않기 때문에 CALayer에서 사용하는 normal-renderInContext : 프로세스와 독립적 인 렌더링 경로를 만들었습니다. 그래서이 코드에서 -recursivelyRenderInContext : 메소드를 볼 수 있습니다.

그러나 weichsel (QCCompositionLayer, CAOpenGLLayer 또는 QTMovieLayer)에서 언급 한 모든 유형의 레이어에서 캡처하려는 경우에는 도움이되지 않습니다.

+0

감사합니다. weichsel의 답변보다 훨씬 포괄적이지만이 경우 실제로 필요한 것 이상입니다. '-recursivelyRenderInContext :'코드는 실제로 매우 훌륭합니다. –

관련 문제