skip to Main Content

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 = "[email protected]";
     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?

4

Answers


  1. 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!)")
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
  3. 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)
    }
    
    Login or Signup to reply.
  4. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search