Search code examples
iosobjective-cuiimagesprite-kitsknode

How to render a SKNode to UIImage


Just playing around with SpriteKit and am trying to figure out how to capture a 'grab' of an SKNode into a UIImage.

With UIView (or a UIView subclass), I have used the layer property of the view to render into a graphics context.

Eg.

#import <QuartzCore/QuartzCore.h>
+ (UIImage *)imageOfView:(UIView *)view {
    UIGraphicsBeginImageContextWithOptions(view.frame.size, YES, 0.0f);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [view.layer renderInContext:context];
    UIImage *viewShot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return viewShot;
}

SKNode is not a subclass of UIView and thus does not appear to be backed by a layer.

Any ideas of how I might go about rendering a given SKNode to a UIImage?


Solution

  • This will capture the entire scene:

    CGRect bounds = self.scene.view.bounds;
    UIGraphicsBeginImageContextWithOptions(bounds.size, NO, [UIScreen mainScreen].scale);
    [self drawViewHierarchyInRect:bounds afterScreenUpdates:YES];
    UIImage* screenshotImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    

    If you want just a particular node branch you can hide all nodes you don't want to capture before taking the screenshot. You can also use accumulated frame converted to UIKit coordinates to capture only the area of the node and its children in question.

    Alternately, you can get an SKTexture from a specific part of the node hierarchy:

    SKTexture* tex = [self.scene.view textureFromNode:yourNode];
    

    Prior to iOS 9, there wasn't way to convert an SKTexture back to a UIImage. Now, however, it's trivial:

    UIImage *image = [UIImage imageWithCGImage:tex.CGImage];