2014-08-31 11 views
6

Come si eliminano tutti i dati exif in una UIImage utilizzando l'obiettivo-c? Sono stato in grado di ottenere i dati exif utilizzando la seguente:Eliminazione di tutti i dati Exif in Objective-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; 

risposta

11

Un paio di pensieri:

  1. In generale il processo di caricamento di un'immagine dal NSData o dai contenuti di un file in un UIImage, ri-estrarre i dati con UIImagePNGRepresentation e il salvataggio che di nuovo ad un NSData eliminerà i metadati dall'immagine.

    Questa semplice tecnica ha i suoi svantaggi, però. In particolare, il processo di forzarlo a una rappresentazione PNG può influenzare notevolmente la dimensione dell'uscita NSData. Ad esempio, se l'immagine originale era un JPEG compresso (come catturato dalla fotocamera), il file PNG risultante può essere effettivamente più grande del JPEG originale.

    In genere io preferirei per ottenere i dati originali (se un file in Documenti o il fagotto, carico che direttamente ad un NSData, se si tratta di qualcosa recuperato dal ALAssetsLibrary, vorrei recuperare il ALAsset, e questo, il ALAssetRepresentation e da questo vorrei usare getBytes per ottenere la rappresentazione binaria originale di quella risorsa originale). Ciò evita lo sgancio a rotazione attraverso un UIImage (in particolare se successivamente utilizzando UIImagePNGRepresentation o UIImageJEPGRepresentation).

  2. Se si vuole mettere a nudo i dati EXIF, è possibile:

    • Creare una sorgente di immagini dall'originale NSData;

    • Creare una destinazione immagine, utilizzando lo stesso "numero di immagini" (quasi sempre 1) e il "tipo";

    • Quando si copiano le immagini dalla sorgente alla destinazione, dirgli che i tasti appropriati (kCGImagePropertyExifDictionary e kCGImagePropertyGPSDictionary deve essere impostato su kCFNull), che secondo la documentazione CGImageDestinationAddImageFromSource è come si specifica che chi deve essere rimosso nel destinazione se sono apparsi nella fonte).

    Pertanto, potrebbe sembrare:

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

    nota, le informazioni GPS non è tecnicamente i dati exif, ma suppongo che si voleva rimuovere quella, anche. Se si desidera mantenere i dati GPS, rimuovere la voce kCGImagePropertyGPSDictionary dal mio dizionario removeExifProperties.

  3. BTW, nel tuo codice per estrarre i metadati, sembra che tu stia lanciando lo CGImageMetadataRef come NSDictionary. Se la tecnica funziona, va bene, ma penso che CGImageMetadataRef è considerato un tipo di dati opaco, e che uno in realtà dovrebbe essere utilizzando CGImageMetadataCopyTags per estrarre la serie di tag:

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

    Per ragioni di completezza, nelle versioni iOS precedenti alla 7.0, è possibile estrarre i dati dalle proprietà:

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

Grazie per la risposta, è aiuto pieno. Ma dopo aver rimosso EXIF ​​e GPS con CGImage, i dati dell'immagine vengono compressi mentre salvataggio UIImage di "writeImageToSavedPhotosAlbum". Se aggiungo "kCGImageDestinationLossyCompressionQuality" come 1.0 a "removeExifProperties", l'immagine di output diventa più grande dei dati originali. Hai qualche suggerimento per mantenere i dati delle immagini come originali ma spoglia alcuni metadati come EXIF ​​e GPS? –

2

Secondo il Image I/O programming guide, è possibile utilizzare CGImageDestinationSetProperties per aggiungere un CFDictionaryRef delle proprietà.

Il loro codice di esempio è:

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. 

E non capisco il motivo per cui non hanno preso tutto il senso. Sto cercando di indovinare che cosa viene dopo sarebbe:

  • creare un CFImageDestinationRef
  • copiare l'immagine ad esso
  • impostare i metadati desiderato su di esso

Come fare il primo passo isn' t molto chiaro dai documenti. Così ho guardato il CGImageDestination reference, e sembra che si può fare in questo modo (non testato):

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

Così creano le proprietà dizionario del modo in cui Apple mostra nella documentazione, quindi creare una destinazione di immagine e scrivi tutto su di esso, comprese le tue proprietà. Successivamente è possibile accedere all'oggetto NSMutableData e leggere i dati dell'immagine.