objective c - UIImage de SKTexture
objective-c sprite-kit (4)
¡De hecho, hay una manera de obtener un UIImage de un SKView en iOS 7.0!
Utiliza las API regulares de UIView para convertir la vista en un ImageContext, luego saca un UIImage de eso. Sin embargo, esta solución tiene un alcance muy limitado. Dibuja el SKView en un UIImage, luego recorta la imagen resultante para ajustarse al marco de un nodo dado. Por lo tanto, no debe haber nada que cubra ese nodo que desea capturar. Además, tanto la vista como la escena deben estar visibles en la pantalla (que es más estricto que el método habitual -[SKView textureFromNode:]
). Incluso puede haber más restricciones que no he descubierto.
Dado todo eso, este procedimiento fue suficiente para lo que necesitaba, así que pensé que valía la pena compartirlo.
+(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;
}
He probado esto en el simulador en iPhones de retina de 3,5 "y 4", iPads retina y no retina. En cuanto a los dispositivos reales, funcionó en iPhone 4S, iPhone 5S y iPad 2, todos ejecutando 7.0.4.
¿Cómo obtener UIImage
de SKTexture
?
Traté de obtener UIImage
de SKTextureAtlas
, pero parece que no funciona:
// p40_prop1 is a part of SKTextureAtlas
UIImage *image = [UIImage imageNamed:@"p40_prop1"];
image
es nula.
A partir de iOS 7.0 no hay forma de obtener un UIImage de SKTexture, SKTextureAtlas o SKView.
A partir de iOS 9 es pan comido. SKTexture
ahora tiene la propiedad CGImage
, que es del tipo CGImageRef
. Así que obtener una imagen de una textura es solo una línea ahora:
let image : UIImage = UIImage(CGImage:texture.CGImage)
Esto parece estar funcionando para mí:
- (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];
}
- obtén SKTexture para tu nodo usando el SKView actual
- hacer otro SKView que sea lo suficientemente grande para su textura
- agregue un SKSpriteNode con la textura en su nueva escena, colocándolo en el medio
- renderizar la vista en un contexto de gráficos
O para aquellos que prefieren 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
}