對於我的應用程序的一部分,我需要創建特定視圖及其所有子視圖的圖像。在Cocoa中繪製視圖層次結構到特定的上下文
要做到這一點,我創建了一個包裝與視圖大小相同的位圖的上下文,但我不確定如何繪製視圖層次結構。我可以繪製一個單一的視圖,只需設置上下文並明確調用drawRect,但這並不涉及所有的子視圖。
我不能在NSView界面看到任何可以幫助解決這個問題的東西,所以我懷疑解決方案可能在更高的層面。
對於我的應用程序的一部分,我需要創建特定視圖及其所有子視圖的圖像。在Cocoa中繪製視圖層次結構到特定的上下文
要做到這一點,我創建了一個包裝與視圖大小相同的位圖的上下文,但我不確定如何繪製視圖層次結構。我可以繪製一個單一的視圖,只需設置上下文並明確調用drawRect,但這並不涉及所有的子視圖。
我不能在NSView界面看到任何可以幫助解決這個問題的東西,所以我懷疑解決方案可能在更高的層面。
我發現,寫繪圖代碼自己是最好的辦法:
下面的代碼並不完美,因爲它不處理從邊界到幀的擴展問題,但它確實考慮了isFlipped狀態,並且對於我使用它的工作非常好。請注意,它只繪製子視圖(和子視圖,...遞歸),但是讓它也可以很容易繪製,只需在imageWithSubviews
的實現中添加[self drawRect:[self bounds]]
即可。
- (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;
}
您可以使用-[NSView dataWithPDFInsideRect:]
將您發送的視圖的整個層次結構呈現爲PDF,並作爲NSData
對象返回。然後你可以用它做任何你想做的事情,包括把它渲染成位圖。
您確定要使用位圖嗎?畢竟,PDF可能(至少在理論上)是獨立於分辨率的。
是的,對於這種特定的用法,未縮放的圖像數據正是我所需要的。
將焦點鎖定在視圖上後,您可以使用-[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:]
「NSView繪圖重定向API」的鏈接10.4 http://developer.apple.com/mac/library/releasenotes/Cocoa/AppKitOlderNotes.html – 2010-02-26 01:15:34
如果視圖位於NSScrollView中,這會產生顯示視圖的副作用內容裁剪爲在滾動視圖中可見的內容,幷包含任何滾動條。 – Jason 2015-09-22 22:21:34