hollance / CoreMLHelpers

Types and functions that make it a little easier to work with Core ML in Swift.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CoreGraphics resizing function from iOS (UIImage) to MacOS (NSImage)

alelordelo opened this issue · comments

Hi Matthias,

Were you able to run your helper functions on MacOS? I replaced iOS (UIImage) to MacOS (NSImage), and got almost everything to work... Only the cgImage.bitsPerPixel part I didn't find a MacOS equivalent.

Have you tried running it on MacOS?

Cheers from Sweden!
Alex

https://stackoverflow.com/questions/67202976/coregraphics-resizing-function-from-ios-uiimage-to-macos-nsimage

What I did:
Code bellow

Problem:
Getting error on this line of code: let bytesPerPixel = cgImage.bitsPerPixel / bitsPerComponent

Error:
Value of type '(UnsafeMutablePointer?, NSGraphicsContext?, [NSImageRep.HintKey : Any]?) -> CGImage?' (aka '(Optional, Optional, Optional<Dictionary<NSImageRep.HintKey, Any>>) -> Optional') has no member 'bitsPerPixel'

iOS: UIImage

extension UIImage {
    
    // Resizeing using CoreGraphics
    func resize(to size:CGSize) -> UIImage? {
        
        let cgImage = self.cgImage!

        let destWidth = Int(size.width)
        let destHeight = Int(size.height)
        let bitsPerComponent = 8
        let bytesPerPixel = cgImage.bitsPerPixel / bitsPerComponent
        let destBytesPerRow = destWidth * bytesPerPixel
        
        let context = CGContext(data: nil,
                                width: destWidth,
                                height: destHeight,
                                bitsPerComponent: bitsPerComponent,
                                bytesPerRow: destBytesPerRow,
                                space: cgImage.colorSpace!,
                                bitmapInfo: cgImage.bitmapInfo.rawValue)!
        context.interpolationQuality = .high
        context.draw(cgImage, in: CGRect(origin: CGPoint.zero, size: size))
        return context.makeImage().flatMap { UIImage(cgImage: $0) }
    }
}

MacOS: NSImage

extension NSImage {
    
    // Resizeing using CoreGraphics
    func resize(to size:CGSize) -> NSImage? {
        
        let cgImage = self.cgImage

        let destWidth = Int(size.width)
        let destHeight = Int(size.height)
        let bitsPerComponent = 8
        let bytesPerPixel = cgImage.bitsPerPixel / bitsPerComponent
        let destBytesPerRow = destWidth * bytesPerPixel
        
        let context = CGContext(data: nil,
                                width: destWidth,
                                height: destHeight,
                                bitsPerComponent: bitsPerComponent,
                                bytesPerRow: destBytesPerRow,
                                space: cgImage.colorSpace!,
                                bitmapInfo: cgImage.bitmapInfo.rawValue)!
        context.interpolationQuality = .high
        context.draw(cgImage, in: CGRect(origin: CGPoint.zero, size: size))
        return context.makeImage().flatMap { NSImage(cgImage: $0) }
    }
}

CGImage should work both on iOS and macOS. It looks like you forgot to unwrap self.cgImage, since the error message is about using an optional, not about CGImage itself.

Thanks Matthias!

I unwrapped self.cgImage, but got same error.

Looks like bitsPerPixel is only available for iOS... : /

Any idea what would be MacOS equivalent to bitsPerPixel?

/* Return the number of bits/pixel of `image'. */

**@available(iOS 2.0, *)**
public var bitsPerPixel: Int { get }

Value of type '(UnsafeMutablePointer?, NSGraphicsContext?, [NSImageRep.HintKey : Any]?) -> CGImage?' (aka '(Optional<UnsafeMutablePointer>, Optional, Optional<Dictionary<NSImageRep.HintKey, Any>>) -> Optional') has no member 'bitsPerPixel'

Ah I see what's going on, NSImage.cgImage is not a property but a function. Namely the function:

func cgImage(forProposedRect proposedDestRect: UnsafeMutablePointer<NSRect>?, context referenceContext: NSGraphicsContext?, hints: [NSImageRep.HintKey : Any]?) -> CGImage?

You're trying to call bitsPerPixel on the function itself, not on the CGImage that comes out of the function. ;-)

thanks for spotting that Matthias! : )

Weird that UIImage.cgImage is a property, and NSImage.cgImage is a function.

Im a bit lost here... Do you have any idea what the final resize function would look like for MacOS?

Thanks again!

Finally made it work with some help from Apple, this is the final function in case you also need. : )

// Resizeing using CoreGraphics
  func resize(to size:CGSize) -> NSImage? {
       
       let cgImage: CGImage = self.cgImage( forProposedRect: nil,  context: nil, hints: nil)!

       let destWidth = Int(size.width)
       let destHeight = Int(size.height)
       let bitsPerComponent = 8
       let bytesPerPixel = cgImage.bitsPerPixel / bitsPerComponent
       let destBytesPerRow = destWidth * bytesPerPixel
       
       let context = CGContext(data: nil,
                               width: destWidth,
                               height: destHeight,
                               bitsPerComponent: bitsPerComponent,
                               bytesPerRow: destBytesPerRow,
                               space: cgImage.colorSpace!,
                               bitmapInfo: cgImage.bitmapInfo.rawValue)!
       context.interpolationQuality = .high
       context.draw(cgImage, in: CGRect(origin: CGPoint.zero, size: size))
       return context.makeImage().flatMap { NSImage(cgImage: $0, size: NSSize(width: 1024, height: 1024)) }
   }