从SKTexture创建UIImage

21

如何从SKTexture获取UIImage

我尝试从SKTextureAtlas中获取UIImage,但貌似也不起作用:

// p40_prop1 is a part of SKTextureAtlas
UIImage *image = [UIImage imageNamed:@"p40_prop1"];

image 为 nil。


你应该把MutantJedi的答案标记为被接受的答案。 - Martin
5个回答

14

iOS 9开始变得非常容易。 SKTexture现在有一个CGImage属性,其类型为CGImageRef。因此,现在从纹理获取图像只需要一行代码:

let image : UIImage = UIImage(CGImage:texture.CGImage)

顺便提一下,上述代码存在内存泄漏问题,你需要添加一个调用CGImageRelease(texture.CGImage)的语句,尽管这似乎是一个错误。 - MoDJ

13

这对我来说似乎是有用的:

- (UIImage*) imageWithView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);

    [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];

    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return img;
}


- (UIImage*) imageFromNode:(SKNode*)node
{
    SKTexture*      tex     = [self.scene.view textureFromNode:node];
    SKView*         view    = [[SKView alloc]initWithFrame:CGRectMake(0, 0, tex.size.width, tex.size.height)];
    SKScene*        scene   = [SKScene sceneWithSize:tex.size];
    SKSpriteNode*   sprite  = [SKSpriteNode spriteNodeWithTexture:tex];
    sprite.position = CGPointMake( CGRectGetMidX(view.frame), CGRectGetMidY(view.frame) );
    [scene addChild:sprite];
    [view presentScene:scene];

    return [self imageWithView:view];
}
  1. 使用当前的SKView获取节点的SKTexture
  2. 创建一个大小刚好能够容纳纹理的另一个SKView
  3. 在新场景中添加一些带有纹理的SKSpriteNode,将其放置在中心位置
  4. 将视图渲染到图形上下文中

对于那些喜欢使用Swift的人:

func imageWithView(view : UIView) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0)
    view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return img
}

func imageFromNode(node : SKNode) -> UIImage? {
    if let tex = self.scene?.view?.textureFromNode(node) {
        let view = SKView(frame:CGRectMake(0, 0, tex.size().width, tex.size().height))
        let scene = SKScene(size: tex.size())
        let sprite  = SKSpriteNode(texture: tex)
        sprite.position = CGPoint(x: CGRectGetMidX(view.frame), y: CGRectGetMidY(view.frame))
        scene.addChild(sprite)
        view.presentScene(scene)
        return self.imageWithView(view)
    }
    return nil
}

6
在iOS 7.0中其实有一种方法可以从SKView获取UIImage!它使用常规的UIView API将视图渲染到ImageContext中,然后从中提取一个UIImage。但是,这种解决方案的范围非常有限。它将SKView绘制到UIImage中,然后裁剪结果图像以适应给定节点的框架。因此,在您想要快照的节点上不能有任何遮盖物。而且,视图和场景都必须显示在屏幕上(这比通常的 - [SKView textureFromNode:] 方法更严格)。甚至可能会有我没有发现的进一步限制。考虑到所有这些,对于我的需求来说,这个过程仍然足够好,所以我觉得值得分享。
+(UIImage *)imageFromNode:(SKNode *)node {
    SKView *view = node.scene.view;
    CGFloat scale = [UIScreen mainScreen].scale;
    CGRect nodeFrame = [node calculateAccumulatedFrame];

    // render SKView into UIImage
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 0.0);
    [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
    UIImage *sceneSnapshot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    // crop to the requested node (making sure to flip the y-coordinate)
    CGFloat originY = sceneSnapshot.size.height*scale - nodeFrame.origin.y*scale - nodeFrame.size.height*scale;   
    CGRect cropRect = CGRectMake(nodeFrame.origin.x * scale, originY, nodeFrame.size.width*scale, nodeFrame.size.height*scale);
    CGImageRef croppedSnapshot = CGImageCreateWithImageInRect(sceneSnapshot.CGImage, cropRect);
    UIImage *nodeSnapshot = [UIImage imageWithCGImage:croppedSnapshot];
    CGImageRelease(croppedSnapshot);

    return nodeSnapshot;
}

我已在3.5英寸和4英寸的视网膜iPhone、视网膜和非视网膜iPad模拟器上测试过这个功能。至于实际设备,它已在运行7.0.4版本的iPhone 4S、iPhone 5S和iPad 2上成功运行。


我需要从SKTexture获取UIImage,而不是从SKNode获取。 - Andrey Gordeev
您可以使用SKSpriteNodeSKTexture绘制到屏幕上,然后使用上述代码进行快照。 我描述的注意事项仍然适用。 - sartak

0
func loadBackground() {
    guard let _ = childNode(withName: "background") as! SKSpriteNode? else {
        let texture = SKTexture(image: UIImage(named: "stick.jpg")!)
        let node = SKSpriteNode(texture: texture)
        node.size = texture.size()
        node.zPosition = StickHeroGameSceneZposition.backgroundZposition.rawValue
        self.physicsWorld.gravity = CGVector(dx: 0, dy: gravity)
        
        addChild(node)
        return
    }
}

-1

从iOS 7.0开始,无法从SKTexture、SKTextureAtlas或SKView中获取UIImage。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接