Рендеринг/моментальный снимок сцены SpriteKit в NSImage

Кто-нибудь знает, как "сделать снимок" полного SKView или SKScene в NSImage?

Мы смогли использовать textureFromNode API для создания SKTexture из узла и всех его дочерних элементов. Но пока мы не можем найти способ извлечь данные изображения, скажем, в файл NSImage. Мы создаем смешанное приложение Cocoa/SpriteKit, в котором нам нужно извлекать небольшие эскизы сцен.

Опять же, это кажется возможным на iOS (чтобы получить UIImage) с помощью drawViewHierarchyInRect:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, scale);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Но как это сделать на Cocoa с NSImage? Помощь.


person poundev23    schedule 18.12.2013    source источник
comment
Это то, что вы ищете: stackoverflow.com/questions/3251261/   -  person steffex    schedule 15.01.2014
comment
Нет, ссылка, которую вы упомянули, не работает для представлений на основе OpenGL (см. Комментарии в ней), что касается SKViews.   -  person Guillaume Laurent    schedule 19.01.2014
comment
Как насчет ответа по адресу: stackoverflow.com/questions/19571357/ios- спрайт-комплект-скриншот   -  person Mark    schedule 17.04.2014


Ответы (4)


Начиная с OS X 10.11 (а также iOS 9 и tvOS, но мы их проигнорируем, поскольку вы спрашиваете о NSImage), SKTexture может экспортировать свое содержимое в файл CGImageRef. Таким образом, упомянутый вами подход textureFromNode теперь является первым шагом в рабочем решении:

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

Обратите внимание на параметр size для initWithCGImage:, вы можете передать туда CGSizeZero, чтобы NSImage наследовал размер пикселей от CGImage, но, поскольку вы можете иметь дело с дисплеем Retina, вам, вероятно, нужна точка размер, который вы можете получить из размеров представления.

person rickster    schedule 11.02.2016

Вот моя попытка (на 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];

Нет игральных костей. Все, что я вижу в своем представлении thumbNail, черное.

Вероятно, по той же причине, что это все рисование на основе OpenGL/GPU.

Это привело бы меня к тому, чтобы каким-то образом найти базовый контекст рисования OpenGL, используемый SKView, и выполнить glReadPixels в этом контексте.

person zzyzy    schedule 03.04.2014
comment
Заголовки говорят, что вы не можете создать подкласс SKView… Я думаю, может быть, в методе update:? - person geowar; 30.05.2014

Прямого доступа к данным изображения из 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
}
person elkraneo    schedule 02.12.2014

SKView является подклассом UIView, поэтому вы должны иметь возможность рисовать слой представления в контексте CoreGraphics, а затем получать изображение из контекста.

Посмотрите на использование view.layer.drawInContext.

person gdavis    schedule 05.03.2015