2014-08-31 36 views
6

如何使用objective-c剝離UIImage中的所有exif數據?我已經能夠用得到的EXIF數據如下:剝離Objective-C中的所有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; 

回答

11

一對夫婦的想法:

  1. 一般從NSData或從文件的內容的圖像加載到UIImage,與UIImagePNGRepresentation重新提取數據,並保存該回的過程NSData將從圖像中去除元數據。

    雖然這種簡單的技術有其缺點。值得注意的是,將其強制爲PNG表示的過程可能會顯着影響輸出NSData的大小。例如,如果原始圖像是壓縮的JPEG(例如由相機拍攝),則生成的PNG文件實際上可能比原始JPEG大。

    一般來說,我更願意得到原始數據(如果在文件或包文件時,負載直接到NSData;如果它是從ALAssetsLibrary檢索到的東西,我會檢索ALAsset,並從該,該ALAssetRepresentation ,並且我會使用getBytes來獲取原始資產的原始二進制表示)。這避免了通過UIImage(特別是如果隨後使用UIImagePNGRepresentationUIImageJEPGRepresentation)。

  2. 如果要剝去EXIF數據,可以:

    • 創建從原始NSData圖像源;

    • 使用相同的「圖像數量」(幾乎總是1)和「類型」創建圖像目的地;

    • 當複製從源到目的地的圖片,告訴它適當的鍵(kCGImagePropertyExifDictionarykCGImagePropertyGPSDictionary應設置爲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; 
    } 
    

    注意,GPS信息是不是技術上的EXIF數據,但我相信你想刪除這一點。如果您想保留GPS數據,請從我的removeExifProperties字典中刪除kCGImagePropertyGPSDictionary條目。

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

    爲了完整起見,在IOS版本7.0之前,您可以從屬性中提取數據:

    - (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; 
    } 
    
+0

謝謝您的回答,這是幫助全。 但我用CGImage刪除EXIF && GPS後,圖像數據被壓縮,因爲我通過「writeImageToSavedPhotosAlbum」保存UIImage。 如果我將「kCGImageDestinationLossyCompressionQuality」添加爲1.0到「removeExifProperties」,則輸出圖像會比原始數據大。 你有任何建議保持圖像數據爲原始的,但剝離EXIF和GPS一些元數據? – 2015-04-16 08:56:25

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
  • 圖像複製到
  • 設置所需的元數據就可以了

怎麼做的第一步ISN」從文檔中非常清楚。所以,我看着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); 

因此,創建您的屬性字典蘋果顯示了文檔的方式,然後創建一個形象的目標和寫下所有內容,包括你的屬性。之後,您可以訪問NSMutableData對象並讀取圖像數據。