Note that there are some explanatory texts on larger screens.

plurals
  1. POModified EXIF data doesn't save properly
    text
    copied!<p>After countless attempts and sieving through every SO answer + google result, it baffles me that working with EXIF on iOS is so frustrating.</p> <p>Below is working code with its results.</p> <pre><code>[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) { NSData *imageNSData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; CGImageSourceRef imgSource = CGImageSourceCreateWithData((__bridge_retained CFDataRef)imageNSData, NULL); //get all the metadata in the image NSDictionary *metadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imgSource, 0, NULL); NSLog(@"original metadata Info: %@",metadata); //make the metadata dictionary mutable so we can add properties to it NSMutableDictionary *metadataAsMutable = [metadata mutableCopy]; NSMutableDictionary *EXIFDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]; NSMutableDictionary *GPSDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]; NSMutableDictionary *RAWDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyRawDictionary]mutableCopy]; if(!EXIFDictionary) EXIFDictionary = [[NSMutableDictionary dictionary] init]; if(!GPSDictionary) GPSDictionary = [[NSMutableDictionary dictionary] init]; if(!RAWDictionary) RAWDictionary = [[NSMutableDictionary dictionary] init]; [GPSDictionary setObject:@"camera coord Latitude" forKey:(NSString*)kCGImagePropertyGPSLatitude]; [GPSDictionary setObject:@"camera coord Longitude" forKey:(NSString*)kCGImagePropertyGPSLongitude]; [GPSDictionary setObject:@"camera GPS Date Stamp" forKey:(NSString*)kCGImagePropertyGPSDateStamp]; [GPSDictionary setObject:@"camera direction (heading) in degrees" forKey:(NSString*)kCGImagePropertyGPSImgDirection]; [GPSDictionary setObject:@"subject coord Latitude" forKey:(NSString*)kCGImagePropertyGPSDestLatitude]; [GPSDictionary setObject:@"subject coord Longitude" forKey:(NSString*)kCGImagePropertyGPSDestLongitude]; [EXIFDictionary setObject:@"[S.D.] kCGImagePropertyExifUserComment" forKey:(NSString *)kCGImagePropertyExifUserComment]; [EXIFDictionary setValue:@"69 m" forKey:(NSString *)kCGImagePropertyExifSubjectDistance]; //Add the modified Data back into the image’s metadata [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary]; [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary]; [metadataAsMutable setObject:RAWDictionary forKey:(NSString *)kCGImagePropertyRawDictionary]; NSLog(@"metadataAsMutable Info: %@",metadataAsMutable); CFStringRef UTI = CGImageSourceGetType(imgSource); //this is the type of image (e.g., public.jpeg) //this will be the data CGImageDestinationRef will write into NSMutableData *newImageData = [NSMutableData data]; CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)newImageData, UTI, 1, NULL); if(!destination) NSLog(@"***Could not create image destination ***"); //add the image contained in the image source to the destination, overidding the old metadata with our modified metadata CGImageDestinationAddImageFromSource(destination, imgSource, 0, (__bridge 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 ***"); CIImage *testImage = [CIImage imageWithData:newImageData]; NSDictionary *propDict = [testImage properties]; NSLog(@"Properties %@", propDict); }]; </code></pre> <p>Which outputs this:</p> <pre><code>2012-10-12 23:17:45.415 Waypointer[3120:907] original metadata Info: { ColorModel = RGB; DPIHeight = 72; DPIWidth = 72; Depth = 8; Orientation = 1; PixelHeight = 2448; PixelWidth = 3264; "{Exif}" = { ApertureValue = "2.526069"; BrightnessValue = "-4.410617"; ColorSpace = 1; ComponentsConfiguration = ( 1, 2, 3, 0 ); ExifVersion = ( 2, 2, 1 ); ExposureMode = 0; ExposureProgram = 2; ExposureTime = "0.06666667"; FNumber = "2.4"; Flash = 16; FlashPixVersion = ( 1, 0 ); FocalLenIn35mmFilm = 35; FocalLength = "4.28"; ISOSpeedRatings = ( 800 ); MeteringMode = 5; PixelXDimension = 3264; PixelYDimension = 2448; SceneCaptureType = 0; SensingMethod = 2; ShutterSpeedValue = "3.906905"; SubjectArea = ( 1631, 1223, 881, 881 ); WhiteBalance = 0; }; "{TIFF}" = { Orientation = 1; ResolutionUnit = 2; XResolution = 72; YResolution = 72; "_YCbCrPositioning" = 1; }; } </code></pre> <p>And this:</p> <pre><code>2012-10-12 23:17:45.421 Waypointer[3120:907] metadataAsMutable Info: { ColorModel = RGB; DPIHeight = 72; DPIWidth = 72; Depth = 8; Orientation = 1; PixelHeight = 2448; PixelWidth = 3264; "{Exif}" = { ApertureValue = "2.526069"; BrightnessValue = "-4.410617"; ColorSpace = 1; ComponentsConfiguration = ( 1, 2, 3, 0 ); ExifVersion = ( 2, 2, 1 ); ExposureMode = 0; ExposureProgram = 2; ExposureTime = "0.06666667"; FNumber = "2.4"; Flash = 16; FlashPixVersion = ( 1, 0 ); FocalLenIn35mmFilm = 35; FocalLength = "4.28"; ISOSpeedRatings = ( 800 ); MeteringMode = 5; PixelXDimension = 3264; PixelYDimension = 2448; SceneCaptureType = 0; SensingMethod = 2; ShutterSpeedValue = "3.906905"; SubjectArea = ( 1631, 1223, 881, 881 ); SubjectDistance = "69 m"; UserComment = "[S.D.] kCGImagePropertyExifUserComment"; WhiteBalance = 0; }; "{GPS}" = { DateStamp = "camera GPS Date Stamp"; DestLatitude = "subject coord Latitude"; DestLongitude = "subject coord Longitude"; ImgDirection = "camera direction (heading) in degrees"; Latitude = "camera coord Latitude"; Longitude = "camera coord Longitude"; }; "{Raw}" = { }; "{TIFF}" = { Orientation = 1; ResolutionUnit = 2; XResolution = 72; YResolution = 72; "_YCbCrPositioning" = 1; }; } </code></pre> <p>And, after it's all done, this:</p> <pre><code>2012-10-12 23:17:47.131 Waypointer[3120:907] Properties { ColorModel = RGB; DPIHeight = 72; DPIWidth = 72; Depth = 8; Orientation = 1; PixelHeight = 2448; PixelWidth = 3264; "{Exif}" = { ApertureValue = "2.526069"; BrightnessValue = "-4.410617"; ColorSpace = 1; ComponentsConfiguration = ( 0, 0, 0, 1 ); ExifVersion = ( 2, 2, 1 ); ExposureMode = 0; ExposureProgram = 2; ExposureTime = "0.06666667"; FNumber = "2.4"; Flash = 16; FlashPixVersion = ( 1, 0 ); FocalLenIn35mmFilm = 35; FocalLength = "4.28"; ISOSpeedRatings = ( 800 ); MeteringMode = 5; PixelXDimension = 3264; PixelYDimension = 2448; SceneCaptureType = 0; SensingMethod = 2; ShutterSpeedValue = "3.906905"; SubjectArea = ( 1631, 1223, 881, 881 ); UserComment = "[S.D.] kCGImagePropertyExifUserComment"; WhiteBalance = 0; }; "{JFIF}" = { DensityUnit = 1; JFIFVersion = ( 1, 1 ); XDensity = 72; YDensity = 72; }; "{TIFF}" = { Orientation = 1; ResolutionUnit = 2; XResolution = 72; YResolution = 72; "_YCbCrPositioning" = 1; }; } </code></pre> <p>As the example illustrates, you can see the image's original metaData, its modification, and then its final output.</p> <p>The final output is what bothers me because no matter what I do, I cannot get my modified values to stick!</p> <p>Is there some very specific format I'm missing? Why is iOS stripping my modifications? What do I need to do to add these extra values? They are listed in the .header and figured it should be easily accepted.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload