简体   繁体   English

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

[英]Save CUSTOM metadata in an image taken from AVFoundation in iOS

How do I save custom metadata in an image when i get the image using the AVFoundation framework ? 当我使用AVFoundation framework获取图像时,如何在图像中保存自定义元数据?

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

So far I access the dictionary like this: (Code taken from Caffeinated Cocoa blog) 到目前为止,我访问这样的字典:(代码取自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 (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);

Or like this 或者像这样

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. BUt这两个选项都没有返回我的自定义原始数据字典。

In summary what i want to do is save my own object in a field created by myself (in this case a cmattitude object) 总之我想要做的是将我自己的对象保存在我自己创建的字段中(在本例中是一个cmattitude对象)

PD: When i NSLOG the dictionary before merging it with the image it does have all the files like i want them. 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;
    };

But when i NSLOG the dictionary from the new image it gives me this for the CIIMage: 但是,当我从新图像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;
    };

And if I NSLog the UIImage it gives me even less info. 如果我NSLogUIImage它给我更少的信息。

Thanks! 谢谢!

UIImage and CIImage don't hold all the metadata. UIImageCIImage不包含所有元数据。 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 . 事实上,将它从NSData转换为这两种格式中的任何一种都会消除很多元数据,因此只有在计划在UI中显示或将其传递给CoreImage时才应使用IMHO, UIImageCIImage

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

You can then convert your NSDictionary to a NSMutableDictionary : 然后,您可以将NSDictionary转换为NSMutableDictionary

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

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: 请注意,通过kCGImagePropertyExifDictionary抓取kCGImagePropertyExifDictionaryGPS数据, kCGImagePropertyGPSDictionary ,可以找到EXIF数据:

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

Look at the CGImageProperties header file for all the keys available. 查看CGImageProperties头文件以获取所有可用键。

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;

And there you have it. 你有它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM