Swift how to modify exif info in images taken from mobile camera

前端 未结 3 755
半阙折子戏
半阙折子戏 2020-12-08 23:47

I use UIImagePickerController to pick images in my iOS App and I know exif info can be got by info[UIImagePickerControllerMediaMetadata]. But when

相关标签:
3条回答
  • 2020-12-09 00:25

    Yes! Finally I made a trick to modify the EXIF info. At first, you can get EXIF info from info[UIImagePickerControllerMediaMetadata] and NSData without EXIF from picked UIImage by UIImageJPEGRepresentation. Then, you can create a new NSDictionary with modified EXIF info. After that, call my function in the following, you can get image NSData with modified EXIF!

    func saveImageWithImageData(data: NSData, properties: NSDictionary, completion: (data: NSData, path: NSURL) -> Void) {
    
        let imageRef: CGImageSourceRef = CGImageSourceCreateWithData((data as CFDataRef), nil)!
        let uti: CFString = CGImageSourceGetType(imageRef)!
        let dataWithEXIF: NSMutableData = NSMutableData(data: data)
        let destination: CGImageDestinationRef = CGImageDestinationCreateWithData((dataWithEXIF as CFMutableDataRef), uti, 1, nil)!
    
        CGImageDestinationAddImageFromSource(destination, imageRef, 0, (properties as CFDictionaryRef))
        CGImageDestinationFinalize(destination)
    
        var paths: [AnyObject] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        let savePath: String = paths[0].stringByAppendingPathComponent("exif.jpg")
    
        let manager: NSFileManager = NSFileManager.defaultManager()
        manager.createFileAtPath(savePath, contents: dataWithEXIF, attributes: nil)
    
        completion(data: dataWithEXIF,path: NSURL(string: savePath)!)
    
        print("image with EXIF info converting to NSData: Done! Ready to upload! ")
    
    }
    
    0 讨论(0)
  • 2020-12-09 00:30

    SWIFT 3

    In case you're capturing a video and getting the CMSampleBuffer there is a way to update the EXIF metadata. In my case in iOS9 I didn't get the DateTimeOriginal, though in iOS10 the DataTimeOriginal was already in. Thus I had to put few additional key-values in.

    self.stillCameraOutput.captureStillImageAsynchronously(from: connectionVideo) { (sampleBuffer, err) in
            if let err = err {
                blockCompletion(nil, err as NSError?)
            }
            else {
                if let sampleBuffer = sampleBuffer {
                    let rawMetadata = CMCopyDictionaryOfAttachments(nil, sampleBuffer, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate))
                    let metadata = CFDictionaryCreateMutableCopy(nil, 0, rawMetadata) as NSMutableDictionary
    
                    let exifData = metadata.value(forKey: "{Exif}") as? NSMutableDictionary
    
                    print("EXIF DATA: \(exifData)")
    
                    if let dateTime = exifData?["DateTimeOriginal"] as? String {
                        print("DateTime exists \(dateTime)")
                    }
                    else {
                        exifData?.setValue(Date().exifDate(), forKey: "DateTimeOriginal")
                    }
    
                    if let dateTime = exifData?["DateTimeDigitized"] as? String {
                        print("DateTime exists \(dateTime)")
                    }
                    else {
                        exifData?.setValue(Date().exifDate(), forKey: "DateTimeDigitized")
                    }
    
                    metadata.setValue(exifData, forKey: "{Exif}")
    
                    CMSetAttachments(sampleBuffer, metadata as CFDictionary, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate))
    
                    let rawMetadata2 = CMCopyDictionaryOfAttachments(nil, sampleBuffer, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate))
                    let metadata2 = CFDictionaryCreateMutableCopy(nil, 0, rawMetadata2) as NSMutableDictionary
    
                    let exifData2 = metadata2.value(forKey: "{Exif}") as? NSMutableDictionary
    
                    print("EXIF DATA: \(exifData2)")
    
                    if let dataImage = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) {
                        blockCompletion(dataImage, nil)
                    }
                    else {
                        blockCompletion(nil, nil)
                    }
                }
                else {
                    blockCompletion(nil, nil)
                }
            }
        }
    
    0 讨论(0)
  • 2020-12-09 00:45

    using and mergind some info from other posts, I approached problem using Dictionary in Swift. I used it in captureOutput of AVFounfation callback for AVCapturePhoto:

    func photoOutput(_ output: AVCapturePhotoOutput,
                     didFinishProcessingPhoto photo: AVCapturePhoto,
                     error: Error?) {
    
        //retrieve exif information
        var photoFormatDescription: CMFormatDescription?
        CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, photoPixelBuffer, &photoFormatDescription)
    
        var metadataAttachments: Dictionary = photo.metadata as Dictionary
    
        if var exifData = metadataAttachments["{Exif}"] as? [String: Any] {
            exifData[kCGImagePropertyExifUserComment as String] = "<whatever you want to write>"
    
        metadataAttachments[kCGImagePropertyExifDictionary as String] = exifData
        }
    
    }
    

    After that "metadataAttachments" is used to build final image (using CGImageDestinationAddImage in my case)

    It seems to work (tried in a project build with Swift 4.0)

    Hope it can help!

    0 讨论(0)
提交回复
热议问题