NSImage : how to crop?

I have a PNG image with a bunch of smaller images in a grid. I need to be able to provide a CGRect relative to this image, and extract the “square”

for iOS, this is super easy

let imageRef: CGImage = largeImage!.cropping(to: extract)!
let tile: UIImage  = UIImage(cgImage: imageRef, scale: 1, orientation: .up)

where largeImage is well the large image :slight_smile: , extract is a CGRect of what to extract, and tile is the resulting UIImage

I am at a loss to find a corresponding set of functions that work for an NSImage

any ideas?
Seems working with NSImage is lacking the most elementary functions, while UIImage has “it all”… and yes I know UIImage was created later, so it got all the shiny new toys :smiley:

only seems to have other drawinrect methods which might let you create an image then draw into it but that somehow feels really wrong

That seems to be all I can find, and its much more complicated than the iOS version.
It would be simpler/faster to include individual tile images for macOS (the problem is there is over a 100)
I need to keep the footprint small, this is to draw a “thumbnail” of the gam board (which has 300+ variations) so to save space, I need to create these “on the fly”

I have given up :frowning:
I’m making 180 individual tiles for the sole purpose of making thumbnail scenes on the fly.
While I “could” do iOS one way and macOS another… it isn’t worth the hassle of maintaining two methods to the same result.

Create an NSImage of size, lock on to it, draw your current NSImage and then unlock the NSImage.

I use this for a variety of things. But do most of my image manipulation in CG or CI, not NS.
NSImage with size
https://developer.apple.com/documentation/appkit/nsimage/1520033-initwithsize?language=objc

Cropping a CGImage
https://developer.apple.com/documentation/coregraphics/1454683-cgimagecreatewithimageinrect?language=objc

Doesn’t work for NSImage directly… you need to do it with a CIIImage…
but for some reason it SAID it was extracting the correct “tile” from the larger image, but the result was always one specific one.

// This converted my spritesheet (PNG) into a CIIimage
let largeImage = NSImage(named: "spritesheet")
let tiffData   = largeImage?.tiffRepresentation
let ci         = CIImage(data:tiffData!)
// this was supposed to extract a single "tile" where cropRect is the location/size
let ciImage = ci?.cropped(to: cropRect)
let rep     = NSCIImageRep(ciImage: ciImage!)
let tile    = NSImage(size: rep.size)
tile.addRepresentation(rep)

I would recommend avoiding Core Image for this. Apple even suggest in the docs to use CGimage cropping functions instead of CIImage cropping functions.

Core Image will load the image to the GPU, crop it, radterize to bitmap data, then transfer that data to RAM before being able to save it.

Not only is this expensive, but it can also fail easily (bugs in OS, GPU limitations, wind blowing in the wrong direction), when it fails you just get a black image.

Look into CGImageCreateWithImageInRect, then create NSImages from the CGImages.

https://developer.apple.com/documentation/coregraphics/1454683-cgimagecreatewithimageinrect?language=objc

Which leads me to ask, why do you need lots of NSImages? If you’re simply drawing them in a NSView, you can get a CGContext from the current NSGraphicsContext and draw CGImages directly there, utilizing all the power that a CGContext can offer.

thats the thing I would prefer NOT to deal with “lots of NSImages”… The idea is to have a single “spritesheet” and to extract a given tile to build up a thumbnail image of what a particular game scenario would look like.

For example… here is what the spritesheet might look like :

The actual game play uses SpriteKit, and does NOT use this sheet (it has Texture Atlas instead)… but I can’t seem to transfer the “Scene” to an NSImage (UIImage is no problem), but this is for all platforms (macOS, iOS, and tvOS)… iOS and tvOS both use UIImage, its NSImage that is a royal pain… I did have something that “kind of” worked with a CIImage, but not matter what it only displayed one tile in one location even though the logs said it was doing the right thing.

I don’t have any experience with SpriteKit, but I’d imagine there is an easier way.

SpriteKit in and of itself isn’t the issue… the issue is how to extract any give tile from that picture.
UIImage is not a problem… it is NSImage that I can’t get to work…

and it seems there is a corruption bug in the SKTexture to CGImage methods in Spritekit…
So, sigh, back to the drawing board