如何在不丢失元数据/EXIF的情况下压缩图片数据(SwiftUI)
解决SwiftUI图片压缩时保留EXIF元数据的问题
核心方案:使用ImageIO框架直接处理原始图片数据
UIImage初始化时会自动丢弃EXIF等元数据,因此必须绕开它,直接用ImageIO框架操作原始图片数据流,实现压缩同时完整保留元数据。
具体实现步骤
- 从原始图片Data中提取完整元数据(包括EXIF)
- 基于原始元数据进行图片压缩,通过动态调整压缩质量确保文件大小不超过1MB
完整代码实现
import ImageIO import MobileCoreServices func compressImageWithMetadata(originalData: Data, targetMaxSize: Int = 1024 * 1024) -> Data? { // 创建图片源 guard let source = CGImageSourceCreateWithData(originalData as CFData, nil) else { return nil } // 获取原始图片的元数据(含EXIF) let sourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary guard let metadata = CGImageSourceCopyPropertiesAtIndex(source, 0, sourceOptions) as? [CFString: Any] else { return nil } // 创建内存输出流 let mutableData = NSMutableData() guard let destination = CGImageDestinationCreateWithData(mutableData, kUTTypeJPEG, 1, nil) else { return nil } // 从高质量开始循环尝试压缩,直到满足大小要求 var compressionQuality: CGFloat = 0.9 let qualityStep: CGFloat = 0.1 var resultData: Data? = nil while compressionQuality >= 0.1 { mutableData.length = 0 // 重置输出流 // 配置压缩选项:保留元数据+当前压缩质量 let destOptions: [CFString: Any] = [ kCGImageDestinationLossyCompressionQuality: compressionQuality, kCGImageDestinationMetadata: metadata ] // 写入压缩后的图片 CGImageDestinationAddImageFromSource(destination, source, 0, destOptions as CFDictionary) guard CGImageDestinationFinalize(destination) else { compressionQuality -= qualityStep continue } // 检查是否符合大小要求 if mutableData.length <= targetMaxSize { resultData = mutableData as Data break } compressionQuality -= qualityStep } return resultData }
结合SwiftUI PhotosPicker的使用示例
struct PhotoUploadView: View { @State private var selectedPhoto: PhotosPickerItem? @State private var compressedData: Data? var body: some View { PhotosPicker(selection: $selectedPhoto, matching: .images) { Text("选择相册照片") } .onChange(of: selectedPhoto) { _, newItem in Task { if let rawData = try? await newItem?.loadTransferable(type: Data.self) { // 压缩图片并保留元数据 compressedData = compressImageWithMetadata(originalData: rawData) // 此处将compressedData上传至服务器 } } } } }
补充说明
- 该代码默认针对JPEG格式压缩,如需处理HEIC等格式,只需将
kUTTypeJPEG替换为对应UTI(如kUTTypeHEIC) - 循环调整压缩质量是为了确保最终文件严格低于1MB,你可以根据需求调整质量步长或终止条件
- 若你能获取到
PHAsset实例,也可直接用PHImageManager请求指定尺寸的图片并保留元数据,但直接处理Data的方式更贴合你当前的流程
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

