如何使用objective-c去除UIImage中的所有exif数据?我已经能够使用以下内容获取exif数据:
NSData* pngData = UIImagePNGRepresentation(image);
CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);
NSDictionary* dic = nil;
if ( NULL == imageSource )
{
#ifdef _DEBUG
CGImageSourceStatus status = CGImageSourceGetStatus ( source );
NSLog ( @"Error: file name : %@ - Status: %d", file, status );
#endif
}
else
{
CFDictionaryRef propertyRef = CGImageSourceCopyPropertiesAtIndex ( imageSource, 0, NULL );
CGImageMetadataRef metadataRef = CGImageSourceCopyMetadataAtIndex ( imageSource, 0, NULL );
// CFDictionaryRef metadataRef = CFDictionaryGetValue(imageProperties, kCGImagePropertyExifDictionary);
if (metadataRef) {
NSDictionary* immutableMetadata = (NSDictionary *)metadataRef;
if ( immutableMetadata ) {
dic = [ NSDictionary dictionaryWithDictionary : (NSDictionary *)metadataRef ];
}
CFRelease ( metadataRef );
}
CFRelease(imageSource);
imageSource = nil;
}
return dic;
答案 0 :(得分:14)
有几点想法:
通常是将图像从NSData
或文件内容加载到UIImage
的过程,使用UIImagePNGRepresentation
重新提取数据并保存回来到NSData
将从图像中删除元数据。
这种简单的技术有其缺点。值得注意的是,将其强制为PNG表示的过程可能会显着影响输出NSData
的大小。例如,如果原始图像是压缩的JPEG(例如相机捕获的),则生成的PNG文件实际上可能比原始JPEG大。
通常我更喜欢获取原始数据(如果文档或包中的文件直接加载到NSData
;如果是从ALAssetsLibrary
检索的内容,我会检索{ {1}},从那里ALAsset
,然后我使用ALAssetRepresentation
来获取该原始资产的原始二进制表示形式。这样可以避免通过getBytes
进行往返(特别是如果随后使用UIImage
或UIImagePNGRepresentation
)。
如果要删除exif数据,可以:
从原始UIImageJEPGRepresentation
;
使用相同的“图像数量”(几乎总是1)和“类型”创建图像目的地;
将图像从源复制到目标时,请告诉它相应的键(NSData
和kCGImagePropertyExifDictionary
应设置为kCGImagePropertyGPSDictionary
),根据kCFNull
文档是指定如果它们恰好出现在源中,应在目标中删除的文档。
因此,它可能看起来像:
CGImageDestinationAddImageFromSource
请注意,GPS信息在技术上并不是exif数据,但我认为您也想删除它。如果您想保留GPS数据,请从我的- (NSData *)dataByRemovingExif:(NSData *)data
{
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL);
NSMutableData *mutableData = nil;
if (source) {
CFStringRef type = CGImageSourceGetType(source);
size_t count = CGImageSourceGetCount(source);
mutableData = [NSMutableData data];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)mutableData, type, count, NULL);
NSDictionary *removeExifProperties = @{(id)kCGImagePropertyExifDictionary: (id)kCFNull,
(id)kCGImagePropertyGPSDictionary : (id)kCFNull};
if (destination) {
for (size_t index = 0; index < count; index++) {
CGImageDestinationAddImageFromSource(destination, source, index, (__bridge CFDictionaryRef)removeExifProperties);
}
if (!CGImageDestinationFinalize(destination)) {
NSLog(@"CGImageDestinationFinalize failed");
}
CFRelease(destination);
}
CFRelease(source);
}
return mutableData;
}
词典中删除kCGImagePropertyGPSDictionary
条目。
顺便说一句,在您提取元数据的代码中,您似乎将removeExifProperties
转换为CGImageMetadataRef
。如果您的技术有效,那很好,但我认为NSDictionary
被认为是一种不透明的数据类型,并且确实应该使用CGImageMetadataRef
来提取标记数组:
CGImageMetadataCopyTags
为了完整起见,在7.0之前的iOS版本中,您可以从属性中提取数据:
- (NSArray *)metadataForData:(NSData *)data
{
NSArray *metadataArray = nil;
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL);
if (source) {
CGImageMetadataRef metadata = CGImageSourceCopyMetadataAtIndex(source, 0, NULL);
if (metadata) {
metadataArray = CFBridgingRelease(CGImageMetadataCopyTags(metadata));
CFRelease(metadata);
}
CFRelease(source);
}
return metadataArray;
}
答案 1 :(得分:2)
根据Image I/O programming guide,您可以使用CGImageDestinationSetProperties
添加CFDictionaryRef
个属性。
他们的示例代码是:
float compression = 1.0; // Lossless compression if available.
int orientation = 4; // Origin is at bottom, left.
CFStringRef myKeys[3];
CFTypeRef myValues[3];
CFDictionaryRef myOptions = NULL;
myKeys[0] = kCGImagePropertyOrientation;
myValues[0] = CFNumberCreate(NULL, kCFNumberIntType, &orientation);
myKeys[1] = kCGImagePropertyHasAlpha;
myValues[1] = kCFBooleanTrue;
myKeys[2] = kCGImageDestinationLossyCompressionQuality;
myValues[2] = CFNumberCreate(NULL, kCFNumberFloatType, &compression);
myOptions = CFDictionaryCreate( NULL, (const void **)myKeys, (const void **)myValues, 3,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// Release the CFNumber and CFDictionary objects when you no longer need them.
而且我不明白他们为什么不采取一切措施。我猜测接下来会是什么:
CFImageDestinationRef
如何做第一步的文档并不是很清楚。所以我看了CGImageDestination
reference,看起来可以这样做(未经测试):
NSMutableData* mutableData = [[NSMutableData alloc] initWithCapacity:[pngData length]];
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge_transfer CFMutableDataRef)mutableData, <# Some UTI Type #>, 1, NULL);
CGImageDestinationAddImage(imageDestination, image, yourProperties);
CGImageDestinationFinalize(imageDestination);
因此,按照Apple在文档中显示的方式创建属性字典,然后创建图像目标并将所有内容写入其中,包括属性。之后,您可以访问NSMutableData
对象并读取您的图像数据。