为什么我无法从加载的UIImage中读取EXIF,但仍然可以从NSData中读取?

huangapple go评论126阅读模式
英文:

Why can't I read EXIF from my loaded UIImage, but still can from NSData?

问题

Can EXIF metadata only be ready from the NSData?(EXIF元数据只能从NSData中读取吗?)

英文:

I have some EXIF stored in a UIImage that I store using NSFileManager writeToFile:atomically:.

Now, when I try to read back the EXIF metadata imageProperties here shows the metadata I expect:

NSData *data = [NSData dataWithContentsOfFile:filePath];
source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
imageProperties = CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);

However, if I read the data as a UIImage first, the data is gone:

UIImage *writtenImage = [UIImage imageWithContentsOfFile:filePath];
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)UIImagePNGRepresentation(writtenImage), NULL);
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);

Additionally, even on converting the data variable above to an image, it fails:

NSData *data = [NSData dataWithContentsOfFile:filePath];
UIImage *writtenImage = [UIImage imageWithData:data];
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)UIImagePNGRepresentation(writtenImage), NULL);
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);

Can EXIF metadata only be ready from the NSData?

答案1

得分: 1

EXIF 是一种用于某些图像文件(如 pngjpgtif 等)的标头。当这些文件被解压后,图像就变成了完全不同的东西 - 一个表示像素数据的数组,此时 EXIF 标头不再相关。因此,当你有一个图像容器的 NSData 对象时,与 UIImage 对象中封装的图像数据完全不同(EXIF 标头在那里不再存在)。

你仍然可以推断出某些元数据并自行填充它,但这与 UIImage 无关,在这种情况下,你直接与容器(文件)一起工作

typedef NS_CLOSED_ENUM(uint8_t, TDWEXIFOrientationValue) {
    TDWEXIFOrientationValueTopLeft = 1,
    TDWEXIFOrientationValueTopRight,
    TDWEXIFOrientationValueBottomRight,
    TDWEXIFOrientationValueBottomLeft,
    TDWEXIFOrientationValueLeftTop,
    TDWEXIFOrientationValueRightTop,
    TDWEXIFOrientationValueRightBottom,
    TDWEXIFOrientationValueLeftBotton,
};

- (void)writeEXIFHeader:(CGImageSourceRef)image {
    /* 获取文件类型 */
    CFStringRef UTI = CGImageSourceGetType(image);
    if (!UTI) {
        /* 根据需要处理无法检索文件类型的错误 */
        return;
    }

    NSMutableData *imageData = [NSMutableData new];
    /* 创建一个用于保存文件的图像目标 */
    CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, UTI, 1, NULL);
    if (!destination) {
        /* 根据需要处理创建 CGImageDestinationRef 的错误 */
        return;
    }

    const void *keys[] = {
        kCGImageDestinationDateTime,
        kCGImageDestinationOrientation,
        kCGImageDestinationMergeMetadata
    };

    TDWEXIFOrientationValue orientationValue = TDWEXIFOrientationValueTopLeft;
    const void *values[] = {
        CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()), // 为图片设置当前日期和时间
        CFNumberCreate(kCFAllocatorDefault, kCFNumberCharType, &orientationValue), // 默认方向
        kCFBooleanTrue // 合并 EXIF 元数据而不是覆盖它
    };

    /* 使用修改后的元数据创建 CFDictionaryRef */
    CFDictionaryRef exifData = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(keys[0]), NULL, NULL);

    /* 向目标中添加图像 */
    CFErrorRef errorRef = nil;
    if (!CGImageDestinationCopyImageSource(destination, image, exifData, &errorRef)) {
        CFStringRef errorDescription = CFErrorCopyDescription(errorRef);
        /* 根据需要处理创建写入 EXIF 数据的错误 */
        CFRelease(errorDescription);
    }
}
英文:

EXIF is a header for certain image files (containers like png, jpg, tif, etc..). When the files are unpacked, the image is a completely different thing - an array of data representing pixels, where EXIF header is no longer relevant. Thus, when you have an NSData object of an image container it's a completely different beast compared to the image data incapsulated in a UIImage object (EXIF header is just not present there).

You can still deduce certain metadata and fill it yourself, but this has nothing to do with UIImage, in this case you just work with the containers (files) directly:

typedef NS_CLOSED_ENUM(uint8_t, TDWEXIFOrientationValue) {
    TDWEXIFOrientationValueTopLeft = 1,
    TDWEXIFOrientationValueTopRight,
    TDWEXIFOrientationValueBottomRight,
    TDWEXIFOrientationValueBottomLeft,
    TDWEXIFOrientationValueLeftTop,
    TDWEXIFOrientationValueRightTop,
    TDWEXIFOrientationValueRightBottom,
    TDWEXIFOrientationValueLeftBotton,
};

- (void)writeEXIFHeader:(CGImageSourceRef)image {
    /* get the file type */
    CFStringRef UTI = CGImageSourceGetType(image);
    if (!UTI) {
        /* Handle Error Retrieving File Type Accordingly */
        return;
    }

    NSMutableData *imageData = [NSMutableData new];
    /* create an image destination for saving the file */
    CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, UTI, 1, NULL);
    if (!destination) {
        /* Handle Error Creating CGImageDestinationRef Accordingly */
        return;
    }

    const void *keys[] = {
        kCGImageDestinationDateTime,
        kCGImageDestinationOrientation,
        kCGImageDestinationMergeMetadata
    };

    TDWEXIFOrientationValue orientationValue = TDWEXIFOrientationValueTopLeft;
    const void *values[] = {
        CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()), // Sets current date and time for the picture
        CFNumberCreate(kCFAllocatorDefault, kCFNumberCharType, &orientationValue), // Default orientation
        kCFBooleanTrue // merge exif metadata instead of overwriting it
    };


    /* create an CFDictionaryRef with the modified metadata */
    CFDictionaryRef exifData = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(keys[0]), NULL, NULL);

    /* add an image to the destination */
    CFErrorRef errorRef = nil;
    if (!CGImageDestinationCopyImageSource(destination, image, exifData, &errorRef)) {
        CFStringRef errorDescription = CFErrorCopyDescription(errorRef);
        /* Handle Error Creating Writing EXIF data Accordingly */
        CFRelease(errorDescription);
    }
}

huangapple
  • 本文由 发表于 2023年3月7日 18:27:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75660753.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定