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
相关产品推荐
相关产品推荐

