将CUSTOM元数据保存在iOS中从AVFoundation拍摄的图像中 [英] Save CUSTOM metadata in an image taken from AVFoundation in iOS
问题描述
当我使用 AVFoundation框架
获取图像时,如何在图像中保存自定义元数据?
How do I save custom metadata in an image when i get the image using the AVFoundation framework
?
我知道我可以访问属性天气我有我的图像 UIImage
或 CIImage
但这些似乎属于彼此不同(即使它是相同的图像)。
I know I can access the properties weather it I have my image as UIImage
or CIImage
but the properties that these seem to have differ from each other (even if it is the same image).
到目前为止,我访问这样的字典:(代码取自Caffeinated Cocoa博客)
So far I access the dictionary like this: (Code taken from Caffeinated Cocoa blog)
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 (e.g., 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 ***");
}
我可以像这样保存我的图像:
And i can either save my image like this:
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 neither of the options return my Custom Raw Data Dictionary.
总之我要做的是将自己的对象保存在我自己创建的字段中(在这种情况下是一个cmattitude对象)
In summary what i want to do is save my own object in a field created by myself (in this case a cmattitude object)
PD:何时我 NSLOG
在将它与图像合并之前的字典它拥有我想要的所有文件。
PD: When i NSLOG
the dictionary before merging it with the image it does have all the files like i want them.
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:
But when i NSLOG the dictionary from the new image it gives me this for the 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;
};
如果我 NSLog
UIImage
它给了我更少的信息。
And if I NSLog
the UIImage
it gives me even less info.
谢谢!
推荐答案
UIImage
和 CIImage
不包含所有元数据。实际上,将它从 NSData
转换为这两种格式中的任何一种都会删除大量的元数据,所以恕我直言, UIImage
和 CIImage
只应在计划在UI中显示或将其传递给 CoreImage 时使用。
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;
}
然后你可以转换你的 NSDictionary
到 NSMutableDictionary
:
You can then convert your NSDictionary
to a NSMutableDictionary
:
NSDictionary *props = [self getImageProperties:imageData];
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:props];
之后,添加您想要的任何字段。请注意,通过 kCGImagePropertyGPSDictionary <抓取
kCGImagePropertyExifDictionary
, GPS 数据可以找到 EXIF 数据/ code>,依此类推:
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];
查看所有的 CGImageProperties
头文件可用的密钥。
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;
你有它。
这篇关于将CUSTOM元数据保存在iOS中从AVFoundation拍摄的图像中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!