2014-08-31 14 views
6

Làm thế nào để bạn loại bỏ tất cả dữ liệu exif trong một UIImage bằng cách sử dụng mục tiêu-c? Tôi đã có thể để có được những dữ liệu Exif sử dụng như sau:Tước tất cả dữ liệu Exif trong mục tiêu-C

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; 

Trả lời

11

Một vài suy nghĩ:

  1. Nói chung quá trình tải một hình ảnh từ NSData hoặc từ nội dung của một tập tin vào một UIImage, tái chiết xuất dữ liệu với UIImagePNGRepresentation và tiết kiệm mà lại để một NSData sẽ tách siêu dữ liệu khỏi hình ảnh.

    Kỹ thuật đơn giản này có nhược điểm của nó. Đáng chú ý, quá trình ép nó vào một đại diện PNG có thể ảnh hưởng đến kích thước của đầu ra NSData đáng kể, mặc dù. Ví dụ: nếu ảnh gốc là ảnh JPEG nén (chẳng hạn như máy ảnh chụp), tệp PNG kết quả thực sự có thể lớn hơn JPEG gốc.

    Nói chung tôi muốn để có được các dữ liệu gốc (nếu một tập tin trong tài liệu hoặc bó, tải trực tiếp đến một NSData; nếu nó là cái gì lấy từ ALAssetsLibrary, tôi sẽ lấy ALAsset, và từ đó, ALAssetRepresentation và từ đó tôi sẽ sử dụng getBytes để có được bản trình bày nhị phân gốc của nội dung gốc đó). Điều này tránh vòng qua một UIImage (đặc biệt nếu sau đó sử dụng UIImagePNGRepresentation hoặc UIImageJEPGRepresentation).

  2. Nếu bạn muốn dải dữ liệu Exif, bạn có thể:

    • Tạo một nguồn hình ảnh từ bản gốc NSData;

    • Tạo điểm đến hình ảnh, sử dụng cùng một "số lượng hình ảnh" (hầu như luôn luôn 1) và "loại";

    • Khi sao chép các hình ảnh từ nguồn đến đích, nói với nó rằng các phím thích hợp (kCGImagePropertyExifDictionarykCGImagePropertyGPSDictionary nên được đặt thành kCFNull), mà theo tài liệu CGImageDestinationAddImageFromSource là cách bạn xác định rằng những cần được loại bỏ trong điểm đến nếu chúng xuất hiện trong nguồn).

    Do đó, nó có thể trông giống như:

    - (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, thông tin GPS không phải là dữ liệu về mặt kỹ thuật Exif, nhưng tôi giả sử bạn muốn loại bỏ điều đó. Nếu bạn muốn giữ dữ liệu GPS, hãy xóa mục nhập kCGImagePropertyGPSDictionary khỏi từ điển removeExifProperties của tôi.

  3. BTW, trong mã của bạn để trích xuất dữ liệu meta, bạn dường như đang truyền CGImageMetadataRef làm NSDictionary. Nếu kỹ thuật của bạn hoạt động, đó là tốt, nhưng tôi nghĩ rằng CGImageMetadataRef được coi là một kiểu dữ liệu mờ đục, và rằng ai thực sự nên sử dụng CGImageMetadataCopyTags để trích xuất các mảng của các thẻ:

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

    Vì lợi ích của sự hoàn chỉnh, trong các phiên bản iOS trước 7.0, bạn có thể trích xuất các dữ liệu từ các thuộc tính:

    - (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

Cám ơn câu trả lời của bạn, nó giúp đầy đủ. Nhưng sau khi tôi xóa EXIF ​​&& GPS bằng CGImage, dữ liệu hình ảnh được nén khi tôi lưu UIImage bằng "writeImageToSavedPhotosAlbum". Nếu tôi thêm "kCGImageDestinationLossyCompressionQuality" là 1.0 vào "removeExifProperties", hình ảnh đầu ra sẽ lớn hơn dữ liệu gốc. Bạn có bất cứ đề xuất nào để giữ dữ liệu hình ảnh ban đầu nhưng loại bỏ một số siêu dữ liệu như EXIF ​​& GPS không? –

2

Theo Image I/O programming guide, bạn có thể sử dụng CGImageDestinationSetProperties để thêm một CFDictionaryRef của các thuộc tính.

mẫu mã của họ là:

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. 

Và tôi không hiểu tại sao họ không mang nó tất cả các cách. Tôi đoán điều gì sẽ đến tiếp theo sẽ là:

  • tạo CFImageDestinationRef
  • sao chép hình ảnh của bạn để nó
  • thiết lập siêu dữ liệu của bạn mong muốn trên nó

Làm thế nào để thực hiện bước đầu tiên isn' t rất rõ ràng từ các tài liệu. Vì vậy, tôi nhìn vào CGImageDestination reference, và có vẻ như nó có thể được thực hiện theo cách này (chưa được thử nghiệm):

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

Vì vậy, tạo ra tài sản của bạn từ điển cách của Apple cho thấy trong các tài liệu, sau đó tạo ra một điểm đến hình ảnh và viết mọi thứ cho nó, kể cả tài sản của bạn. Sau đó, bạn có thể truy cập đối tượng NSMutableData và đọc dữ liệu hình ảnh của bạn.

Các vấn đề liên quan