将 EXIF 数据保存为 JPEG - Swift

Posted

技术标签:

【中文标题】将 EXIF 数据保存为 JPEG - Swift【英文标题】:Saving EXIF data to JPEG - Swift 【发布时间】:2018-10-15 06:26:34 【问题描述】:

我目前正在尝试使用 UIImagePickerController 在应用程序中拍摄照片,将它们保存到本地数据库并稍后将它们上传到服务。

但元数据(尤其是 EXIF)似乎没有自动与此图像捆绑在一起。我试着像这样提取它:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
 
    self.imageDelegate?.saveImage( image: info[UIImagePickerControllerOriginalImage] as! UIImage, metadata: (info[UIImagePickerControllerMediaMetadata] as? NSDictionary)! ) 
    // ...

现在我应该拥有图像和元数据,但是如何将其存储到 JPEG 文件中?我需要服务器上图像中的 GPS 数据。

我目前正在直接从相机胶卷中的 UImage 创建图像:

UIImageJPEGRepresentation(image,CGFloat(Constants.JPEG_QUALITY))

这将被存储和上传。

我读到有可能使用“CGImageDestination”,但我不知道如何在我的情况下使用它们。

【问题讨论】:

【参考方案1】:

我的解决方案:

func toJpegWithExif(image: UIImage, metadata: NSDictionary, location: CLLocation?) -> Data? 
    return autoreleasepool(invoking:  () -> Data in
        let data = NSMutableData()
        let options = metadata.mutableCopy() as! NSMutableDictionary
        options[ kCGImageDestinationLossyCompressionQuality ] = CGFloat(Constants.JPEG_QUALITY)

        // if location is available, add GPS data, thanks to https://gist.github.com/nitrag/343fe13f01bb0ef3692f2ae2dfe33e86
        if ( nil != location ) 
            let gpsData = NSMutableDictionary()

            let altitudeRef = Int(location!.altitude < 0.0 ? 1 : 0)
            let latitudeRef = location!.coordinate.latitude < 0.0 ? "S" : "N"
            let longitudeRef = location!.coordinate.longitude < 0.0 ? "W" : "E"

            // GPS metadata
            gpsData[(kCGImagePropertyGPSLatitude as String)] = abs(location!.coordinate.latitude)
            gpsData[(kCGImagePropertyGPSLongitude as String)] = abs(location!.coordinate.longitude)
            gpsData[(kCGImagePropertyGPSLatitudeRef as String)] = latitudeRef
            gpsData[(kCGImagePropertyGPSLongitudeRef as String)] = longitudeRef
            gpsData[(kCGImagePropertyGPSAltitude as String)] = Int(abs(location!.altitude))
            gpsData[(kCGImagePropertyGPSAltitudeRef as String)] = altitudeRef
            gpsData[(kCGImagePropertyGPSTimeStamp as String)] = location!.timestamp.isoTime()
            gpsData[(kCGImagePropertyGPSDateStamp as String)] = location!.timestamp.isoDate()
            gpsData[(kCGImagePropertyGPSVersion as String)] = "2.2.0.0"

            options[ kCGImagePropertyGPSDictionary as String ] = gpsData
        

        let imageDestinationRef = CGImageDestinationCreateWithData(data as CFMutableData, kUTTypeJPEG, 1, nil)!
        CGImageDestinationAddImage(imageDestinationRef, image.cgImage!, options)
        CGImageDestinationFinalize(imageDestinationRef)
        return data as Data
    )


extension Date 

    func isoDate() -> String 
        let f = DateFormatter()
        f.timeZone = TimeZone(abbreviation: "UTC")
        f.dateFormat = "yyyy:MM:dd"
        return f.string(from: self)
    

    func isoTime() -> String 
        let f = DateFormatter()
        f.timeZone = TimeZone(abbreviation: "UTC")
        f.dateFormat = "HH:mm:ss.SSSSSS"
        return f.string(from: self)
    

该方法将 UIImage 转换为 Jpeg,其中包含来自相机的 EXIF 数据以及来自 CLLocationManager 的可选 GPS 位置。

【讨论】:

以上是关于将 EXIF 数据保存为 JPEG - Swift的主要内容,如果未能解决你的问题,请参考以下文章

如何在不丢失 exif 数据的情况下将 UIImage 转换为 JPEG?

使用 libexif 将 exif 数据写入 jpg

JS 客户端 Exif 方向:旋转和镜像 JPEG 图像

如何将 EXIF/其他元数据插入存储在内存缓冲区中的 JPEG 中?

设置 Android 照片 EXIF 方向

使用 libexif 和 libjpeg 在现有 JPEG 上设置 exif 标签