Cocoa: adding EXIF metadata to images
February 29th, 2008 (06:11 pm)
Greetings, this is my serious attempt at blogging. I have started to code Flickr Import as a part of learning Objective-C and Cocoa programming.
Flickr Import allows you to download images from Flickr into iPhoto. One of the nifty thing it does is to retain the TIFF and EXIF meta data. I will show you here, how Flickr Import does this.
First, add ApplicationServices.framework to your project and include the header file, thusly:
#include <ApplicationServices/ApplicationServices.h>
this gives you access to CGImageDestination and CGImageSource
You will then get a handle to the image source and create an destination handle thusly:
NSURL *file = [NSURL fileURLWithPath:@"/tmp/foo.jpg"];
CGImageSourceRef source = CGImageSourceCreateWithURL( (CFURLRef) file, NULL);
if (!source) {
NSLog(@"***Could not create image source *** %@", file);
return;
}
CFStringRef UTI = CGImageSourceGetType(source);
NSMutableData *data = [NSMutableData data];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)data,UTI,1,NULL);
if(!destination) {
NSLog(@"***Could not create image destination ***");
return;
}
To update any of the destination properties, first create mutable dictionary, which holds these values, as shown below:
NSMutableDictionary *exifDict = [NSMutableDictionary dictionary];
// aperture - using a float variable named aperture
[exifDict setValue: [NSNumber numberWithFloat: &aperture]
forKey: (NSString *) kCGImagePropertyExifApertureValue];
// shutter speed - using a float variable named shutterSpeed
[exifDict setValue: [NSNumber numberWithFloat: &shutterSpeed]
forKey: (NSString *) kCGImagePropertyExifShutterSpeedValue];
The destination properties (of type CFStringRef) are defined here.
A key-value pair of the destination property and desired value is used to update the metadata, via CGImageDestinationAddImageFromSource() call. Apple has documented all the 'key's that can be used, however, what is not mentioned in apple's documentation is the type of the 'value'. This is exhaustively documented in the specs and also here.
Once you have a mutable dictionary of destination property and value, you can update the image file:
NSMutableDictionary *metaData = [NSMutableDictionary dictionary];
[metaData setObject: exifDict forKey:(NSString *)kCGImagePropertyExifDictionary];
//add the image contained in the image source to the destination, overidding the old metadata with our modified metadata
CGImageDestinationAddImageFromSource(destination,source,0, (CFDictionaryRef) metaData);
//tell the destination to write the image data and metadata into our data object.
//It will return false if something goes wrong
BOOL success = NO;
success = CGImageDestinationFinalize(destination);
if(!success) {
NSLog(@"***Could not create data from image destination ***");
return;
}
//now we have the data ready to go, so do whatever you want with it
//here we just write it to disk at the same path we were passed
[data writeToFile:[self downloadPath] atomically:YES];
//cleanup
CFRelease(destination);
CFRelease(source);
If you wish to read the EXIF data, have a look at this blog entry
Comments and corrections are welcome.




