Search code examples
swiftcore-foundation

Creating a CFDictionary


In an attempt to get this following code to work:

import ImageIO

if let imageSource = CGImageSourceCreateWithURL(self.URL, nil) {
    let options: CFDictionary = [
        kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height) / 2.0,
        kCGImageSourceCreateThumbnailFromImageIfAbsent: true
    ]

    let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options).flatMap { UIImage(CGImage: $0) }
}

I need to know how to correctly initialize a CFDictionary. Unfortunately, it seems like it's not as easy as I predicted. I've done some experimenting and research, and it seems like there is conflicting information.

For starters, here's an entry in the Apple Docs regarding the kCGImageSourceThumbnailMaxPixelSize key:

kCGImageSourceThumbnailMaxPixelSize

The maximum width and height in pixels of a thumbnail. If this key is not specified, the width and height of a thumbnail is not limited and thumbnails may be as big as the image itself. If present, this key must be a CFNumber value. This key can be provided in the options dictionary that you pass to the function CGImageSourceCreateThumbnailAtIndex.

After looking into how to initialize the CFNumber, I found an excerpt for CFNumber

CFNumber is “toll-free bridged” with its Cocoa Foundation counterpart, NSNumber. This means that the Core Foundation type is interchangeable in function or method calls with the bridged Foundation object

I then tried to do this:

let options: CFDictionary = [
    kCGImageSourceThumbnailMaxPixelSize: NSNumber(double: 3.0)
]

and was greeted by the error message: '_' is not convertible to 'CFString!' and Type of expression is ambiguous without more context.


Solution

  • Here is your working code:

    func processImage(jpgImagePath: String, thumbSize: CGSize) {
    
        if let path = NSBundle.mainBundle().pathForResource(jpgImagePath, ofType: "") {
            if let imageURL = NSURL(fileURLWithPath: path) {
                if let imageSource = CGImageSourceCreateWithURL(imageURL, nil) {
    
                    let maxSize = max(thumbSize.width, thumbSize.height) / 2.0
    
                    let options : [NSString : AnyObject] = [
                        kCGImageSourceThumbnailMaxPixelSize:  maxSize,
                        kCGImageSourceCreateThumbnailFromImageIfAbsent: true
                    ]
    
                    let scaledImage = UIImage(CGImage: CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options))
    
                    // do other stuff
                }
            }
        }
    }
    

    From Docs:

    The implicit conversions from bridged Objective-C classes (NSString/NSArray/NSDictionary) to their corresponding Swift value types (String/Array/Dictionary) have been removed, making the Swift type system simpler and more predictable.

    The problem in your case are the CFStrings like kCGImageSourceThumbnailMaxPixelSize. These are not automatically converted to String anymore.

    reference from HERE.