如何在iOS中将自定义元数据写入PNG图像

我的应用程序应该能够编写自定义元数据条目到PNG图像导出到UIPasteboard。

把这个主题的各个post拼凑在一起,我就能够拿出下面给出的类来源。

使用button触发copyPressed方法,我可以使用JPG图像(EXIF)设置自定义元数据:

Image[6101:907] found jpg exif dictionary Image[6101:907] checking image metadata on clipboard Image[6101:907] { ColorModel = RGB; Depth = 8; Orientation = 1; PixelHeight = 224; PixelWidth = 240; "{Exif}" = { ColorSpace = 1; PixelXDimension = 240; PixelYDimension = 224; UserComment = "Here is a comment"; }; "{JFIF}" = { DensityUnit = 0; JFIFVersion = ( 1, 1 ); XDensity = 1; YDensity = 1; }; "{TIFF}" = { Orientation = 1; }; } 

虽然我能够阅读PNG元数据,但我似乎无法写信给它:

 Image[6116:907] found png property dictionary Image[6116:907] checking image metadata on clipboard Image[6116:907] { ColorModel = RGB; Depth = 8; PixelHeight = 224; PixelWidth = 240; "{PNG}" = { InterlaceType = 0; }; } 

然而,文档中没有任何内容表明这会失败,许多特定于PNG的元数据常量表明它应该成功。

我的应用程序应该使用PNG来避免JPG的有损压缩 。

为什么我不能在iOS中的内存PNG图像上设置自定义元数据?

注意:我已经看到了这个问题 ,但是这里没有解决这个问题,那就是如何将元数据专门写入PNG图像。

IMViewController.m

 #import "IMViewController.h" #import <ImageIO/ImageIO.h> @interface IMViewController () @end @implementation IMViewController - (IBAction)copyPressed:(id)sender { // [self copyJPG]; [self copyPNG]; } -(void)copyPNG { NSData *pngData = UIImagePNGRepresentation([UIImage imageNamed:@"wow.png"]); CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)pngData, NULL); NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL); NSMutableDictionary *mutableMetadata = [metadata mutableCopy]; NSMutableDictionary *dict = [[mutableMetadata objectForKey:(NSString *) kCGImagePropertyPNGDictionary] mutableCopy]; if (dict) { NSLog(@"found png property dictionary"); } else { NSLog(@"creating png property dictionary"); dict = [NSMutableDictionary dictionary]; } // set values on the root dictionary [mutableMetadata setObject:@"Name of Software" forKey:(NSString *)kCGImagePropertyPNGDescription]; [mutableMetadata setObject:dict forKey:(NSString *)kCGImagePropertyPNGDictionary]; // set values on the internal dictionary [dict setObject:@"works" forKey:(NSString *)kCGImagePropertyPNGDescription]; CFStringRef UTI = CGImageSourceGetType(source); NSMutableData *data = [NSMutableData data]; CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef) data, UTI, 1, NULL); if (!destination) { NSLog(@">>> Could not create image destination <<<"); return; } CGImageDestinationAddImageFromSource(destination, source, 0, (__bridge CFDictionaryRef) mutableMetadata); BOOL success = CGImageDestinationFinalize(destination); if (!success) { NSLog(@">>> Error Writing Data <<<"); } UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; [pasteboard setData:data forPasteboardType:@"public.png"]; [self showPNGMetadata]; } -(void)copyJPG { NSData *jpgData = UIImageJPEGRepresentation([UIImage imageNamed:@"wow.jpg"], 1); CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) jpgData, NULL); NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL); NSMutableDictionary *mutableMetadata = [metadata mutableCopy]; NSMutableDictionary *exif = [[mutableMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy]; if (exif) { NSLog(@"found jpg exif dictionary"); } else { NSLog(@"creating jpg exif dictionary"); } // set values on the exif dictionary [exif setObject:@"Here is a comment" forKey:(NSString *)kCGImagePropertyExifUserComment]; [mutableMetadata setObject:exif forKey:(NSString *)kCGImagePropertyExifDictionary]; CFStringRef UTI = CGImageSourceGetType(source); NSMutableData *data = [NSMutableData data]; CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef) data, UTI, 1, NULL); if(!destination) { NSLog(@">>> Could not create image destination <<<"); return; } CGImageDestinationAddImageFromSource(destination,source, 0, (__bridge CFDictionaryRef) mutableMetadata); BOOL success = CGImageDestinationFinalize(destination); if (!success) { NSLog(@">>> Could not create data from image destination <<<"); } UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; [pasteboard setData:data forPasteboardType:@"public.jpeg"]; [self showJPGMetadata]; } -(void)showJPGMetadata { NSLog(@"checking image metadata on clipboard"); UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; NSData *data = [pasteboard dataForPasteboardType:@"public.jpeg"]; CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL); NSLog(@"%@", metadata); } -(void)showPNGMetadata { NSLog(@"checking image metadata on clipboard"); UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; NSData *data = [pasteboard dataForPasteboardType:@"public.png"]; CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL); NSLog(@"%@", metadata); } @end 

如果您尝试使用修改后的元数据保存图片

 [data writeToFile:[NSTemporaryDirectory() stringByAppendingPathComponent:@"test.png"] atomically:YES]; 

而不是在Finder中查看它的属性。 您会看到kCGImagePropertyPNGDescription字段已成功设置。

在这里输入图像说明

但是,如果您尝试读取这个新文件的元数据, kCGImagePropertyPNGDescription将会丢失。

 ColorModel = RGB; Depth = 8; PixelHeight = 1136; PixelWidth = 640; "{PNG}" = { InterlaceType = 0; }; 

经过一番研究,我发现PNG不包含元数据。 但是它可能包含XMP元数据 。 不过好像ImageIO不能用于XMP。
也许你可以尝试使用ImageMagic或libexif 。

有用的链接:
PNG规范
在iPhone / Objective-C上读/写图像XMP
PNG是否支持Author,Camera Model等元数据字段?
PNG是否包含像JPG这样的EXIF数据?
libexif.sourceforge.net