Как визуализировать представление, содержащее слои основной анимации, в растровое изображение?
Я использую 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
.
Ответы
Ответ 1
Есть отличная статья на тему "Cocoa - моя девушка" о записи Core Animations. Автор фиксирует всю анимацию в фильме, но вы можете использовать ту часть, где он захватывает один кадр.
Перейдите к разделу "Получение текущего кадра" в этой статье:
http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/
Основная идея:
- Создать CGContext
- Используйте CALayer
renderInContext:
- Создайте NSBitmapImageRep из
контекста (используя
CGBitmapContextCreateImage и
NSBitmapImageRep initWithCGImage)
Update:
Я просто прочитал, что метод renderInContext:
не поддерживает все типы слоев в Mac OS X 10.5.
Он не работает для следующих классов слоев:
- QCCompositionLayer
- CAOpenGLLayer
- QTMovieLayer
Ответ 2
Если вам нужен пример кода для визуализации иерархии CALayer для NSImage (или UIImage для iPhone), вы можете посмотреть Core Plot framework CPLayer и - метод imageOfLayer. Мы фактически создали путь рендеринга, который не зависит от процесса normal -renderInContext:, который используется CALayer, поскольку обычный способ не сохраняет векторные элементы при создании PDF-представлений слоев. Поэтому в этом коде вы увидите метод -recursivelyRenderInContext:
Однако это не поможет вам, если вы пытаетесь захватить любой из типов слоев, упомянутых weichsel (QCCompositionLayer, CAOpenGLLayer или QTMovieLayer).