将CUSTOM元数据保存在iOS中从AVFoundation拍摄的图像中

当我使用AVFoundation framework获取图像时,如何在图像中保存自定义元数据?

我知道我可以访问属性天气我将我的图像作为UIImageCIImage但这些属性看起来彼此不同(即使它是相同的图像)。

到目前为止,我访问这样的字典:(代码取自Caffeinated Cocoa博客)

 NSLog(@"about to request a capture from: %@", [self stillImageOutput]); [[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) { NSData *jpeg = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer] ; CGImageSourceRef source = CGImageSourceCreateWithData((__bridge_retained CFDataRef)jpeg, NULL); //get all the metadata in the image NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,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]; } if(!GPSDictionary) { GPSDictionary = [NSMutableDictionary dictionary]; } if(!RAWDictionary) { RAWDictionary = [NSMutableDictionary dictionary]; } float _lat = gpsInfo.coordinate.latitude; float _lon = gpsInfo.coordinate.longitude; float _alt = gpsInfo.altitude; NSDate *_date = gpsInfo.timestamp; float _heading = gpsInfo.course;; [GPSDictionary setValue:[NSNumber numberWithFloat:_lat] forKey:(NSString*)kCGImagePropertyGPSLatitude]; [GPSDictionary setValue:[NSNumber numberWithFloat:_lon] forKey:(NSString*)kCGImagePropertyGPSLongitude]; [GPSDictionary setValue:[NSNumber numberWithFloat:_alt] forKey:(NSString*)kCGImagePropertyGPSAltitude]; [GPSDictionary setValue:_date forKey:(NSString*)kCGImagePropertyGPSDateStamp]; [GPSDictionary setValue:[NSNumber numberWithFloat:_heading] forKey:(NSString*)kCGImagePropertyGPSImgDirection]; [EXIFDictionary setValue:@"Wasup" forKey:(NSString *)kCGImagePropertyExifUserComment]; [RAWDictionary setValue:attitude forKey:@"Attitude"]; //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(@"Info: %@",metadataAsMutable); CFStringRef UTI = CGImageSourceGetType(source); //this is the type of image (eg, public.jpeg) //this will be the data CGImageDestinationRef will write into NSMutableData *data = [NSMutableData data]; CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)data,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,source,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:data]; NSDictionary *propDict = [testImage properties]; NSLog(@"Properties %@",propDict); 

或者像这样

 UIImage *imageMod = [[UIImage alloc] initWithData:data]; CGImageSourceRef source2 = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); //get all the metadata in the image NSDictionary *metadata2 = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source2,0,NULL); NSLog(@"WASD: %@",metadata2); 

BUt这两个选项都不返回我的自定义原始数据字典。

总之我想要做的是将我自己的对象保存在我自己创建的字段中(在这种情况下是一个cmattitude对象)

PD:当我在将字典与图像合并之前对字典进行NSLOG ,它确实拥有了我想要的所有文件。

 Info: { ColorModel = RGB; DPIHeight = 72; DPIWidth = 72; Depth = 8; Orientation = 6; PixelHeight = 1080; PixelWidth = 1920; "{Exif}" = { ApertureValue = "2.526069"; BrightnessValue = "4.013361"; ColorSpace = 1; ComponentsConfiguration = ( 1, 2, 3, 0 ); ExifVersion = ( 2, 2, 1 ); ExposureMode = 0; ExposureProgram = 2; ExposureTime = "0.03333334"; FNumber = "2.4"; Flash = 16; FlashPixVersion = ( 1, 0 ); FocalLenIn35mmFilm = 35; FocalLength = "4.28"; ISOSpeedRatings = ( 80 ); MeteringMode = 5; PixelXDimension = 1920; PixelYDimension = 1080; SceneCaptureType = 0; SensingMethod = 2; Sharpness = 0; ShutterSpeedValue = "4.906905"; SubjectArea = ( 959, 539, 518, 388 ); UserComment = "Wazup"; WhiteBalance = 0; }; "{GPS}" = { Altitude = 102; DateStamp = "2012-01-20 06:55:48 +0000"; ImgDirection = "-1"; Latitude = "35.02496"; Longitude = "135.754"; }; "{Raw}" = { Attitude = "Pitch: 50.913760, Roll: 36.342350, Yaw: -164.272361 @ 0.048291\n"; }; "{TIFF}" = { Orientation = 6; ResolutionUnit = 2; XResolution = 72; YResolution = 72; "_YCbCrPositioning" = 1; }; 

但当我从新图像NSLOG字典时,它给了我这个CIIMage:

 Properties { ColorModel = RGB; DPIHeight = 72; DPIWidth = 72; Depth = 8; Orientation = 6; PixelHeight = 1080; PixelWidth = 1920; "{Exif}" = { ApertureValue = "2.526069"; BrightnessValue = "4.013361"; ColorSpace = 1; ComponentsConfiguration = ( 0, 0, 0, 1 ); ExifVersion = ( 2, 2, 1 ); ExposureMode = 0; ExposureProgram = 2; ExposureTime = "0.03333334"; FNumber = "2.4"; Flash = 16; FlashPixVersion = ( 1, 0 ); FocalLenIn35mmFilm = 35; FocalLength = "4.28"; ISOSpeedRatings = ( 80 ); MeteringMode = 5; PixelXDimension = 1920; PixelYDimension = 1080; SceneCaptureType = 0; SensingMethod = 2; Sharpness = 0; ShutterSpeedValue = "4.906905"; SubjectArea = ( 959, 539, 518, 388 ); UserComment = "Wazup"; WhiteBalance = 0; }; "{GPS}" = { Altitude = 102; ImgDirection = 0; Latitude = "35.025"; Longitude = "135.754"; }; "{JFIF}" = { DensityUnit = 1; JFIFVersion = ( 1, 1 ); XDensity = 72; YDensity = 72; }; "{TIFF}" = { Orientation = 6; ResolutionUnit = 2; XResolution = 72; YResolution = 72; "_YCbCrPositioning" = 1; }; 

如果我NSLogUIImage它给我更少的信息。

谢谢!

UIImageCIImage不包含所有元数据。 事实上,将它从NSData转换为这两种格式中的任何一种都会消除很多元数据,因此只有在计划在UI中显示或将其传递给CoreImage时才应使用IMHO, UIImageCIImage

您可以像这样读取图像属性:

 - (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; } 

然后,您可以将NSDictionary转换为NSMutableDictionary

 NSDictionary *props = [self getImageProperties:imageData]; NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:props]; 

之后,添加您想要的任何字段。 请注意,通过kCGImagePropertyExifDictionary抓取kCGImagePropertyExifDictionaryGPS数据, kCGImagePropertyGPSDictionary ,可以找到EXIF数据:

 NSMutableDictionary *exifDictionary = properties[(__bridge NSString *) kCGImagePropertyExifDictionary]; 

查看CGImageProperties头文件以获取所有可用键。

好的,现在您已经对元数据进行了所需的任何更改,将其添加回来需要执行以下几个步骤:

 // 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; 

你有它。