对于我的应用程序的一部分,我需要创建某个视图及其所有子视图的图像。
为此,我正在创建一个包含与视图大小相同的位图的上下文,但我不确定如何将视图层次结构绘制到其中。我可以通过设置上下文并显式调用 drawRect 来绘制单个视图,但这并不能处理所有子视图。
我在 NSView 界面中看不到任何可以帮助解决此问题的内容,因此我怀疑解决方案可能位于更高的级别。
对于我的应用程序的一部分,我需要创建某个视图及其所有子视图的图像。
为此,我正在创建一个包含与视图大小相同的位图的上下文,但我不确定如何将视图层次结构绘制到其中。我可以通过设置上下文并显式调用 drawRect 来绘制单个视图,但这并不能处理所有子视图。
我在 NSView 界面中看不到任何可以帮助解决此问题的内容,因此我怀疑解决方案可能位于更高的级别。
您可以使用-[NSView dataWithPDFInsideRect:]
将您发送到的视图的整个层次结构呈现为 PDF,并作为NSData
对象返回。然后,您可以做任何您想做的事情,包括将其渲染为位图。
你确定你想要一个位图表示吗?毕竟,该 PDF 可能(至少在理论上)与分辨率无关。
我发现自己编写绘图代码是最好的方法:
下面的代码并不完美,因为它不处理从边界到帧时的缩放问题,但它确实考虑了 isFlipped 状态,并且非常适合我使用它的用途。请注意,它只绘制子视图(以及子视图,......递归),但让它也绘制自己非常容易,只需[self drawRect:[self bounds]]
在imageWithSubviews
.
- (void)drawSubviews
{
BOOL flipped = [self isFlipped];
for ( NSView *subview in [self subviews] ) {
// changes the coordinate system so that the local coordinates of the subview (bounds) become the coordinates of the superview (frame)
// the transform assumes bounds and frame have the same size, and bounds origin is (0,0)
// handling of 'isFlipped' also probably unreliable
NSAffineTransform *transform = [NSAffineTransform transform];
if ( flipped ) {
[transform translateXBy:subview.frame.origin.x yBy:NSMaxY(subview.frame)];
[transform scaleXBy:+1.0 yBy:-1.0];
} else
[transform translateXBy:subview.frame.origin.x yBy:subview.frame.origin.y];
[transform concat];
// recursively draw the subview and sub-subviews
[subview drawRect:[subview bounds]];
[subview drawSubviews];
// reset the transform to get back a clean graphic contexts for the rest of the drawing
[transform invert];
[transform concat];
}
}
- (NSImage *)imageWithSubviews
{
NSImage *image = [[[NSImage alloc] initWithSize:[self bounds].size] autorelease];
[image lockFocus];
// it seems NSImage cannot use flipped coordinates the way NSView does (the method 'setFlipped:' does not seem to help)
// Use instead an NSAffineTransform
if ( [self isFlipped] ) {
NSAffineTransform *transform = [NSAffineTransform transform];
[transform translateXBy:0 yBy:NSMaxY(self.bounds)];
[transform scaleXBy:+1.0 yBy:-1.0];
[transform concat];
}
[self drawSubviews];
[image unlockFocus];
return image;
}
您可以-[NSBitmapImageRep initWithFocusedViewRect:]
在将焦点锁定在视图上后使用,以使视图本身(及其子视图)呈现到给定的矩形中。
您想要做的事情已经明确可用。请参阅 10.4 AppKit 发行说明中的“NSView 绘图重定向 API”部分。
制作一个 NSBitmapImageRep 进行缓存并清除它:
NSGraphicsContext *bitmapGraphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:cacheBitmapImageRep];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:bitmapGraphicsContext];
[[NSColor clearColor] set];
NSRectFill(NSMakeRect(0, 0, [cacheBitmapImageRep size].width, [cacheBitmapImageRep size].height));
[NSGraphicsContext restoreGraphicsState];
缓存到它:
-[NSView cacheDisplayInRect:toBitmapImageRep:]
如果您想更广泛地正确绘制指定的上下文处理视图递归和透明度,
-[NSView displayRectIgnoringOpacity:inContext:]