ImageIO iPhone doesn't handle IPTCDictionary on write
Originator: | cgodefroy | ||
Number: | rdar://8204225 | Date Originated: | 2010/07/18 |
Status: | Closed | Resolved: | 2011-07 iOS 5 |
Product: | iOS | Product Version: | 4.0.1 |
Classification: | Serious Bug | Reproducible: | Always |
18-Jul-2010 10:21 AM Cyril Godefroy: Summary: Trying to edit and rewrite the IPTCDictionary with imageIO on the iPhone SDK 4.0.1 deletes the dictionary from the image. Seems only happening on jpeg files. Steps to Reproduce: --------------- Open a public.jpeg image with ImageIO Read the ExifDictionary read the GPSDictionary Read the IPTCDictionary Edit the info from these dictionaries Rewrite the dictionaries to the file Expected Results: -------------- The end file should contain IPTC info, for example Keywords Actual Results: ----------- Preview on the Mac doesn't display any IPTC info, nor keywords Notes: ------ I did try by putting a file with IPTC info in the shared document folder, editing it and saving it back: the destinationFile had no more IPTC Keywords. Another developer had the same kind of issues, and reported on Stack Overflow: http://stackoverflow.com/questions/3003036/ Here is the code, I also provide the full app. - (void)saveMetaData{ CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)[NSURL fileURLWithPath:[self filePath]], nil); //get all the metadata in the image NSDictionary *metadata = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL); //make the metadata dictionary mutable so we can add properties to it NSMutableDictionary *metadataAsMutable = [metadata mutableCopy]; [metadata release]; NSMutableDictionary *EXIFDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]autorelease]; if(!EXIFDictionary) { //if the image does not have an EXIF dictionary (not all images do), then create one for us to use EXIFDictionary = [NSMutableDictionary dictionary]; } //we need to format the date so it conforms to the EXIF spec and can be read by other apps NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init]; //the date format for EXIF dates as from http://www.abmt.unibas.ch/dokumente/ExIF.pdf [dateFormatter setDateFormat:@"yyyy:MM:dd HH:mm:ss"]; //use the date formatter to get a string from the date we were passed in the EXIF format NSString *EXIFFormattedCreatedDate = [dateFormatter stringFromDate:[self creationDate]]; [dateFormatter release]; [EXIFDictionary setObject:EXIFFormattedCreatedDate forKey:(NSString *)kCGImagePropertyExifDateTimeDigitized]; NSMutableDictionary *GPSDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary ]mutableCopy]autorelease]; if(!GPSDictionary){ GPSDictionary = [NSMutableDictionary dictionary]; } [GPSDictionary setObject:self.longitude forKey:(NSString *)kCGImagePropertyGPSLongitude]; [GPSDictionary setObject:self.latitude forKey:(NSString *)kCGImagePropertyGPSLatitude]; NSMutableDictionary *IPTCDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyIPTCDictionary ]mutableCopy]autorelease]; if(!IPTCDictionary){ IPTCDictionary = [NSMutableDictionary dictionary]; } if(self.name) [IPTCDictionary setObject:self.name forKey:(NSString *)kCGImagePropertyIPTCHeadline]; if(self.tags) [IPTCDictionary setObject:self.tags forKey:(NSString *)kCGImagePropertyIPTCKeywords]; //add our modified dictionaries data back into the image’s metadata [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary]; [metadataAsMutable setObject:IPTCDictionary forKey:(NSString *)kCGImagePropertyIPTCDictionary]; [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary]; CFStringRef UTI = CGImageSourceGetType(source); //this will be the data CGImageDestinationRef will write into NSMutableData *data = [NSMutableData data]; CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)data,UTI,1,NULL); if(!destination) { NSLog(@"***Could not create image destination ***"); return ; } //add the image contained in the image source to the destination, overidding the old metadata with our modified metadata CGImageDestinationAddImageFromSource(destination,source,0, (CFDictionaryRef) metadataAsMutable); //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 writeToURL:[NSURL fileURLWithPath:[self filePath]] atomically:YES]; //cleanup CFRelease(destination); CFRelease(source); } 18-Jul-2010 10:25 AM Cyril Godefroy: 'Archive-1.zip' was successfully uploaded ----------------- OpenRadar Note: Am I wrong in believing I should be able to write my iptc dict with this code? I have to admit, I'm an imageIO noob.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!
Don't make a copy
I had the same thing happen to me. Don't make a mutable copy for yourself. Edit the returned object directly (it's already mutable). Then you'll keep your changes as long as it's a metadata tag that's already supported. If you try to add one that's not supported (it's not documented which don't exist on iOS (see http://www.openradar.me/8569366)) it'll silently get thrown away.