无数的尝试和每一等答案 + 谷歌通过筛分结果之后,它很困惑我那在 iOS 上处理 EXIF 是如此令人沮丧。
下面是工作的代码,它的结果。
[[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);
}];
其中输出这:
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; }; }
和这:
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; }; }
并且,在它以后所有,这样做:
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; }; }
如示例所示,您可以看到该图像的原始元数据、 其修改,然后其最终的输出。
最终的输出正是困扰我的因为不管我做什么,无法坚持我修改后的值!
有一些非常具体的格式我错过吗?为什么 iOS 剥离所做的修改?我是否需要做来添加这些额外的值?他们是在.header 中列出,并且觉得它应该很容易接受。
解决方法 1:
斯科特,在苹果公司,开发人员与我事件报告返回和固定的问题:
前面的代码上面写入字符串值的 GPS 值-这不会工作,他们必须为 NS/CFNumbers (我们提取 EXIF 一个浮点值)。
我将会申请一个 bug 报告给苹果反对它们的文档。
虽然花了一个星期才能拿这种反应,我真的很欣赏苹果向开发者提供的支持。(感谢斯科特!);-)
下面是改进了代码和其正确的输出:
[[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);
//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:[NSNumber numberWithFloat:37.795] forKey:(NSString*)kCGImagePropertyGPSLatitude];
[GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
[GPSDictionary setObject:[NSNumber numberWithFloat:122.410] forKey:(NSString*)kCGImagePropertyGPSLongitude];
[GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
[GPSDictionary setObject:@"2012:10:18" forKey:(NSString*)kCGImagePropertyGPSDateStamp];
[GPSDictionary setObject:[NSNumber numberWithFloat:300] forKey:(NSString*)kCGImagePropertyGPSImgDirection];
[GPSDictionary setObject:[NSNumber numberWithFloat:37.795] forKey:(NSString*)kCGImagePropertyGPSDestLatitude];
[GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSDestLatitudeRef];
[GPSDictionary setObject:[NSNumber numberWithFloat:122.410] forKey:(NSString*)kCGImagePropertyGPSDestLongitude];
[GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSDestLongitudeRef];
[EXIFDictionary setObject:@"[S.D.] kCGImagePropertyExifUserComment" forKey:(NSString *)kCGImagePropertyExifUserComment];
[EXIFDictionary setObject:[NSNumber numberWithFloat:69.999] 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];
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(@"Final properties %@", propDict);
}];
其中输出这:
Final properties info { ColorModel = RGB; DPIHeight = 72; DPIWidth = 72; Depth = 8; Orientation = 6; PixelHeight = 2448; PixelWidth = 3264; "{Exif}" = { ApertureValue = "2.526069"; BrightnessValue = "0.547474"; ColorSpace = 1; ComponentsConfiguration = ( 0, 0, 0, 1 ); ExifVersion = ( 2, 2, 1 ); ExposureMode = 0; ExposureProgram = 2; ExposureTime = "0.05"; FNumber = "2.4"; Flash = 16; FlashPixVersion = ( 1, 0 ); FocalLenIn35mmFilm = 35; FocalLength = "4.28"; ISOSpeedRatings = ( 320 ); MeteringMode = 5; PixelXDimension = 3264; PixelYDimension = 2448; SceneCaptureType = 0; SensingMethod = 2; ShutterSpeedValue = "4.321929"; SubjectArea = ( 1631, 1223, 881, 881 ); SubjectDistance = "69.999"; UserComment = "[S.D.] kCGImagePropertyExifUserComment"; WhiteBalance = 0; }; "{GPS}" = { DateStamp = "2012:10:18"; DestLatitude = "37.795"; DestLatitudeRef = N; DestLongitude = "122.41"; DestLongitudeRef = W; ImgDirection = 300; Latitude = "37.795"; LatitudeRef = N; Longitude = "122.41"; LongitudeRef = W; }; "{JFIF}" = { DensityUnit = 1; JFIFVersion = ( 1, 1 ); XDensity = 72; YDensity = 72; }; "{TIFF}" = { Orientation = 6; ResolutionUnit = 2; XResolution = 72; YResolution = 72; "_YCbCrPositioning" = 1;
|