问题描述
如果键/ val已经存在于具有CGImageDestination的原始图像元数据中,我似乎无法正确地将图像元数据写入图像。它的工作原理很好,如果它们的键/ val不存在于原始的元数据。
这几乎就好像原始图像中的图像元数据属性优先于修改。这是一种拜占庭式的格式问题我不知道,在哪里我需要填充键/ val在一些不寻常的方式,一个bug,或?任何人都看过这个?
下面的代码和输出,适用于正常工作(如果值还没有设置)和无法写入的情况已经设置为其他)。
任何帮助非常感谢。
这里是/图像NSData:
//将现有资产转换为nsdata以覆盖自己
ALAssetRepresentation * rep = [asset defaultRepresentation ];
Byte * buffer =(Byte *)malloc(rep.size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
NSData * imageData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
//将元数据直接写入图像本身的nsdata中
NSData * newImage = [self writeMetadataIntoImageData:imageData metadata:newMetadata];
这是元数据的实际修改:
- (NSData *)writeMetadataIntoImageData:(NSData *)imageData metadata:(NSMutableDictionary *)metadataAsMutable
{
// create an imagesourceref
CGImageSourceRef source = CGImageSourceCreateWithData((__ bridge CFDataRef)imageData,NULL);
//读取和记录预写元数据
NSDictionary * metadata =(NSDictionary *)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source,0,NULL));
NSLog(@之前:\\\
------------------------------%@ \\\
-- ----------------------------,metadata);
//在这里设置新的元数据键
NSMutableDictionary * iptc = [metadataAsMutable [(NSString *)kCGImagePropertyIPTCDictionary] mutableCopy];
if(!iptc)
{
iptc = [NSMutableDictionary dictionaryWithCapacity:1];
}
iptc [(NSString *)kCGImagePropertyIPTCCaptionAbstract] = @Hardcoded Caption;
metadataAsMutable [(NSString *)kCGImagePropertyIPTCDictionary] = iptc;
//记录我们想要的新元数据
NSLog(@Parameter:\\\
------------------ ------------%@ \\\
------------------------------,metadataAsMutable );
//这是图像类型(例如public.jpeg)
CFStringRef UTI = CGImageSourceGetType(source);
//创建一个新的数据对象并写入新的数据
NSMutableData * dest_data = [NSMutableData data];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((__ bridge CFMutableDataRef)dest_data,UTI,1,NULL);
if(!destination)
{
NSLog(@Error:Could not create image destination);
}
//将图像源中包含的图像添加到目标,使用我们修改的元数据覆盖旧的元数据
CGImageDestinationAddImageFromSource(destination,source,0,(__bridge CFDictionaryRef)metadataAsMutable);
BOOL success = NO;
success = CGImageDestinationFinalize(destination);
if(!success)
{
NSLog(@错误:无法从映像目标创建数据);
}
//读取和记录后写入元数据
CGImageSourceRef source2;
source2 = CGImageSourceCreateWithData((__ bridge CFDataRef)dest_data,NULL);
NSDictionary * metadata2 =(NSDictionary *)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source2,0,NULL));
NSLog(@After:\\\
------------------------------%@ \\\
-- ----------------------------,metadata2);
//清除
CFRelease(destination);
//返回新数据
return dest_data;
}
以下是当图像具有键的现有值时的NSLogs:
之前:
-------------------- ---------- {
< ... snip ...>
{IPTC}= {
Caption / Abstract= Blurry;
DateCreated = 20130923;
DigitalCreationDate = 20130923;
DigitalCreationTime = 173815;
Keywords =(
fake
);
SupplementalCategory =(
fake
);
TimeCreated = 173815;
};
< ... snip ...>
}
------------------------------
参数:
- ----------------------------- {
< ... snip ...>
{IPTC}= {
Caption / Abstract=Hardcoded Caption;
DateCreated = 20130923;
DigitalCreationDate = 20130923;
DigitalCreationTime = 173815;
Keywords =(
fake
);
SupplementalCategory =(
fake
);
TimeCreated = 173815;
};
< ... snip ...>
}
------------------------------
之后:
- ----------------------------- {
< ... snip ...>
{IPTC}= {
Caption / Abstract= Blurry;
DateCreated = 20130923;
DigitalCreationDate = 20130923;
DigitalCreationTime = 173815;
Keywords =(
fake
);
SupplementalCategory =(
fake
);
TimeCreated = 173815;
};
< ... snip ...>
}
------------------------------
以下是图片没有键值的NSLogs:
之前:
------------------------------ {
< ... snip ...>
{IPTC}= {
DateCreated = 20130925;
DigitalCreationDate = 20130925;
DigitalCreationTime = 192856;
Keywords =(
fake
);
SupplementalCategory =(
fake
);
TimeCreated = 192856;
};
< ... snip ...>
}
------------------------------
参数:
- ----------------------------- {
< ... snip ...>
{IPTC}= {
Caption / Abstract=Hardcoded Caption; $ b¥b DateCreated = 20130925;
DigitalCreationDate = 20130925;
DigitalCreationTime = 192856;
Keywords =(
fake
);
SupplementalCategory =(
fake
);
TimeCreated = 192856;
};
< ... snip ...>
}
------------------------------
之后:
- ----------------------------- {
< ... snip ...>
{IPTC}= {
Caption / Abstract=Hardcoded Caption;
DateCreated = 20130925;
DigitalCreationDate = 20130925;
DigitalCreationTime = 192856;
Keywords =(
fake
);
SupplementalCategory =(
fake
);
TimeCreated = 192856;
};
< ... snip ...>
}
------------------------------
解决方案根据IPTC文档,说明字段绑定到TIFF和EXIF地址。更改TIFF中的值,它还更新IPTC条目!
谢谢user2452250的提示。I can't seem to get image metadata to be written to the image correctly if the key/val is already present in the original image metadata with CGImageDestination. It works just fine if it they key/val is not present in the original metadata.
It's almost as though image metadata properties in the original image take precedence over modifications. Is this some kind of byzantine formatting issue I am not aware of, where I need to populate the key/val in some unusual way, a bug, or? Anyone else seen this?
Code and output below, for both cases where it works properly (if the value is not already set) and fails to write (if the value is already set to something else).
Any help appreciated greatly appreciated.
Here is where/how I create the image NSData:
// convert the existing asset to nsdata to overwrite itself ALAssetRepresentation* rep = [asset defaultRepresentation]; Byte* buffer = (Byte*)malloc(rep.size); NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil]; NSData* imageData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES]; // write the metadata directly into the nsdata of the image itself NSData* newImage = [self writeMetadataIntoImageData:imageData metadata:newMetadata];
Here is the actual modification of the metadata:
- (NSData*)writeMetadataIntoImageData:(NSData*)imageData metadata:(NSMutableDictionary*)metadataAsMutable { // create an imagesourceref CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL); // read and log pre write metadata NSDictionary* metadata = (NSDictionary *) CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source,0,NULL)); NSLog(@"Before:\n------------------------------%@\n------------------------------", metadata); // set the new metadata keys here NSMutableDictionary* iptc = [metadataAsMutable[(NSString*)kCGImagePropertyIPTCDictionary] mutableCopy]; if (!iptc) { iptc = [NSMutableDictionary dictionaryWithCapacity:1]; } iptc[(NSString*)kCGImagePropertyIPTCCaptionAbstract] = @"Hardcoded Caption"; metadataAsMutable[(NSString*)kCGImagePropertyIPTCDictionary] = iptc; // log the new metadata as we want it written NSLog(@"Parameter:\n------------------------------%@\n------------------------------", metadataAsMutable); // this is the type of image (e.g., public.jpeg) CFStringRef UTI = CGImageSourceGetType(source); // create a new data object and write the new image into it NSMutableData *dest_data = [NSMutableData data]; CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)dest_data,UTI,1,NULL); if(!destination) { NSLog(@"Error: 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); BOOL success = NO; success = CGImageDestinationFinalize(destination); if(!success) { NSLog(@"Error: Could not create data from image destination"); } // read and log post write metadata CGImageSourceRef source2; source2 = CGImageSourceCreateWithData((__bridge CFDataRef) dest_data, NULL); NSDictionary *metadata2 = (NSDictionary *) CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source2,0,NULL)); NSLog(@"After:\n------------------------------%@\n------------------------------", metadata2); // cleanup CFRelease(destination); // return the new data return dest_data; }
Here are the NSLogs for when the image has an existing value for the key:
Before: ------------------------------{ <...snip...> "{IPTC}" = { "Caption/Abstract" = Blurry; DateCreated = 20130923; DigitalCreationDate = 20130923; DigitalCreationTime = 173815; Keywords = ( fake ); SupplementalCategory = ( fake ); TimeCreated = 173815; }; <...snip...> } ------------------------------ Parameter: ------------------------------{ <...snip...> "{IPTC}" = { "Caption/Abstract" = "Hardcoded Caption"; DateCreated = 20130923; DigitalCreationDate = 20130923; DigitalCreationTime = 173815; Keywords = ( fake ); SupplementalCategory = ( fake ); TimeCreated = 173815; }; <...snip...> } ------------------------------ After: ------------------------------{ <...snip...> "{IPTC}" = { "Caption/Abstract" = Blurry; DateCreated = 20130923; DigitalCreationDate = 20130923; DigitalCreationTime = 173815; Keywords = ( fake ); SupplementalCategory = ( fake ); TimeCreated = 173815; }; <...snip...> } ------------------------------
Here are the NSLogs for when the image has no value for the key:
Before: ------------------------------{ <...snip...> "{IPTC}" = { DateCreated = 20130925; DigitalCreationDate = 20130925; DigitalCreationTime = 192856; Keywords = ( fake ); SupplementalCategory = ( fake ); TimeCreated = 192856; }; <...snip...> } ------------------------------ Parameter: ------------------------------{ <...snip...> "{IPTC}" = { "Caption/Abstract" = "Hardcoded Caption"; DateCreated = 20130925; DigitalCreationDate = 20130925; DigitalCreationTime = 192856; Keywords = ( fake ); SupplementalCategory = ( fake ); TimeCreated = 192856; }; <...snip...> } ------------------------------ After: ------------------------------{ <...snip...> "{IPTC}" = { "Caption/Abstract" = "Hardcoded Caption"; DateCreated = 20130925; DigitalCreationDate = 20130925; DigitalCreationTime = 192856; Keywords = ( fake ); SupplementalCategory = ( fake ); TimeCreated = 192856; }; <...snip...> } ------------------------------
解决方案According to the IPTC documentation the description field is bound to the TIFF and EXIF address. changing the value in the TIFF it updates also the IPTC entry!thank you user2452250 for the tip.
这篇关于如何覆盖图像元数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!