Location, or any metadata, can be saved in 2 places:
- In Photos app’s database
- In the jpg/heic/dng/mov files
You WILL have to do both for an iOS app, because if you don’t, then you will lose the information along the way eg importing.
TIP: Use exiftool -a -u -g1 filename.jpg
to examine the info.
1. Photos app’s database
Let’s start with the easy one.
PHAssetCreationRequest makes it very easy to add the location data to the database.
PHPhotoLibrary.shared().performChanges({
let creationRequest = PHAssetCreationRequest.forAsset()
creationRequest.location = latestLocation
creationRequest.addResource(with: .photo, data: photoData, options: options)
...
})
You can also set the creationDate
and isFavorite
.
The Problem
If you do (1), but not (2), then when the photo is imported into macOS/Windows, surprisingly, even using Apple’s Photo app, metadata will be lost.
When importing, only the metadata in the file is used.
So you need to write metadata to the file, and that is HARDER.
2. Writing metadata to file
If you are using AVFoundation to capture photo, then it is relatively easy. There is a variant of fileDataRepresentation
that can take in the metadata.
This is what you do in the AVCapturePhotoCaptureDelegate
method:
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
var metadata = photo.metadata
metadata[kCGImagePropertyGPSDictionary as String] = gpsMetadata
photoData = photo.fileDataRepresentation(withReplacementMetadata: metadata,
replacementEmbeddedThumbnailPhotoFormat: photo.embeddedThumbnailPhotoFormat,
replacementEmbeddedThumbnailPixelBuffer: nil,
replacementDepthData: photo.depthData)
...
}
With the photoData
, you can save to file or add to Photos using PHAssetCreationRequest
.
Using Image I/O and other frameworks
If you are not capturing photo using AVFoundation, then you don’t have the luxury of the above to get the fileDataRepresentation
along with the metadata.
In that case, you have to add metadata manually to the original image data.
Image I/O Framework provides methods to Modifying Image Metadata Without Recompressing Image (QA1895), using CGImageDestinationCopyImageSource
, which supports JPEG, PNG, PSD, TIFF.
The options_dict
in the sample code is the metadata dictionary.
Check out S/O answers like this or this (using Core Media).
Assets Library framework (deprecated) also has it’s own methods to Accessing Image Metadata in iOS (QA1622).
Metadata
Wonder what kind of structure is metadata
?
Metadata is a dictionary of dictionaries.
CGImageProperties has a reference to the dictionaries you can define. For example, GPS has it’s own dictionary keys, so does EXIF.
// gpsMetadata and exifMetadata are 2 dictionaries
metadata[kCGImagePropertyGPSDictionary as String] = gpsMetadata
metadata[kCGImagePropertyExifDictionary as String] = exifMetadata
There is a helper on turning CLLocation
into the GPS data in a dictionary.
A Swift extension is kindly available too.