将CUSTOM元数据保存在iOS中从AVFoundation拍摄的图像中 [英] Save CUSTOM metadata in an image taken from AVFoundation in iOS

查看:141
本文介绍了将CUSTOM元数据保存在iOS中从AVFoundation拍摄的图像中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆