You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用UIImagePickerController为拍摄的照片设置位置信息

解决方案

一、保存相册图片时保留GPS元数据

直接保存UIImage对象会丢失EXIF元数据(包括GPS信息),因为UIImage仅存储像素数据,不包含图片的原始元数据。必须获取原始图片的完整数据(含元数据)再写入文件:

实现步骤(Swift)

  1. 通过info[UIImagePickerController.InfoKey.referenceURL]获取相册图片的Asset URL
  2. 借助PHAsset读取图片的原始数据与元数据
  3. 将带元数据的图片数据写入Documents文件夹
import Photos

func saveAlbumImageWithMetadata(info: [UIImagePickerController.InfoKey: Any]) {
    guard let assetURL = info[.referenceURL] as? URL else { return }
    let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [assetURL], options: nil)
    guard let asset = fetchResult.firstObject else { return }
    
    let options = PHImageRequestOptions()
    options.isSynchronous = true
    options.deliveryMode = .highQualityFormat
    options.version = .original
    
    PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options) { imageData, _, _, info in
        guard let data = imageData else { return }
        // 写入Documents目录
        let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let saveURL = docsDir.appendingPathComponent("saved_album_image.jpg")
        do {
            try data.write(to: saveURL)
        } catch {
            print("保存失败:\(error)")
        }
    }
}

二、为应用内拍摄的照片添加GPS位置信息

拍照后info[.referenceURL]为nil是因为照片尚未存入系统相册,需主动获取当前位置,将GPS信息写入图片的EXIF元数据后再保存:

实现步骤(Swift)

  1. 在Info.plist中添加位置权限描述(NSLocationWhenInUseUsageDescription)
  2. 获取当前经纬度坐标
  3. 将GPS信息转换为EXIF格式的元数据
  4. 合并图片数据与元数据后保存
import CoreLocation
import ImageIO

// 获取当前位置
func getCurrentLocation(completion: @escaping (CLLocationCoordinate2D?) -> Void) {
    let locationManager = CLLocationManager()
    locationManager.requestWhenInUseAuthorization()
    guard CLLocationManager.locationServicesEnabled() else {
        completion(nil)
        return
    }
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.delegate = self
    locationManager.requestLocation()
}

// 为图片添加GPS元数据
func addGPSMetadata(to imageData: Data, coordinate: CLLocationCoordinate2D) -> Data? {
    guard let source = CGImageSourceCreateWithData(imageData as CFData, nil),
          let uti = CGImageSourceGetType(source) else { return nil }
    
    let mutableData = NSMutableData(data: imageData)
    guard let destination = CGImageDestinationCreateWithData(mutableData, uti, 1, nil) else { return nil }
    
    // 获取原始元数据并注入GPS信息
    var metadata = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any] ?? [:]
    let gpsMetadata: [CFString: Any] = [
        kCGImagePropertyGPSLatitude: abs(coordinate.latitude),
        kCGImagePropertyGPSLatitudeRef: coordinate.latitude >= 0 ? "N" : "S",
        kCGImagePropertyGPSLongitude: abs(coordinate.longitude),
        kCGImagePropertyGPSLongitudeRef: coordinate.longitude >= 0 ? "E" : "W",
        kCGImagePropertyGPSTimeStamp: Date().iso8601String
    ]
    metadata[kCGImagePropertyGPSDictionary] = gpsMetadata
    
    // 写入带GPS元数据的图片
    CGImageDestinationAddImageFromSource(destination, source, 0, metadata as CFDictionary)
    return CGImageDestinationFinalize(destination) ? mutableData as Data : nil
}

// Date扩展:生成ISO8601格式时间字符串
extension Date {
    var iso8601String: String {
        let formatter = ISO8601DateFormatter()
        formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
        return formatter.string(from: self)
    }
}

// 保存拍摄的图片(在UIImagePickerControllerDelegate中调用)
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true)
    guard let image = info[.originalImage] as? UIImage,
          let imageData = image.jpegData(compressionQuality: 0.8) else { return }
    
    getCurrentLocation { coordinate in
        if let coord = coordinate, let dataWithGPS = self.addGPSMetadata(to: imageData, coordinate: coord) {
            self.saveImageToDocuments(data: dataWithGPS)
        } else {
            // 无位置权限时保存无GPS的图片
            self.saveImageToDocuments(data: imageData)
        }
    }
}

// 写入Documents目录
func saveImageToDocuments(data: Data) {
    let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let saveURL = docsDir.appendingPathComponent("captured_image.jpg")
    do {
        try data.write(to: saveURL)
    } catch {
        print("保存失败:\(error)")
    }
}

// 实现CLLocationManagerDelegate协议
extension YourViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.first else { return }
        manager.stopUpdatingLocation()
        // 此处可根据业务逻辑处理位置回调
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("获取位置失败:\(error)")
        manager.stopUpdatingLocation()
    }
}

注意事项

  • 位置权限需提前申请,Info.plist中必须添加对应权限描述,否则应用会崩溃
  • 若需将带GPS的拍摄图片存入系统相册,可改用PHPhotoLibrary写入带元数据的图片数据

内容的提问来源于stack exchange,提问作者Akhileshwar Babu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 07:31:17