在Objective-C中剥离所有Exif数据 [英] Stripping All Exif Data in Objective-C
问题描述
如何使用Objective-C剥离UIImage中的所有exif数据?我已经可以使用以下命令获取exif数据:
How do you strip all exif data in a UIImage using objective-c? I have been able to get the exif data using the following :
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;
推荐答案
一些想法:
-
通常,将图像从
NSData
或文件内容加载到UIImage
,用UIImagePNGRepresentation
重新提取数据并将其保存回NSData
的过程如下:从图像中删除元数据.
Generally the process of loading an image from the
NSData
or from the contents of a file into aUIImage
, re-extracting the data withUIImagePNGRepresentation
and saving that back to aNSData
will strip the metadata from the image.
但是,这种简单的技术有其缺点.值得注意的是,将其强制为PNG表示的过程可能会极大地影响输出NSData
的大小.例如,如果原始图像是压缩的JPEG(例如由相机捕获),则生成的PNG文件实际上可能大于原始JPEG.
This simple technique has its disadvantages, though. Notably, the process of forcing it to a PNG representation may affect the size of the output NSData
dramatically, though. For example, if the original image was a compressed JPEG (such as captured by the camera), the resulting PNG file can actually be larger than the original JPEG.
通常,我希望获取原始数据(如果将文档或文档包中的文件直接加载到NSData
中;如果是从ALAssetsLibrary
中检索到的内容,则我将检索ALAsset
,然后然后从ALAssetRepresentation
开始,然后从getBytes
获取该原始资产的原始二进制表示形式).这样可以避免通过UIImage
(特别是如果随后使用UIImagePNGRepresentation
或UIImageJEPGRepresentation
)来回传递它.
Generally I would prefer to get the original data (if a file in Documents or the bundle, load that directly to a NSData
; if it's something retrieved from the ALAssetsLibrary
, I would retrieve the ALAsset
, and from that, the ALAssetRepresentation
, and from that I'd use getBytes
to get the original binary representation of that original asset). This avoids the round-tripping it through a UIImage
(particularly if subsequently using UIImagePNGRepresentation
or UIImageJEPGRepresentation
).
如果要剥离exif数据,可以:
If you want to strip exif data, you can:
-
从原始
NSData
;
使用相同的图片数量"(几乎始终为1)和类型"创建图片目标;
Create an image destination, using the same "number of images" (almost always 1) and the "type";
将图像从源复制到目标时,告诉它适当的键(kCGImagePropertyExifDictionary
和kCGImagePropertyGPSDictionary
应该设置为kCFNull
),根据CGImageDestinationAddImageFromSource
文档,该方法是您可以指定如果它们恰巧出现在源代码中,则应将它们从目标位置删除.
When copying the images from the source to the destination, tell it that the appropriate keys (kCGImagePropertyExifDictionary
and kCGImagePropertyGPSDictionary
should be set to kCFNull
), which according to the CGImageDestinationAddImageFromSource
documentation is how you specify that those should be removed in the destination if they happened to appear in the source).
因此,它可能看起来像:
Thus, it might look like:
- (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;
}
请注意,GPS信息从技术上讲不是exif数据,但我想您也想删除它.如果要保留GPS数据,请从我的removeExifProperties
词典中删除kCGImagePropertyGPSDictionary
条目.
Note, GPS information is not technically exif data, but I assume you wanted to remove that, too. If you wanted to keep the GPS data, remove the kCGImagePropertyGPSDictionary
entry from my removeExifProperties
dictionary.
BTW,在提取元数据的代码中,您似乎将CGImageMetadataRef
强制转换为NSDictionary
.如果您的技术可行,那很好,但是我认为CGImageMetadataRef
被认为是一种不透明的数据类型,确实应该使用CGImageMetadataCopyTags
来提取标签数组:
BTW, in your code to extract the meta data, you seem to be casting the CGImageMetadataRef
as a NSDictionary
. If your technique works, that's fine, but I think that CGImageMetadataRef
is considered to be an opaque data type, and that one really should be using CGImageMetadataCopyTags
to extract the array of tags:
- (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;
}
为了完整起见,在7.0之前的iOS版本中,您可以从属性中提取数据:
For the sake of completeness, in iOS versions prior to 7.0, you can extract the data from the properties:
- (NSDictionary *)metadataForData:(NSData *)data
{
NSDictionary *properties = nil;
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL);
if (source) {
properties = CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source, 0, NULL));
CFRelease(source);
}
return properties;
}
这篇关于在Objective-C中剥离所有Exif数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!