2012-01-20 8 views
8

¿Cómo guardo los metadatos personalizados en una imagen cuando obtengo la imagen usando el AVFoundation framework?Guardar metadatos CUSTOM en una imagen tomada de AVFoundation en iOS

Sé que puedo acceder a las propiedades meteorológicas Tengo mi imagen como UIImage o CIImage pero las propiedades que parecen tener difieren entre sí (incluso si se trata de la misma imagen).

Hasta ahora acceder al diccionario como esto: (código tomado del blog con cafeína cacao)

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 ***"); 
     } 

y puedo ya sea salvar mi imagen como esta:

CIImage *testImage = [CIImage imageWithData:data]; 

     NSDictionary *propDict = [testImage properties]; 


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

O como esta

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 ninguna de las opciones devuelve mi Diccionario de datos brutos personalizados.

En resumen lo que quiero hacer es salvar mi propio objeto en un campo creado por mi (en este caso un objeto cmattitude)

PD: Cuando NSLOG el diccionario antes de su fusión con la imagen que tiene todos los archivos como los quiero.

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

Pero cuando NSLog el diccionario de la nueva imagen que me esto da para la 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; 
    }; 

Y si NSLog la UIImage me da aún menos información.

Gracias!

+0

Bueno, para empezar, su código está produciendo datos de imágenes enriquecidos con metadatos en una ubicación sostenida por la variable "destino", pero luego intenta guardarlo usando la variable "datos". ¡No me extraña que no funcione! –

+0

Últimamente estoy trabajando en imágenes, pasé mucho tiempo tratando de obtener buenos resultados con los marcos de trabajo de Apple. Sin embargo, incluso si logra cambiar los metadatos, necesita volver a procesar la imagen, quiero decir que debe crear una copia de la imagen en la que está trabajando. Incluso si tiene el mismo tamaño de archivo, etc. Después de buscar un poco de alternativa a los frameworks nativos, encontré el XMP Toolkit de Adobe. No solo los archivos de imagen puede alterar los metadatos en casi todos los archivos multimedia con XMP toolkit. Puede leer/escribir/alterar todos los espacios de nombres de metadatos. – mohacs

+0

@BenjaminWheeler no ... CGImageDestinationCreateWithData "Crea un destino de imagen que escribe en un objeto de datos mutable de Core Foundation", por lo que al pasarle una referencia NSMutableData escribo directamente a "datos". – Pochi

Respuesta

3

UIImage y CIImage no contienen todos los metadatos. De hecho, convertirlo de NSData a cualquiera de esos dos formatos eliminará una gran cantidad de metadatos, por lo que en mi humilde opinión, UIImage y CIImage solo deben usarse si planea mostrarlo en la interfaz de usuario o pasarlo a CoreImage.

Usted puede leer las propiedades de imagen como esta:

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

A continuación, puede convertir su NSDictionary a un NSMutableDictionary:

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

Después de eso, añada cualquier campos que le gustaría. Tenga en cuenta que los datos EXIF ​​ se encuentra por el acaparamiento de la kCGImagePropertyExifDictionary, GPS datos por el kCGImagePropertyGPSDictionary, y así sucesivamente:

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

vistazo al archivo CGImageProperties cabecera para todas las claves disponibles.

Bien, ahora que usted ha hecho cualquier cambio que necesita para los metadatos, añadiendo de nuevo toma un par de pasos más:

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

Y ahí lo tienen.

+0

¡Oye! Buen código aquí! Pero, @mikeho, tengo una pregunta: ¿Dónde se almacena la nueva Imagen? Creo que debo almacenarlo con '[newImage writeToFile: @"/Users/nikola/Desktop/newImage.jpg "atómicamente: SÍ];', pero si lo compruebo registrando las propiedades de ese archivo no tiene nuevas claves que he escrito ... –

+0

@NikolaMarkovic Hey, lo siento. No he tenido la oportunidad de responder. Sí, tienes que escribirlo como lo hiciste. Pero, ¿qué propiedades estás mirando? Necesita un visor EXIF ​​para ver los datos (o cargar los datos en Photoshop y debería mostrarle). – mikeho

+0

Perdón por llegar tarde con esta respuesta ... Guardo la nueva imagen en el escritorio, pero EXIF ​​sigue siendo la misma ... No puedo entender por qué ... Se comporta como si fuera protegida/inmutable, pero no sé por qué. –

Cuestiones relacionadas