9

Info: Using Swift and the CGImageSourceCreateWithURL function.

I am attempting to load a file from a URL and then edit a dictionary which has all the data from that particular photo.

This is the code from the .swift file.

    let url = NSURL(string: "http://jwphotographic.co.uk/Images/1.jpg")
    let imageSource = CGImageSourceCreateWithURL(url, nil)
    let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as Dictionary

    println(imageProperties)

    //this is an example
    let aperture = imageProperties[kCGImagePropertyGPSLatitude] as! NSNumber!

    /*
    //these are all being defined as nil
    //Load the ones from the exif data of the file
    let lensUsed = imageProperties[kCGImagePropertyExifFocalLength]
    let aperture = imageProperties[kCGImagePropertyExifApertureValue] as!
    let isoSpeed = imageProperties[kCGImagePropertyExifISOSpeedRatings] as! NSNumber
    let latitude = imageProperties[kCGImagePropertyGPSLatitude] as! NSNumber
    let longitude = imageProperties[kCGImagePropertyGPSLongitude] as! NSNumber
    let shutterSpeed = imageProperties[kCGImagePropertyExifShutterSpeedValue] as! NSNumber
    let cameraName = imageProperties[kCGImagePropertyExifBodySerialNumber] as! NSNumber
    */

    println(aperture)

Even though image properties prints all the data as would be expected, no-matter what I have attmpted to extract from the imageProperties dictionary - it is always returned as null - such as 'aperture' in the example. The imageProperties prints as;

[{TIFF}: {
     Artist = JOHN;
     Copyright = "johnrwatson0@gmail.com";
     DateTime = "2015:07:31 21:07:05";
     Make = Canon;
     Model = "Canon EOS 7D Mark II";
     ResolutionUnit = 2;
     Software = "Adobe Photoshop Lightroom 6.0 (Macintosh)";
     XResolution = 72;
     YResolution = 72;
}, {IPTC}: {
     Byline =     (
       JOHN
     );
     CopyrightNotice = etc.. etc..

I have done a lot of research and testing and I simply cannot work out what I'm doing wrong to access the elements in this dictionary - Could someone give me an example how I would set a variable as the "Model" element inside the dictionary?

Cœur
  • 37,241
  • 25
  • 195
  • 267
user3423554
  • 101
  • 1
  • 1
  • 3

4 Answers4

14

In Swift 3.0 I found the following solution

let url = NSURL(string: "http://jwphotographic.co.uk/Images/1.jpg")
let imageSource = CGImageSourceCreateWithURL(url, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as Dictionary?
let exifDict = imageProperties?[kCGImagePropertyExifDictionary]

Now you can access the exif-Tags by for example

let dateTimeOriginal = exifDict?[kCGImagePropertyExifDateTimeOriginal]
Swift.print("dateTimeOriginal: \(dateTimeOriginal)")

You will get optional values and you have to test, if there are values or nil. For a list of available property constants look at the apple documentation.

Erich Kuester
  • 460
  • 4
  • 11
11

To get to Exif parameters do the following:

    let filePath_ = "file:///Users/pfernandes/Documents/softwareDevelopment/PhotoLine/TestData/IMG_1243.JPG"
    let fileURL = NSURL(string:filePath_)
    let myImage = CGImageSourceCreateWithURL(fileURL!,nil)

    let imageDict = CGImageSourceCopyPropertiesAtIndex(myImage!, 0, nil)! as NSDictionary;
    let tiffModel_ = imageDict.value(forKey: "{TIFF}")

    let cameraMake = (tiffModel_ as AnyObject).value(forKey: kCGImagePropertyTIFFMake as String)
    let cameraModel = (tiffModel_ as AnyObject).value(forKey: kCGImagePropertyTIFFModel as String)

    let exifDict_ = imageDict.value(forKey: "{Exif}") as! NSDictionary
    let dateTimeOriginal = exifDict_.value(forKey:kCGImagePropertyExifDateTimeOriginal as String) as! NSString
    let exposure         = exifDict_.value(forKey:kCGImagePropertyExifExposureTime as String)

    print ("\(String(describing: cameraMake)) \(String(describing: cameraModel)) \(dateTimeOriginal) \(exposure!)")
Cortex
  • 2,300
  • 2
  • 15
  • 14
1

This code will help you to obtain the date of the photo and exif

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true, completion: nil)
    if let image = info[.originalImage] as? UIImage {
        
       
        let assetURL = info[UIImagePickerController.InfoKey.referenceURL] as! NSURL
        let asset = PHAsset.fetchAssets(withALAssetURLs: [assetURL as URL], options: nil)
        guard let result = asset.firstObject else {
            return
        }

        let imageManager = PHImageManager.default()
        imageManager.requestImageData(for: result , options: nil, resultHandler:{
            (data, responseString, imageOriet, info) -> Void in
            let imageData: NSData = data! as NSData
            if let imageSource = CGImageSourceCreateWithData(imageData, nil) {
                let imageDict = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)! as NSDictionary
                let exifDict_ = imageDict.value(forKey: "{Exif}") as! NSDictionary
                   let dateTimeOriginal = exifDict_.value(forKey:kCGImagePropertyExifDateTimeOriginal as String) as! NSString
               print (" exifDict : \(exifDict_)")
                print (" fecha : original \(dateTimeOriginal)")
            }
        })
        
    picker.dismiss(animated: true, completion: nil)
}
0

Here is a sample code that helps us in reading the entire imageMetadata and converts it into dictionary format.

        guard let imageSource = CGImageSourceCreateWithURL(fileURL as CFURL, nil),
              let metadata = CGImageSourceCopyMetadataAtIndex(imageSource, 0, nil),
              let tags = CGImageMetadataCopyTags(metadata),
              let imageInfo = self.readMetadataTagArr(tagArr: tags) else { return }

Then there are a few helper functions that actually do all the hardwork to extract/convert the data into dictionary format.

    /// Reads the Arrays of tags and convert them into a dictionary of [String: Any]
private static func readMetadataTagArr(tagArr: CFArray) -> [String: Any]? {
    var result = [String: Any]()
    for (_, tag) in (tagArr as NSArray).enumerated() {
        let tagMetadata = tag as! CGImageMetadataTag
        if let cfName = CGImageMetadataTagCopyName(tagMetadata) {
            let name = String(cfName)
            result[name] = self.readMetadataTag(metadataTag: tagMetadata)
        }
    }
    return result
}

    /// convert CGImageMetadataTag to a dictionary of [String: Any]
private static func readMetadataTag(metadataTag: CGImageMetadataTag) -> [String: Any] {
    var result = [String: Any]()
    guard let cfName = CGImageMetadataTagCopyName(metadataTag) else { return result }
    let name = String(cfName)
    let value = CGImageMetadataTagCopyValue(metadataTag)
    
    /// checking the type of `value` object and then performing respective operation on `value`
    if CFGetTypeID(value) == CFStringGetTypeID() {
        let valueStr = String(value as! CFString)
        result[name] = valueStr
    } else if CFGetTypeID(value) == CFDictionaryGetTypeID() {
        let nsDict: NSDictionary = value as! CFDictionary
        result[name] = self.getDictionary(from: nsDict)
    } else if CFGetTypeID(value) == CFArrayGetTypeID() {
        let valueArr: NSArray = value as! CFArray
        for (_, item) in valueArr.enumerated() {
            let tagMetadata = item as! CGImageMetadataTag
            result[name] = self.readMetadataTag(metadataTag: tagMetadata)
        }
    } else {
        // when the data was of some other type
        let descriptionString: CFString = CFCopyDescription(value);
        let str = String(descriptionString)
        result[name] = str
    }
    return result
}

    /// Converting CGImage Metadata dictionary to [String: Any]
private static func getDictionary(from nsDict: NSDictionary) -> [String: Any] {
    var subDictionary = [String: Any]()
    for (key, val) in nsDict {
        guard let key = key as? String else { continue }
        let tempDict: [String: Any] = [key: val]
        if JSONSerialization.isValidJSONObject(tempDict) {
            subDictionary[key] = val
        } else {
            let mData = val as! CGImageMetadataTag
            let tempDict: [String: Any] = [key: self.readMetadataTag(metadataTag: mData)]
            if JSONSerialization.isValidJSONObject(tempDict) {
                subDictionary[key] = tempDict
            }
        }
    }
    return subDictionary
}

Here is the list of all dictionary keys extracted Here is the list of all dictionary keys extracted

Here are some sample dictionary values Here are some sample dictionary values

Hassaan Fayyaz
  • 189
  • 1
  • 4