Как я представляю представление, которое содержит Базовые Слои анимации к битовому массиву?

Я использую 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 для рендеринга его к битовому массиву, и это нетривиально в этом случае для создания дублирующегося дерева слоя.

Есть ли некоторый другой способ добраться CALayers для рендеринга к битовому массиву? Я не могу найти пример кода нигде для того, чтобы сделать это, на самом деле я не могу найти пример кода для CARenderer вообще.

11
задан Rob Keniger 30 December 2009 в 07:14
поделиться

2 ответа

В "Какао - моя девушка" есть отличный пост о записи "Cocoa is my girlfriend". Автор запечатлевает всю анимацию в фильме, но можно использовать ту часть, где он хватается за один кадр
. Перейдите в раздел "Получение текущего кадра" этой статьи:
http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/

Основная идея:

  • Создать CGContext
  • Использовать CALayer's renderInContext:
  • Create a NSBitmapImageRep from the контекст (с использованием CGBitmapContextCreateImage и NSBitmapImageRep initWithCGImage)

Обновление:
Я только что прочитал, что метод renderInContext: не поддерживает все уровни в Mac OS X 10.5. Он не работает для следующих классов уровней:

  • QCCompositionLayer
  • CAOpenGLLayer
  • QTMovieLayer
15
ответ дан 3 December 2019 в 06:21
поделиться

Если вам нужен пример кода, как визуализировать иерархию CALayer в NSImage (или UIImage для iPhone), вы можете посмотреть на CPLayer фреймворка Core Plot и его -метод ImageOfLayer. Фактически мы создали путь рендеринга, не зависящий от обычного процесса -renderInContext:, используемого CALayer, так как обычный способ не сохраняет векторные элементы при генерации PDF-представлений слоев. Поэтому в этом коде вы увидите метод -recursivelyRenderInContext:.

Однако, это не поможет, если вы пытаетесь захватить с любого из типов слоев, упомянутых Weichsel (QCCompositionLayer, CAOpenGLLayer или QTMovieLayer).

4
ответ дан 3 December 2019 в 06:21
поделиться