-1

Currently I'm making an isometric map editor (in Swift) where each map tile is added to an SKNode called mapLayer. I want to know whether it is possible to produce a png image from this mapLayer, once I have finished designing a map?

Kendel
  • 1,698
  • 2
  • 17
  • 33
wes
  • 47
  • 5

3 Answers3

1

Not in Swift but it should give you a good idea on how to do it.

You can capture your screen to a UIImage by doing this:

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

Then create a PNG image from the UIImage (and write it to disk) like this:

// Create paths to output images
NSString  *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Test.png"];
NSString  *jpgPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Test.jpg"];

Source here.

// Write a UIImage to JPEG with minimum compression (best quality)
// The value 'image' must be a UIImage object
// The value '1.0' represents image compression quality as value from 0.0 to 1.0
[UIImageJPEGRepresentation(image, 1.0) writeToFile:jpgPath atomically:YES];

// Write image to PNG
[UIImagePNGRepresentation(image) writeToFile:pngPath atomically:YES];

// Let's check to see if files were successfully written...

// Create file manager
NSError *error;
NSFileManager *fileMgr = [NSFileManager defaultManager];

// Point to Document directory
NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];

// Write out the contents of home directory to console
NSLog(@"Documents directory: %@", [fileMgr contentsOfDirectoryAtPath:documentsDirectory error:&error]);

Source here.

Community
  • 1
  • 1
sangony
  • 11,636
  • 4
  • 39
  • 55
1

Here's an example of how to write the contents of the view to a PNG file. First, define a UIView extension that captures the contents of the view and converts it to a UIImage.

extension UIView {
    func screenGrab() -> UIImage {
        // Uncomment this (and comment out the next statement) for retina screen capture
        // UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.mainScreen().scale)
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, 1.0)
        drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

Then, define a UIImage extension that writes a UIImage to a file.

extension UIImage {
    func writeToFile(fileName:String) {
        let path = NSHomeDirectory().stringByAppendingPathComponent("Documents/"+fileName)
        UIImagePNGRepresentation(self).writeToFile(path, atomically: true)
    }
}

Lastly, capture and write the contents of the view to a PNG file with

self.view?.screenGrab().writeToFile("capture.png")

and here's how to determine where the PNGs will be stored:

println(NSHomeDirectory().stringByAppendingPathComponent("Documents"))
Epsilon
  • 1,016
  • 1
  • 6
  • 15
  • I take it this would work for iOS since it uses UIKit, but I want it to work for a mac application. Is there an equivalent using AppKit? – wes Aug 31 '15 at 09:23
  • Sorry about that. I missed the osx tag. I'll have to research that. – Epsilon Aug 31 '15 at 09:36
0

This is one of the instances where macOS and iOS behave very differently. Spoiler: the usual methods of capturing the contents of an NSView to NSImage don't work.

NSImage(data:inside:) and NSView.bitmapImageRepForCachingDisplay(in:to) work fine for NSView, but if you embed an SKView or apply them to the SKView directly, you'll only get a blank canvas.

The solution lies in thinking SpriteKit:

An SKScene is an SKNode at heart (actually, an SKEmitterNode), and SKView has a method called texture(from: SKNode) which gives you an SKTexture. SKTexture has a cgImage() property, and there you are.

This assumes three properties in the NSViewController that presents the scene: skView: SKView, scene: SKScene?, and an NSImageView for display named snapView.

  if  let rendered = skView.texture(from: scene!){
        snapView.image = NSImage(cgImage: rendered.cgImage(), size: self.skView.bounds.size)

(Don't force unwrap, it's only for demo purposes)

green_knight
  • 1,319
  • 14
  • 26
  • I know: old, downvoted question. This was the first search result for trying to take a screenshot of an SKView on macOS, so I'm posting the answer anyway. – green_knight May 11 '20 at 00:16