Objective c 渲染/快照SpriteKit场景到NSImage

Objective c 渲染/快照SpriteKit场景到NSImage,objective-c,macos,cocoa,sprite-kit,skview,Objective C,Macos,Cocoa,Sprite Kit,Skview,有人知道如何将完整的SKView或SKScene快照到NSImage中吗 我们已经能够使用textureFromNodeAPI从节点及其所有子节点创建SKTexture。但是到目前为止,我们还没有找到一种方法将图像数据提取到NSImage中。我们正在构建一个混合的Cocoa/SpriteKit应用程序,在这里我们需要提取场景的小缩略图 同样,在iOS上(使用drawViewHierarchyInRect获取UIImage)这似乎也是可能的: UIGraphicsBeginImageContext

有人知道如何将完整的
SKView
SKScene
快照到
NSImage
中吗

我们已经能够使用
textureFromNode
API从节点及其所有子节点创建
SKTexture
。但是到目前为止,我们还没有找到一种方法将图像数据提取到NSImage中。我们正在构建一个混合的
Cocoa
/
SpriteKit
应用程序,在这里我们需要提取场景的小缩略图

同样,在iOS上(使用
drawViewHierarchyInRect
获取
UIImage
)这似乎也是可能的:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, scale);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
但是如何使用
NSImage
Cocoa
上执行此操作?帮助。

这是我(在OSX上)试图获取底层渲染图像的尝试

首先,我对
SKView
进行了子类化,并在其
drawRect
方法中懒洋洋地抓取了一个
NSBitmapImageRep

if (![self cache])
    [self setCache:[self bitmapImageRepForCachingDisplayInRect:[self visibleRect]]];
然后,我设置了一个
NSTimer
,它会定期尝试将该缓存的内容复制到自定义缩略图视图:

MySKView *sv = .....
NSBitmapImageRep *cache = [sv cache];
if (!cache)
    return;

NSRect srcFrame = NSMakeRect(0,0,[sv frame].size.width,[sv frame].size.height);
NSRect thumbFrame = [[self thumbView] frame];
NSRect thumbRect = NSMakeRect(0,0,thumbFrame.size.width,thumbFrame.size.height);
[sv cacheDisplayInRect:srcFrame toBitmapImageRep:cache];
[[self thumbView] lockFocus];
[cache drawInRect:thumbRect
         fromRect:srcFrame
         operation:NSCompositeCopy
         fraction:1.0
   respectFlipped:YES
            hints:nil];
[[self thumbView] unlockFocus];
没有骰子。我在缩略视图中看到的都是黑色

可能是因为同样的原因,这都是基于OpenGL/GPU的绘图


这将引导我以某种方式找到
SKView
使用的底层OpenGL绘图上下文,并在该上下文上执行
glReadPixels

目前还无法从SKTexture直接访问图像数据。可以在屏幕外场景中显示节点并捕获视图层次。我在iOS中使用此代码作为参考:

class func imageFromNode(node : SKNode, inScene scene: SKScene) -> UIImage? {
    if let texture = scene.view?.textureFromNode(node) {
        let view = SKView(frame: CGRect(origin: CGPointZero, size: texture.size()))
        view.allowsTransparency = true
        view.backgroundColor = SKColor.clearColor()

        let scene = SKScene(size: view.bounds.size)
        scene.view?.allowsTransparency = true
        scene.backgroundColor = SKColor.clearColor()

        let sprite  = SKSpriteNode(texture: texture)
        sprite.position = CGPoint(x: CGRectGetMidX(view.frame), y: CGRectGetMidY(view.frame))
        scene.addChild(sprite)
        view.presentScene(scene)
        UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
        view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
    return nil
}

SKView
是一个
UIView
子类,因此您应该能够在CoreGraphics上下文中绘制视图的图层,然后从上下文中获取图像

查看如何使用
查看.layer.drawInContext

从OS X 10.11(以及iOS 9和tvOS,但我们将忽略这些,因为您询问的是
NSImage
),
SKTexture
可以将其内容导出到
cImageRef
。因此,您提到的
textureFromNode
方法现在是有效解决方案的第一步:

SKTexture *texture = [view textureFromNode: view.scene];
NSImage *image = [[NSImage alloc] initWithCGImage: texture.CGImage
                                             size: view.bounds];

注意
size
参数到
initWithCGImage:
您可以将
cgizezero
传递到那里,使
NSImage
继承
CGImage
的像素大小,但由于您可能正在处理视网膜显示,您可能需要点大小,您可以从视图维度中获得它。

这就是您要寻找的:不,您提到的链接对基于OpenGL的视图不起作用(请参阅其中的注释),这对于SKViews就是如此。答案是:标题上说您不能对SKView进行子类化……我想可能在更新:方法中?