I’m trying to modify the metadata contained in a JPEG image. It can be any of the metadata in the image, in my example I’m attempting to change to DateTimeDigitized
property to the current date.
My code seems to mostly work, however the set property is being removed rather than changed. I’m not certain why this is happening, can anyone tell me what I’m doing wrong?
I’d welcome any advice on frameworks that can help perform the task but I’d especially be interested in what I’m doing incorrectly with this approach.
I’m running this code in a Playground where the image named “foo.jpg” is stored in the path ~/Documents/Shared Playground Data/
.
import Foundation
import ImageIO // CGImage functions
import PlaygroundSupport
let ImagePropertyExifDictionary = kCGImagePropertyExifDictionary as String
let ImagePropertyExifDateTimeDigitized = kCGImagePropertyExifDateTimeDigitized as String
func updateEXIFDateDigitized() {
// Create URL for source and destination
let sourceURL = playgroundSharedDataDirectory.appendingPathComponent("foo.jpg") as CFURL
let destinationURL = playgroundSharedDataDirectory.appendingPathComponent("bar.jpg") as CFURL
// Read source and get properties
guard
let sourceRef = CGImageSourceCreateWithURL(sourceURL, nil),
var metadata = CGImageSourceCopyPropertiesAtIndex(sourceRef, 0, nil) as? [String:Any] else { return }
print("unmodified properties", metadata, separator:"\n")
// Modify EXIF DateTimeDigitized property
guard var exif = metadata[ImagePropertyExifDictionary] as? [String:Any] else { return }
exif[ImagePropertyExifDateTimeDigitized] = Date() as CFDate
metadata[ImagePropertyExifDictionary] = exif as CFDictionary
print("", "modified properties", metadata, separator:"\n")
// Set up destination
guard let destinationRef = CGImageDestinationCreateWithURL(destinationURL, kUTTypeJPEG, 1, nil) else { return }
// Add image from source to destination with new properties
CGImageDestinationAddImageFromSource(destinationRef, sourceRef, 0, metadata as CFDictionary)
// Save destination
guard CGImageDestinationFinalize(destinationRef) else { return }
guard
let sourceRef2 = CGImageSourceCreateWithURL(destinationURL, nil),
let metadata2 = CGImageSourceCopyPropertiesAtIndex(sourceRef2, 0, nil) else { return }
print("", "saved properties", metadata2, separator:"\n")
}
updateEXIFDateDigitized()
The relevant bits of the result, I removed the other fields for brevity:
unmodified properties
{
"{Exif}" = {
DateTimeDigitized = "2007:07:31 17:42:01";
DateTimeOriginal = "2007:07:31 17:42:01";
};
}
modified properties
{
"{Exif}" = {
DateTimeDigitized = "2017-05-11 15:45:38 +0000";
DateTimeOriginal = "2007:07:31 17:42:01";
};
}
saved properties
{
"{Exif}" = {
DateTimeOriginal = "2007:07:31 17:42:01";
};
}