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

iOS 17下使用PHPicker获取图片GPS位置失败求助

iOS 17(Xcode 15)下PHPicker获取图片GPS位置失败问题

在iOS 17(Xcode 15)环境中,使用PHPicker从相册选取图片后,无法获取其GPS位置数据,kCGImagePropertyGPSDictionary始终返回nil。但图片的Exif元数据存在,且相册应用中能看到该图片的位置信息。

尝试的代码

import UIKit
import CoreLocation
import MobileCoreServices
import PhotosUI
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    @IBOutlet weak var selectedImageView:UIImageView!
    @IBAction func selectTheImage() {
        self.pickImageFromLibrary_PH()
    }
    func pickImageFromLibrary_PH() {
        var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
        configuration.filter = .images
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        present(picker, animated: true, completion: nil)
    }
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        if let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {
            itemProvider.loadObject(ofClass: UIImage.self) { (image, error) in
                if let image = image as? UIImage {
                    self.fetchLocation(for: image)
                }
            }
        }
        picker.dismiss(animated: true, completion: nil)
    }
    func fetchLocation(for image: UIImage) {
        let locationManager = CLLocationManager()
        guard let imageData = image.jpegData(compressionQuality: 1.0) else {
            print("Unable to fetch image data.")
            return
        }
        guard let source = CGImageSourceCreateWithData(imageData as CFData, nil) else {
            print("Unable to create image source.")
            return
        }
        guard let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [String: Any] else {
            print("Unable to fetch image properties.")
            return
        }
        print(properties)
        if let gpsInfo = properties[kCGImagePropertyGPSDictionary as String] as? [String: Any],
           let latitude = gpsInfo[kCGImagePropertyGPSLatitude as String] as? CLLocationDegrees,
           let longitude = gpsInfo[kCGImagePropertyGPSLongitude as String] as? CLLocationDegrees {
            let location = CLLocation(latitude: latitude, longitude: longitude)
            print("Image was taken at \(location.coordinate.latitude), \(location.coordinate.longitude)")
        } else {
            print("PHPicker- Location information not found in the image.")
        }
    }
}

图片现有属性输出

["ProfileName": Display P3, "{Exif}": {
    ColorSpace = 65535;
    PixelXDimension = 4032;
    PixelYDimension = 3024;
}, "DPIWidth": 72, "Depth": 8, "PixelHeight": 3024, "ColorModel": RGB, "DPIHeight": 72, "{TIFF}": {
    Orientation = 1;
    ResolutionUnit = 2;
    XResolution = 72;
    YResolution = 72;
}, "PixelWidth": 4032, "Orientation": 1, "{JFIF}": {
    DensityUnit = 0;
    JFIFVersion =     (
        1,
        0,
        1
    );
    XDensity = 72;
    YDensity = 72;
}]

问题原因

核心问题在于通过loadObject(ofClass: UIImage.self)获取的UIImage对象不包含完整的GPS元数据:

  • UIImage仅存储图像像素数据和基础显示相关的元数据,会丢弃GPS这类额外的Exif信息;
  • 后续将UIImage转成jpegData时,生成的是新的图像数据,仅包含基础Exif,原始的GPS信息已经丢失;
  • 相册能显示位置,是因为系统直接从PHAsset的数据库记录中读取位置,而非从图片文件的元数据中获取。

解决方案

方案1:加载原始图片数据获取GPS元数据

直接加载图片的原始数据(而非转成UIImage),从原始数据中读取完整的元数据:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    guard let result = results.first else {
        picker.dismiss(animated: true)
        return
    }
    
    // 加载原始图片数据,保留完整元数据
    if result.itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
        result.itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { data, error in
            guard let data = data, error == nil else {
                print("加载图片数据失败: \(error?.localizedDescription ?? "未知错误")")
                return
            }
            self.fetchLocation(from: data)
            // 转UIImage用于显示
            if let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self.selectedImageView.image = image
                }
            }
        }
    }
    
    picker.dismiss(animated: true, completion: nil)
}

func fetchLocation(from data: Data) {
    guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
        print("无法创建图片源")
        return
    }
    guard let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [String: Any] else {
        print("无法获取图片属性")
        return
    }
    print(properties)
    
    if let gpsInfo = properties[kCGImagePropertyGPSDictionary as String] as? [String: Any],
       let latitude = gpsInfo[kCGImagePropertyGPSLatitude as String] as? Double,
       let latitudeRef = gpsInfo[kCGImagePropertyGPSLatitudeRef as String] as? String,
       let longitude = gpsInfo[kCGImagePropertyGPSLongitude as String] as? Double,
       let longitudeRef = gpsInfo[kCGImagePropertyGPSLongitudeRef as String] as? String {
        
        // 转换GPS的南北纬、东西经
        let convertedLatitude = latitudeRef == "N" ? latitude : -latitude
        let convertedLongitude = longitudeRef == "E" ? longitude : -longitude
        
        let location = CLLocation(latitude: convertedLatitude, longitude: convertedLongitude)
        print("图片拍摄位置: \(location.coordinate.latitude), \(location.coordinate.longitude)")
    } else {
        print("未找到GPS位置信息")
    }
}

方案2:通过PHAsset直接获取位置

利用PHPicker返回的assetIdentifier获取PHAsset,直接读取其location属性,更简洁:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    guard let result = results.first, let assetId = result.assetIdentifier else {
        picker.dismiss(animated: true)
        return
    }
    
    // 通过assetIdentifier获取PHAsset
    let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil)
    if let asset = fetchResult.firstObject {
        // 直接读取PHAsset的位置
        if let location = asset.location {
            print("图片拍摄位置: \(location.coordinate.latitude), \(location.coordinate.longitude)")
        } else {
            print("PHAsset中无位置信息")
        }
        
        // 加载图片用于显示
        let options = PHImageRequestOptions()
        options.deliveryMode = .highQualityFormat
        PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: 300, height: 300), contentMode: .aspectFit, options: options) { image, info in
            DispatchQueue.main.async {
                self.selectedImageView.image = image
            }
        }
    }
    
    picker.dismiss(animated: true, completion: nil)
}

内容的提问来源于stack exchange,提问作者Ramprasath Selvam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 01:57:43