Grimxn
Grimxn

Reputation: 22487

NSData from CGImageRef in Swift

I am having difficulty figuring out how to get an NSData representation of an image from a CGImageRef. All of the answers I've found make use of UIImage or NSImage, but my application is cross-platform, so I want to use only Core Graphics. Objective-C answers state simply that CFData is toll-free bridged to NSData and simply cast it, but Swift will not allow this. The closest I've got is:

var image: CGImageRef? = nil

//...
if let dataProvider: CGDataProviderRef = CGDataProviderCreateWithURL(url) {
    image = CGImageCreateWithPNGDataProvider(dataProvider, nil, false, CGColorRenderingIntent.RenderingIntentDefault) 
    // works fine
    //...
    if let data = CGDataProviderCopyData(CGImageGetDataProvider(image)) as? NSData {
        // Do something with data, if only it ever got here!
    }
}

but the cast doesn't ever succeed...

Upvotes: 2

Views: 1350

Answers (1)

Martin R
Martin R

Reputation: 539745

CGDataProviderCopyData() returns the optional CFData?, and that cannot be cast to the non-optional NSData. But you can convert/bridge it to NSData? and use that in the optional binding:

if let data = CGDataProviderCopyData(CGImageGetDataProvider(image)) as NSData? {
    // Do something with data ...

}

Here is a simpler example demonstrating the same issue with CFString and NSString:

let cfstr : CFString? = "Hello world"
if let nsstr = cfstr as? NSString {
    print("foo") // not printed
}
if let nsstr = cfstr as NSString? {
    print("bar") // printed
}

But I admit that my explanation is not fully satisfying, because a similar optional cast works in other cases:

class MyClass { }
class MySubclass : MyClass { }

let mc : MyClass? = MySubclass()
if let msc = mc as? MySubclass {
    print("yes") // printed
}

So this must be related to the toll-free bridging between CoreFoundation and Foundation types.

Upvotes: 4

Related Questions