How do I save custom metadata in an image when i get the image using the AVFoundation framework
?
I know I can access the properties weather it I have my
UIImage
and CIImage
don't hold all the metadata. In fact, converting it from NSData
to either of those two formats will strip a lot of that metadata out, so IMHO, UIImage
and CIImage
should only be used if you are planning on displaying it in the UI or passing it to CoreImage.
You can read the image properties like this:
- (NSDictionary *)getImageProperties:(NSData *)imageData {
// get the original image metadata
CGImageSourceRef imageSourceRef = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL);
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSourceRef, 0, NULL);
NSDictionary *props = (__bridge_transfer NSDictionary *) properties;
CFRelease(imageSourceRef);
return props;
}
You can then convert your NSDictionary
to a NSMutableDictionary
:
NSDictionary *props = [self getImageProperties:imageData];
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:props];
After that, add whatever fields you would like. Note that EXIF data is found by grabbing the kCGImagePropertyExifDictionary
, GPS data by the kCGImagePropertyGPSDictionary
, and so on:
NSMutableDictionary *exifDictionary = properties[(__bridge NSString *) kCGImagePropertyExifDictionary];
Look at the CGImageProperties
header file for all the keys available.
Okay, so now that you have made whatever changes you needed to the metadata, adding it back takes a couple of more steps:
// incoming image data
NSData *imageData;
// create the image ref
CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef) imageData);
CGImageRef imageRef = CGImageCreateWithJPEGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);
// the updated properties from above
NSMutableDictionary *mutableDictionary;
// create the new output data
CFMutableDataRef newImageData = CFDataCreateMutable(NULL, 0);
// my code assumes JPEG type since the input is from the iOS device camera
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef) @"image/jpg", kUTTypeImage);
// create the destination
CGImageDestinationRef destination = CGImageDestinationCreateWithData(newImageData, type, 1, NULL);
// add the image to the destination
CGImageDestinationAddImage(destination, imageRef, (__bridge CFDictionaryRef) mutableDictionary);
// finalize the write
CGImageDestinationFinalize(destination);
// memory cleanup
CGDataProviderRelease(imgDataProvider);
CGImageRelease(imageRef);
CFRelease(type);
CFRelease(destination);
// your new image data
NSData *newImage = (__bridge_transfer NSData *)newImageData;
And there you have it.