Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save CGImage to Data in Swift?

This code type checks and compiles but then crashes. How do I save a CGImage to Data so that I can read it in again later.

let cgi: CGImage? = ...        
var mData = Data()
let imageDest = CGImageDestinationCreateWithData(mData as! CFMutableData, 
                                                 kUTTypePNG, 1, nil)!
CGImageDestinationAddImage(imageDest, cgi!, nil)
CGImageDestinationFinalize(imageDest)

The last line crashes. Error in console is:

2018-01-17 19:25:43.656664-0500 HelloPencil[2799:3101092] -[_NSZeroData 
  appendBytes:length:]: unrecognized selector sent to instance 0x1c80029c0
2018-01-17 19:25:43.658420-0500 HelloPencil[2799:3101092] *** Terminating app 
  due to uncaught exception 'NSInvalidArgumentException', reason: 
  '-[_NSZeroData appendBytes:length:]: unrecognized selector 
  sent to instance 0x1c80029c0'

That cast from Data to CFMutableData was recommended by Xcode, but maybe it's wrong.

like image 495
Rob N Avatar asked Jan 18 '18 00:01

Rob N


1 Answers

The problem is the way you are creating your mutable data. Data is not convertible to NSMutableData. Just change your forced casting from Data to CFMutableData to CFDataCreateMutable(nil, 0). Another option is to use NSMutableData which is toll-free bridged to CFMutableData. Try like this:

if let cgi = cgi, 
    let mutableData = CFDataCreateMutable(nil, 0),
    let destination = CGImageDestinationCreateWithData(mutableData, "public.png" as CFString, 1, nil) {
    CGImageDestinationAddImage(destination, cgi, nil)
    if CGImageDestinationFinalize(destination) {
        let data = mutableData as Data
        if let image = UIImage(data: data) {
            print(image.size)
        }
    } else {
        print("Error writing Image")
    }
}

edit/update: Xcode 11 • Swift 5.1

extension CGImage {
    var png: Data? {
        guard let mutableData = CFDataCreateMutable(nil, 0),
            let destination = CGImageDestinationCreateWithData(mutableData, "public.png" as CFString, 1, nil) else { return nil }
        CGImageDestinationAddImage(destination, self, nil)
        guard CGImageDestinationFinalize(destination) else { return nil }
        return mutableData as Data
    }
}
like image 141
Leo Dabus Avatar answered Oct 29 '22 03:10

Leo Dabus