Search code examples
iosswiftgpsuiimagepickercontrollerexif

How to Add Properties For Image UIImagePicker Swift 4


I want to capture an image and add properties longitude and latitude, i tried several times every example available on StackOverflow but doesn't work. I use UIImagePickerController to capture image and UIImageWriteToSavedPhotosAlbum to save data to album

The property must look like this

enter image description here

But now my image looks like this below

enter image description here


Solution

  • I don't know about what you have tried so far and what is your requirement but according to your question here is an example of setting the location to image metadata.

    After capturing the image:

    /// This is Mohali location for example
    let location = CLLocation(latitude: 30.7046, longitude: 76.7179)
    
    /// It will return image metaData including location
    let metaData = self.addLocation(location, toImage: image)
    
    /// Saving the image to gallery
    self.saveImage(image, withMetadata: metaData)
    

    And here is all required methods:

    func addLocation(_ location: CLLocation, toImage image: UIImage) -> Dictionary<String, Any> {
    
        /// Initializing the metaData dict
        var metaData: Dictionary<String, Any> = [:]
    
        /// Check if image already have its meta data
        if let ciImage = image.ciImage {
            metaData = ciImage.properties
        }
    
        /// Initializing the gpsData dict
        var gpsData: Dictionary<String, Any> = [:]
    
        /// Check if there is any gps information
        if let gps = metaData[kCGImagePropertyGPSDictionary as String] as? Dictionary<String, Any> {
            gpsData = gps
        }
    
        /// Adding all the required information to gpsData dictionary
        // #1. Data & Time
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy:MM:dd HH:mm:ss"
        let localDate = dateFormatter.string(from: location.timestamp)
        gpsData[kCGImagePropertyGPSTimeStamp as String] = localDate
    
        // #2. Latitude, Longitude
        var latitude  = location.coordinate.latitude
        var longitude = location.coordinate.longitude
        var latRef = ""
        var lngRef = ""
        if latitude < 0.0 {
            latitude *= -1.0
            latRef = "S"
        } else  {
            latRef = "N"
        }
    
        if longitude < 0.0 {
            longitude *= -1.0
            lngRef = "W"
        }
        else {
            lngRef = "E"
        }
    
        gpsData[kCGImagePropertyGPSLatitudeRef as String] = latRef
        gpsData[kCGImagePropertyGPSLongitudeRef as String] = lngRef
        gpsData[kCGImagePropertyGPSLatitude as String] = latitude
        gpsData[kCGImagePropertyGPSLongitude as String] = longitude
    
        // #3. Accuracy
        gpsData[kCGImagePropertyGPSDOP as String] = location.horizontalAccuracy
    
        // #4. Altitude
        gpsData[kCGImagePropertyGPSAltitude as String] = location.altitude
    
        /// You can add what more you want to add into gpsData and after that
        /// Add this gpsData information into metaData dictionary
        metaData[kCGImagePropertyGPSDictionary as String] = gpsData
    
        return metaData
    }
    
    func saveImage(_ image:UIImage, withMetadata metaData: Dictionary<String, Any>) {
        /// Creating jpgData from UIImage (1 = original quality)
        guard let jpgData = UIImageJPEGRepresentation(image, 1) else { return }
    
        /// Adding metaData to jpgData
        guard let source = CGImageSourceCreateWithData(jpgData as CFData, nil), let uniformTypeIdentifier = CGImageSourceGetType(source) else {
            return
        }
    
        let finalData = NSMutableData(data: jpgData)
        guard let destination = CGImageDestinationCreateWithData(finalData, uniformTypeIdentifier, 1, nil) else { return }
        CGImageDestinationAddImageFromSource(destination, source, 0, metaData as CFDictionary)
        guard CGImageDestinationFinalize(destination) else { return }
    
        /// Your destination file path
        let filePath = "\(documentsDicrectoryPath)/finalImage.jpg"
    
        /// Now write this image to directory
        if FileManager.default.fileExists(atPath: filePath) {
            try? FileManager.default.removeItem(atPath: filePath)
        }
    
        let success = FileManager.default.createFile(atPath: filePath, contents: finalData as Data, attributes: [FileAttributeKey.protectionKey : FileProtectionType.complete])
        if success {
            /// Finally Save image to Gallery
            /// Important you need PhotoGallery permission before performing below operation.
            try? PHPhotoLibrary.shared().performChangesAndWait {
                PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: URL(fileURLWithPath: filePath))
            }
        }
    }
    

    Below is the difference b/w normal and gps data image while viewing in PhotoGallery:

    Before After

    And in documentsDirectory if you see the image info it will look like:

    Image Get Info in documents directory