Does it have to be so hard?
Are you writing a camera app or image editing app for iOS but are clueless on how to add geolocation to your pictures? Baffled by the lack of information in the otherwise very thorough XCode documentation? I feel your pain my friend. Or actually, felt, cause I got your meds right here.
When developing Snap I wanted to add this feature so that it could actually replace the built-in camera app. And since the built-in camera app adds geolocation, along with a lot of other metadata to the images, Snap had to do this too.
I present to you my NSMutableDictionary category that will solve all your problems. Ok, maybe not all, but the ones related to image metadata on iOS anyway.
For those with no patience, here’s the GitHub repo: https://github.com/gpambrozio/GusUtils. The repo contains an XCode project that should compile a nice static library for you to use on your projects. I plan on add a lot of utility classes here, so you might just want to pick and choose whatever you need to use instead of using the whole library.
The category is easy enough to use if you check out the code, but I’ll explain a few things on how to use it for those that never had to deal with image metadata on iOS before.
Who is this metadata person anyway?
For those of you that have no idea what I’m talking about, image metadata is most commonly known as EXIF data, even though that’s slightly wrong because EXIF data is only one type of metadata that can be embedded in an image file. My category deals with EXIF metadata, as well as with TIFF and IPTC metadata, depending on what kind of information you want to add to the image.
For example, the Original Date of an image can be embedded inside an EXIF property or inside a TIFF property. My category knows this and if you want to embed this date it will set both properties for you.
You can see all this metadata using most image viewers. On OSX, if you press cmd-i on the Preview app you can see an image’s metadata.
How does it work on iOS?
iOS SDK 4.1 introduced some methods that allowed an app to write image metadata in an image. One example is ALAssetsLibrary’s:
That takes a NSDictionary as the metadata source. What the documentation doesn’t explain (or at least I could not find) is how this dictionary should be. I googled a lot and found some examples online that I used as a starting point for the category (sorry, can’t remember most of them…).
Turns out that this dictionary consists of a lot of other NSDictionaries with key/values that are dependent on the type of metadata you’re adding. You can find all the dictionaries that go inside this dictionary (I know…. even I’m getting confused with so many dictionaries…) in the CGImageProperties Reference of the documentation.
I’ll try to explain with an example. Say you want to add a “Description” property in your image. This property sits inside the TIFF dictionary. So, in order to add this information to your metadata dictionary you can use this code:
NSMutableDictionary *tiffMetadata = [[NSMutableDictionary alloc] init]; [tiffMetadata setObject:@"This is my description" forKey:(NSString*)kCGImagePropertyTIFFImageDescription]; NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init]; [metadata setObject:tiffMetadata forKey:(NSString*)kCGImagePropertyTIFFDictionary];
Why am I using NSMutableDictionary? Well, in this example you really don’t have to, but say you want to add another TIFF property to your metadata, with NSMutableDictionary you can just add another key/value to the tiffMetadata dictionary. If you used NSDictionary you’d have to create a new NSDictionary with the old key/values plus the new key/value. Not cool….
Adding geolocation is even harder. Geolocation has it’s own dictionary with a lot of possible values that are NOT explained in the documentation. The best information I found about this was in this StackOverflow question that I used as the basis for my implementation.
Please, help, I don’t want to do this…
The NSMutableDDictionary+ImageMetadata category takes all this complexity away from your code. To add geolocation to your metadata dictionary, all you have to do is this:
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init]; [metadata setLocation:location];
Where location is a CLLocation instance. That’s it. My category will create the appropriate dictionary and add it to your NSMutableDictionary with all the appropriate key/values. I’ve implemented some other interesting setters and there are some helper methods that make it very easy to add methods for other properties:
- (void)setLocation:(CLLocation *)currentLocation; - (void)setUserComment:(NSString*)comment; - (void)setDateOriginal:(NSDate *)date; - (void)setDateDigitized:(NSDate *)date; - (void)setMake:(NSString*)make model:(NSString*)model software:(NSString*)software; - (void)setDescription:(NSString*)description; - (void)setKeywords:(NSString*)keywords; - (void)setImageOrientarion:(UIImageOrientation)orientation;
After setting all your properties, you can call ALAssetsLibrary’s – writeImageDataToSavedPhotosAlbum:metadata:completionBlock: or – writeImageToSavedPhotosAlbum:metadata:completionBlock:. using your very special NSMutableDictionary and you’re all set!
There’s another hard to find issue with metadata and that’s getting it from an image you just took using UIImagePickerController or an AVCaptureStillImageOutput. I’ll deal with this problem in another post but rest assured that out friendly category will help you a lot too. (UPDATE: The reading part in on this blog post)
Can I use this?
Yes, use it, fork it, spread the word. And if you make any improvements to your fork, or if you found a bug or a better way to do things, please send me a pull request so that I can incorporate your improvements into the main branch.
And if you really want t help me out and get a nice app at the same time, get Snap for your iPhone. Best 2 bucks you’ll spend today!