2012-01-20 2 views
8

Come faccio a salvare i metadati personalizzati in un'immagine quando ottengo l'immagine usando lo AVFoundation framework?Salvare i metadati CUSTOM in un'immagine presa da AVFoundation in iOS

So che posso accedere alle proprietà weather it I have my image come UIImage o CIImage ma le proprietà che questi sembrano differire l'una dall'altra (anche se è la stessa immagine).

Finora ho accedere al dizionario come questo: (codice preso da caffeina Cacao blog)

NSLog(@"about to request a capture from: %@", [self stillImageOutput]); 
    [[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) 
    { 

NSData *jpeg = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer] ; 

     CGImageSourceRef source = CGImageSourceCreateWithData((__bridge_retained CFDataRef)jpeg, NULL); 

     //get all the metadata in the image 
     NSDictionary *metadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL); 

     //make the metadata dictionary mutable so we can add properties to it 
     NSMutableDictionary *metadataAsMutable = [metadata mutableCopy]; 

     NSMutableDictionary *EXIFDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]; 
     NSMutableDictionary *GPSDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]; 
     NSMutableDictionary *RAWDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyRawDictionary]mutableCopy]; 

     if(!EXIFDictionary) { 
      EXIFDictionary = [NSMutableDictionary dictionary]; 
     } 
     if(!GPSDictionary) { 
      GPSDictionary = [NSMutableDictionary dictionary]; 
     } 
     if(!RAWDictionary) { 
      RAWDictionary = [NSMutableDictionary dictionary]; 
     } 

     float _lat = gpsInfo.coordinate.latitude; 
     float _lon = gpsInfo.coordinate.longitude; 
     float _alt = gpsInfo.altitude; 
     NSDate *_date = gpsInfo.timestamp; 
     float _heading = gpsInfo.course;; 

     [GPSDictionary setValue:[NSNumber numberWithFloat:_lat] 
         forKey:(NSString*)kCGImagePropertyGPSLatitude]; 
     [GPSDictionary setValue:[NSNumber numberWithFloat:_lon] 
         forKey:(NSString*)kCGImagePropertyGPSLongitude]; 
     [GPSDictionary setValue:[NSNumber numberWithFloat:_alt] 
         forKey:(NSString*)kCGImagePropertyGPSAltitude]; 
     [GPSDictionary setValue:_date 
         forKey:(NSString*)kCGImagePropertyGPSDateStamp]; 
     [GPSDictionary setValue:[NSNumber numberWithFloat:_heading] 
         forKey:(NSString*)kCGImagePropertyGPSImgDirection]; 


     [EXIFDictionary setValue:@"Wasup" forKey:(NSString *)kCGImagePropertyExifUserComment]; 

     [RAWDictionary setValue:attitude forKey:@"Attitude"]; 

     //Add the modified Data back into the image’s metadata 
     [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary]; 
     [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary]; 
     [metadataAsMutable setObject:RAWDictionary forKey:(NSString *)kCGImagePropertyRawDictionary]; 

     NSLog(@"Info: %@",metadataAsMutable); 

     CFStringRef UTI = CGImageSourceGetType(source); //this is the type of image (e.g., public.jpeg) 

     //this will be the data CGImageDestinationRef will write into 
     NSMutableData *data = [NSMutableData data]; 

     CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)data,UTI,1,NULL); 

     if(!destination) { 
      NSLog(@"***Could not create image destination ***"); 
     } 

     //add the image contained in the image source to the destination, overidding the old metadata with our modified metadata 

     CGImageDestinationAddImageFromSource(destination,source,0, (__bridge CFDictionaryRef) metadataAsMutable); 

     //tell the destination to write the image data and metadata into our data object. 
     //It will return false if something goes wrong 
     BOOL success = NO; 
     success = CGImageDestinationFinalize(destination); 

     if(!success) { 
      NSLog(@"***Could not create data from image destination ***"); 
     } 

e posso sia salvare la mia immagine in questo modo:

CIImage *testImage = [CIImage imageWithData:data]; 

     NSDictionary *propDict = [testImage properties]; 


     NSLog(@"Properties %@",propDict); 

O come questo

UIImage *imageMod = [[UIImage alloc] initWithData:data]; 


CGImageSourceRef source2 = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); 

     //get all the metadata in the image 
NSDictionary *metadata2 = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source2,0,NULL); 

NSLog(@"WASD: %@",metadata2); 

BUt nessuna delle opzioni restituisce il mio dizionario personalizzato dei dati grezzi.

In sintesi quello che voglio fare è salvare il mio proprio oggetto in un campo creato da me (in questo caso un oggetto cmattitude)

PD: Quando ho NSLOG dizionario prima di fondersi con l'immagine che deve avere tutti i file come li voglio

Info: { 
    ColorModel = RGB; 
    DPIHeight = 72; 
    DPIWidth = 72; 
    Depth = 8; 
    Orientation = 6; 
    PixelHeight = 1080; 
    PixelWidth = 1920; 
    "{Exif}" =  { 
     ApertureValue = "2.526069"; 
     BrightnessValue = "4.013361"; 
     ColorSpace = 1; 
     ComponentsConfiguration =   (
      1, 
      2, 
      3, 
      0 
     ); 
     ExifVersion =   (
      2, 
      2, 
      1 
     ); 
     ExposureMode = 0; 
     ExposureProgram = 2; 
     ExposureTime = "0.03333334"; 
     FNumber = "2.4"; 
     Flash = 16; 
     FlashPixVersion =   (
      1, 
      0 
     ); 
     FocalLenIn35mmFilm = 35; 
     FocalLength = "4.28"; 
     ISOSpeedRatings =   (
      80 
     ); 
     MeteringMode = 5; 
     PixelXDimension = 1920; 
     PixelYDimension = 1080; 
     SceneCaptureType = 0; 
     SensingMethod = 2; 
     Sharpness = 0; 
     ShutterSpeedValue = "4.906905"; 
     SubjectArea =   (
      959, 
      539, 
      518, 
      388 
     ); 
     UserComment = "Wazup"; 
     WhiteBalance = 0; 
    }; 
    "{GPS}" =  { 
     Altitude = 102; 
     DateStamp = "2012-01-20 06:55:48 +0000"; 
     ImgDirection = "-1"; 
     Latitude = "35.02496"; 
     Longitude = "135.754"; 
    }; 
    "{Raw}" =  { 
     Attitude = "Pitch: 50.913760, Roll: 36.342350, Yaw: -164.272361 @ 0.048291\n"; 
    }; 
    "{TIFF}" =  { 
     Orientation = 6; 
     ResolutionUnit = 2; 
     XResolution = 72; 
     YResolution = 72; 
     "_YCbCrPositioning" = 1; 
    }; 

Ma quando NSLog il dizionario della nuova immagine che mi dà questo per il CIIMage:

Properties { 
    ColorModel = RGB; 
    DPIHeight = 72; 
    DPIWidth = 72; 
    Depth = 8; 
    Orientation = 6; 
    PixelHeight = 1080; 
    PixelWidth = 1920; 
    "{Exif}" =  { 
     ApertureValue = "2.526069"; 
     BrightnessValue = "4.013361"; 
     ColorSpace = 1; 
     ComponentsConfiguration =   (
      0, 
      0, 
      0, 
      1 
     ); 
     ExifVersion =   (
      2, 
      2, 
      1 
     ); 
     ExposureMode = 0; 
     ExposureProgram = 2; 
     ExposureTime = "0.03333334"; 
     FNumber = "2.4"; 
     Flash = 16; 
     FlashPixVersion =   (
      1, 
      0 
     ); 
     FocalLenIn35mmFilm = 35; 
     FocalLength = "4.28"; 
     ISOSpeedRatings =   (
      80 
     ); 
     MeteringMode = 5; 
     PixelXDimension = 1920; 
     PixelYDimension = 1080; 
     SceneCaptureType = 0; 
     SensingMethod = 2; 
     Sharpness = 0; 
     ShutterSpeedValue = "4.906905"; 
     SubjectArea =   (
      959, 
      539, 
      518, 
      388 
     ); 
     UserComment = "Wazup"; 
     WhiteBalance = 0; 
    }; 
    "{GPS}" =  { 
     Altitude = 102; 
     ImgDirection = 0; 
     Latitude = "35.025"; 
     Longitude = "135.754"; 
    }; 
    "{JFIF}" =  { 
     DensityUnit = 1; 
     JFIFVersion =   (
      1, 
      1 
     ); 
     XDensity = 72; 
     YDensity = 72; 
    }; 
    "{TIFF}" =  { 
     Orientation = 6; 
     ResolutionUnit = 2; 
     XResolution = 72; 
     YResolution = 72; 
     "_YCbCrPositioning" = 1; 
    }; 

E se io NSLog l'UIImage mi dà ancora meno informazioni.

Grazie!

+0

Bene per i principianti, il codice sta producendo dati di immagini arricchiti con metadati in una posizione detenuta dalla variabile "destinazione", ma poi si tenta di salvarlo utilizzando la variabile "dati". Non c'è da stupirsi che non funzioni! –

+0

Ultimamente sto lavorando su immagini, ho passato molto tempo a cercare di ottenere buoni risultati con i framework Apple. Tuttavia, anche se riesci a cambiare i metadati devi rielaborare l'immagine stessa, voglio dire che devi creare una copia dell'immagine su cui stai lavorando. Anche se sembra la stessa modifica delle dimensioni del file, ecc. Dopo una piccola ricerca alternativa ai framework nativi, ho trovato Adobe XMP Toolkit. Non solo i file di immagine è possibile modificare i metadati all'interno di quasi tutti i file multimediali con XMP toolkit. Può leggere/scrivere/modificare tutti gli spazi dei nomi dei metadati. – mohacs

+0

@BenjaminWheeler no ... CGImageDestinationCreateWithData "Crea una destinazione dell'immagine che scrive su un oggetto dati mutabile di Core Foundation", quindi passando ad esso un riferimento NSMutableData che sto scrivendo direttamente ai "dati". – Pochi

risposta

3

UIImage e CIImage non contengono tutti i metadati. In effetti, la conversione da uno di questi due formati eliminerà molti metadati, quindi IMHO, UIImage e CIImage devono essere utilizzati solo se si prevede di visualizzarli nell'interfaccia utente o di passarli a CoreImage.

È possibile leggere le proprietà immagine come questo:

- (NSDictionary *)getImageProperties:(NSData *)imageData { 
    // get the original image metadata 
    CGImageSourceRef imageSourceRef = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL); 
    CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSourceRef, 0, NULL); 
    NSDictionary *props = (__bridge_transfer NSDictionary *) properties; 
    CFRelease(imageSourceRef); 

    return props; 
} 

È quindi possibile convertire il vostro NSDictionary ad un NSMutableDictionary:

NSDictionary *props = [self getImageProperties:imageData]; 
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:props]; 

Dopo di che, aggiungere qualsiasi campi che si desidera. Si noti che i dati EXIF ​​ viene trovato afferrando il GPS kCGImagePropertyExifDictionary, dati dal kCGImagePropertyGPSDictionary, e così via:

NSMutableDictionary *exifDictionary = properties[(__bridge NSString *) kCGImagePropertyExifDictionary]; 

guardare il file CGImageProperties intestazione per tutte le chiavi disponibili.

Bene, ora che avete fatto tutte le modifiche necessarie alle metadati, aggiungendo riprende un altro paio di passi:

// incoming image data 
NSData *imageData; 

// create the image ref 
CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef) imageData); 
CGImageRef imageRef = CGImageCreateWithJPEGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault); 

// the updated properties from above 
NSMutableDictionary *mutableDictionary; 

// create the new output data 
CFMutableDataRef newImageData = CFDataCreateMutable(NULL, 0); 
// my code assumes JPEG type since the input is from the iOS device camera 
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef) @"image/jpg", kUTTypeImage); 
// create the destination 
CGImageDestinationRef destination = CGImageDestinationCreateWithData(newImageData, type, 1, NULL); 
// add the image to the destination 
CGImageDestinationAddImage(destination, imageRef, (__bridge CFDictionaryRef) mutableDictionary); 
// finalize the write 
CGImageDestinationFinalize(destination); 

// memory cleanup 
CGDataProviderRelease(imgDataProvider); 
CGImageRelease(imageRef); 
CFRelease(type); 
CFRelease(destination); 

// your new image data 
NSData *newImage = (__bridge_transfer NSData *)newImageData; 

E il gioco è fatto.

+0

Ehi! Bel codice qui! Ma, @ mikeho, ho una domanda: Dove è memorizzata la nuova immagine? Credo di doverlo memorizzare io stesso con '[newImage writeToFile: @"/Users/nikola/Desktop/newImage.jpg "atomicamente: YES];', ma se lo controllo registrando le proprietà di quel file non ha nuove chiavi che ho scritto ... –

+0

@NikolaMarkovic Ehi, mi dispiace. Non ho avuto la possibilità di rispondere. Sì, devi scriverlo come hai fatto tu. Ma quali proprietà stai guardando? Hai bisogno di un visualizzatore EXIF ​​per vedere i dati (o caricare i dati in Photoshop e dovrebbe mostrarti). – mikeho

+0

Ci scusiamo per il ritardo con questa risposta .. Ho salvato la nuova immagine sul desktop, ma è EXIF ​​che rimane la stessa .. Non riesco a capire perché .. Si comporta come se fosse protetta/immutabile, ma non lo faccio perché. –

Problemi correlati