Для тех, кто приезжает сюда, пытаясь сделать снимок с помощью камеры в вашем приложении и сохранить файл изображения в рулон камеры с метаданными GPS, у меня есть Swift решение , которое использует Фотографии API , поскольку ALAssetsLibrary устарело с iOS 9.0 .
Как уже упоминал Рикстер в этом ответе , API фотографий не встраивает данные о местоположении непосредственно в файл изображения JPG, даже если вы задали свойство .location для нового ресурса.
С учетом буфера семплов CMSampleBuffer buffer
, некоторого CLLocation location
и использования предложения Морти для использования CMSetAttachments
во избежание дублирования изображения, мы можем сделать следующее. gpsMetadata
метод, расширяющий CLLocation, можно найти здесь .
if let location = location {
// Get the existing metadata dictionary (if there is one)
var metaDict = CMCopyDictionaryOfAttachments(nil, buffer, kCMAttachmentMode_ShouldPropagate) as? Dictionary<String, Any> ?? [:]
// Append the GPS metadata to the existing metadata
metaDict[kCGImagePropertyGPSDictionary as String] = location.gpsMetadata()
// Save the new metadata back to the buffer without duplicating any data
CMSetAttachments(buffer, metaDict as CFDictionary, kCMAttachmentMode_ShouldPropagate)
}
// Get JPG image Data from the buffer
guard let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer) else {
// There was a problem; handle it here
}
// Now save this image to the Camera Roll (will save with GPS metadata embedded in the file)
self.savePhoto(withData: imageData, completion: completion)
Метод savePhoto
приведен ниже. Обратите внимание, что удобный метод addResource:with:data:options
доступен только в iOS 9. Если вы поддерживаете более раннюю iOS и хотите использовать API Photos, то вы должны создать временный файл и затем создать ресурс из файла по этому URL, если вы хотите, чтобы метаданные GPS были правильно внедрены (PHAssetChangeRequest.creationRequestForAssetFromImage:atFileURL
). Только установка .location PHAsset НЕ будет встраивать ваши новые метаданные в сам файл.
func savePhoto(withData data: Data, completion: (() -> Void)? = nil) {
// Note that using the Photos API .location property on a request does NOT embed GPS metadata into the image file itself
PHPhotoLibrary.shared().performChanges({
if #available(iOS 9.0, *) {
// For iOS 9+ we can skip the temporary file step and write the image data from the buffer directly to an asset
let request = PHAssetCreationRequest.forAsset()
request.addResource(with: PHAssetResourceType.photo, data: data, options: nil)
request.creationDate = Date()
} else {
// Fallback on earlier versions; write a temporary file and then add this file to the Camera Roll using the Photos API
let tmpURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent("tempPhoto").appendingPathExtension("jpg")
do {
try data.write(to: tmpURL)
let request = PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: tmpURL)
request?.creationDate = Date()
} catch {
// Error writing the data; photo is not appended to the camera roll
}
}
}, completionHandler: { _ in
DispatchQueue.main.async {
completion?()
}
})
}
Кроме:
Если вы просто хотите сохранить изображение с метаданными GPS во временные файлы или документы (в отличие от фотопленки / библиотеки фотографий), вы можете пропустить это с помощью API Фото и напрямую записать imageData в URL.
// Write photo to temporary files with the GPS metadata embedded in the file
let tmpURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent("tempPhoto").appendingPathExtension("jpg")
do {
try data.write(to: tmpURL)
// Do more work here...
} catch {
// Error writing the data; handle it here
}