Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
371 views
in Technique[技术] by (71.8m points)

uiimage - Stripping All Exif Data in Objective-C

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;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A couple of thoughts:

  1. Generally the process of loading an image from the NSData or from the contents of a file into a UIImage, re-extracting the data with UIImagePNGRepresentation and saving that back to a NSData will strip the metadata from the image.

    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.

    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).

  2. If you want to strip exif data, you can:

    • Create an image source from the original NSData;

    • Create an image destination, using the same "number of images" (almost always 1) and the "type";

    • 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;
    }
    

    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.

  3. 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;
    }
    

    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;
    }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...