UIImage от SKTexture

Как получить UIImage от SKTexture?

Я пытался получить UIImage из SKTextureAtlas, но тоже не работает:

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

image равно нулю.


person Andrey Gordeev    schedule 11.01.2014    source источник
comment
Вы должны отметить ответ MutantJedi как принятый.   -  person Martin    schedule 31.10.2014


Ответы (4)


Начиная с iOS 9 это проще простого. SKTexture теперь имеет свойство CGImage типа CGImageRef. Таким образом, получение изображения из текстуры теперь занимает всего одну строку:

let image : UIImage = UIImage(CGImage:texture.CGImage)
person Andrey Chernukha    schedule 09.10.2015
comment
Вышеупомянутая утечка памяти Кстати, вам нужно добавить вызов CGImageRelease(texture.CGImage), хотя это похоже на ошибку. - person MoDJ; 15.06.2016

Кажется, это работает для меня:

- (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. получить SKTexture для вашего узла, используя текущий SKView
  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
}
person AutomatonTec    schedule 04.04.2014

На самом деле есть способ получить UIImage из SKView в iOS 7.0!

Он использует обычные API-интерфейсы UIView для рендеринга представления в 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 с сетчаткой и без нее. Что касается реальных устройств, то он работал на iPhone 4S, iPhone 5S и iPad 2, на всех версиях 7.0.4.

person sartak    schedule 06.02.2014
comment
Мне нужно было получить UIImage от SKTexture, а не SKNode - person Andrey Gordeev; 06.02.2014
comment
Вы можете нарисовать SKTexture на экране с помощью SKSpriteNode, а затем сделать снимок, используя приведенный выше код. Предостережения, которые я описал, по-прежнему применимы. - person sartak; 06.02.2014

Начиная с iOS 7.0 невозможно получить UIImage из SKTexture, SKTextureAtlas или SKView.

person LearnCocos2D    schedule 11.01.2014