剥离Objective-C中的所有Exif数据

Jas*_*ter 7 exif objective-c uiimage

如何使用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;
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 14

几点想法:

  1. 通常,将图像从NSData文件内容或从文件内容加载到a中的过程UIImage,重新提取数据UIImagePNGRepresentation并将其保存回a NSData将从图像中剥离元数据.

    但是,这种简单的技术有其缺点.值得注意的是,强制它进入PNG表示的过程可能会NSData显着影响输出的大小.例如,如果原始图像是压缩的JPEG(例如由相机捕获),则生成的PNG文件实际上可能比原始JPEG大.

    通常我更喜欢获取原始数据(如果文件或包中的文件,直接加载到NSData;如果是从中检索到的东西ALAssetsLibrary,我会检索ALAsset,从中,ALAssetRepresentation从中我会使用getBytes获取该原始资产的原始二进制表示.这避免了通过a往返UIImage(特别是如果随后使用UIImagePNGRepresentationUIImageJEPGRepresentation).

  2. 如果要删除exif数据,可以:

    • 从原始创建图像源NSData;

    • 使用相同的"图像数量"(几乎总是1)和"类型"创建图像目的地;

    • 将图像从源复制到目标时,请告诉它相应的键(kCGImagePropertyExifDictionary并且kCGImagePropertyGPSDictionary应该设置为kCFNull),根据CGImageDestinationAddImageFromSource文档的说明,如果它们恰好出现在源中,则指定如何在目标中删除这些键. ).

    因此,它可能看起来像:

    - (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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,GPS信息在技术上并不是exif数据,但我认为您也想删除它.如果您想保留GPS数据,请kCGImagePropertyGPSDictionary从我的removeExifProperties字典中删除该条目.

  3. 顺便说一句,在你的代码中提取元数据,你似乎正在把它CGImageMetadataRef作为一个NSDictionary.如果你的技术有效,那很好,但我认为这CGImageMetadataRef被认为是一种不透明的数据类型,并且应该用它CGImageMetadataCopyTags来提取标签数组:

    - (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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    为了完整起见,在7.0之前的iOS版本中,您可以从属性中提取数据:

    - (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;
    }
    
    Run Code Online (Sandbox Code Playgroud)