将自定义元数据保存在从 iOS 中的 AVFoundation 获取的图像中

2023-11-26

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

我知道我可以访问属性,只要我的图像是UIImage or CIImage但它们的属性似乎彼此不同(即使是同一图像)。

到目前为止,我像这样访问字典:(代码取自含咖啡因的可可博客)

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 ***");
        }

我可以这样保存我的图像:

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

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

总之,我想要做的是将我自己的对象保存在我自己创建的字段中(在本例中是 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;
    };

如果我NSLog the UIImage它给我的信息更少。

Thanks!


UIImage and CIImage不保存所有元数据。事实上,将其转换为NSData这两种格式中的任何一种都会删除很多元数据,所以恕我直言,UIImage and CIImage仅当您计划在 UI 中显示它或将其传递给核心图像.

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

- (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 to a NSMutableDictionary:

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

之后,添加您想要的任何字段。注意EXIF数据是通过抓取来找到的kCGImagePropertyExifDictionary, GPS数据由kCGImagePropertyGPSDictionary, 等等:

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;

现在你就得到了它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将自定义元数据保存在从 iOS 中的 AVFoundation 获取的图像中 的相关文章

随机推荐

  • Windows 10 的应用内存限制是多少?

    Windows Phone 8 1 的应用程序内存限制可以在 MSDN 上轻松找到 但我似乎无法找到有关 Windows 10 尤其是 Windows 10 Mobile 上应用程序内存限制的明确信息 每个设备系列 Xbox 台式机 手机
  • Webview shouldOverrideUrlLoading 没有被调用

    我正在制作一个电子书阅读器 它使用 epub 格式将书籍加载到网络视图中 在某些书中 有指向同一章中某些部分的锚链接 每一章都以 html 形式加载 这就是链接的样子 file storage sdcard0 Android data co
  • 如何用 JSON 表示稀疏数组?

    我有一个稀疏数组 我想用 JSON 表示 例如 10 gt 100 1 gt 102 3 gt 44 12 gt 87 12345 gt 0 我怎样才能做到这一点 我可以这样做吗 您可以将其表示为一个简单的对象 10 100 1 102 3
  • 关联关系中的角色名称

    从 UML 圣经来看 大约role 角色 角色名称解释了对象如何参与关系 每个对象都需要保存对关联对象的引用 该引用保存在对象内的属性值中 当只有一个关联时 则只有一个属性持有引用 这句话是什么意思呢 谁能举个例子来解释一下吗 Roles
  • 如何在 Symfony5 中为学说配置 apcu

    在 Symfony4 中 我使用以下配置进行教义 apcu 缓存 doctrine orm auto mapping true auto generate proxy classes false metadata cache driver
  • C++ 将数字从零舍入

    你好 我想在 C 中像这样舍入双数 远离零 4 2 gt 5 5 7 gt 6 7 8 gt 8 34 2 gt 35 做到这一点的有效方法是什么 inline double myround double x return x lt 0 f
  • R Shiny 应用程序中的延迟执行

    RShiny 应用程序的某些部分是否可能以延迟方式执行 就像 Windows 服务中的延迟启动一样 让我详细说明一下 我有一个带有选项卡的闪亮应用程序 每个选项卡的侧边栏面板上都有一堆单选按钮 单击每个单选按钮都会弹出一个报告 我的设置就是
  • 从 TextTransform.exe 获取参数值到模板中

    当我使用 TextTransform exe 从模板生成代码时 我找不到一些示例如何使用参数 a 在MSDN参数 a 的描述如下 指定指令的参数 处理器可以查询为 名称 值对 该指令 处理器和标识符是可选的 这允许指定参数 对于任何指令处理
  • 使用react-router-dom成功进行身份验证后将用户重定向到他们请求的页面

    我构建了一个公共路由组件 用于在用户未经身份验证时显示登录信息 每当未登录的用户单击受保护的路由时 他将被重定向到可以输入凭据的登录页面 我想要一种编程方式 这样如果他使用正确的凭据登录 他应该被重定向到他首先尝试访问的页面 例如 如果用户
  • 设置证书验证位置时出错,install_github

    我正在尝试从 github 安装软件包 但当我安装时不断收到错误消息 使用install github library devtools install github repo swirl username ncarchedi Instal
  • JavaScript 模板字符串的 Polyfill

    是否有任何使用反引号的 JavaScript 模板字符串的填充 我指的是如下代码 var textTemplate h1 My Template String h1 p Some more stuf here p 我不想使用诸如 babel
  • Cython 编译错误:'-mno-fused-madd'

    每当我编译 Cython 代码时 使用pyximport 并且经常当我从源安装软件包时 使用pip I get clang warning argument unused during compilation mno fused madd
  • Intellij IDEA Tomcat 应用程序服务器在运行配置停止之前未连接,原因:无法在 localhost:1099 ping 服务器

    我正在使用 Intellij Ultimate 版本 14 0 2 使用 Maven 作为我的构建工具来处理 Java 项目 尝试通过 Tomcat 服务器启动我的项目时 我们收到此错误 运行配置停止前未连接应用程序服务器 原因 无法 pi
  • jQuery Mobile 1.1.1 自定义选择菜单 - 占位符文本不可见

    今天早些时候 2012 年 7 月 13 日 升级到 jQuery Mobile 1 1 1 后 我注意到我的所有自定义选择菜单不再在页面加载时显示占位符文本 在 1 1 1 中我需要做一些不同的事情才能在自定义选择菜单中显示占位符文本吗
  • Java:BufferedImage 到字节数组并返回

    我发现很多人都有类似的问题 但是我还没有尝试找到我正在寻找的东西 因此 我有一个读取输入图像并将其转换为字节数组的方法 File imgPath new File ImageName BufferedImage bufferedImage
  • 如何在 Bootstrap 3 模态中居中输入?

    我目前正在从 Bootstrap 2 切换到 Bootstrap 3 如何将 Bootstrap 3 中的输入字段居中 文本正确居中 它曾经为 BS2 工作 我尝试过移动 div 中的 style text align center 但仍然
  • 如何找到word在文件中的位置?

    例如我有文件和单词 test 文件部分是二进制的 但有字符串 test 如何在不加载该文件到内存的情况下找到文件中单词 索引 的位置 除非打开文件 否则无法找到文件中文本的位置 这就像要求某人在不睁开眼睛的情况下阅读报纸一样 回答你问题的第
  • GWT 从 2.8.1 升级到 2.8.2 后出现“XmlRootElement 无法解析为类型”错误

    为了修复 Chrome 61 中损坏的 GWT 拖放功能 我们决定升级 GWT 因为修复是在 GWT 2 8 2 中 升级后 我遇到了数百个以下错误 ERROR Line 7 XmlRootElement cannot be resolve
  • Form_for 带有 url、格式和 html 选项

    我觉得我在这里缺少一些简单的东西 我正在将 form for 助手与对象一起使用 我指定 url 格式和 html 方法 但是 在渲染时 action 属性中的 url 不会采用该格式 这是我的代码 form for site url co
  • 将自定义元数据保存在从 iOS 中的 AVFoundation 获取的图像中

    当我使用以下命令获取图像时 如何在图像中保存自定义元数据AVFoundation framework 我知道我可以访问属性 只要我的图像是UIImage or CIImage但它们的属性似乎彼此不同 即使是同一图像 到目前为止 我像这样访问