2012-01-20 32 views
8

當我使用AVFoundation framework獲取圖像時,如何將自定義元數據保存在圖像中?在iOS中的AVFoundation拍攝的圖像中保存CUSTOM元數據

我知道我可以訪問屬性天氣它我有我的形象爲UIImageCIImage但這些似乎有不同的屬性(即使它是相同的圖像)。

到目前爲止,我查閱字典是這樣的:(從含咖啡因的可可博客代碼取)

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

而且我可以節省我的形象是這樣的:

CIImage *testImage = [CIImage imageWithData:data]; 

     NSDictionary *propDict = [testImage properties]; 


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

或者這樣

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都沒有選項返回我的自定義原始數據字典。

總之就是我想要做的是挽救我自己的對象由自己創造了一個場(在這種情況下cmattitude對象)

PD:當我與圖像合併之前NSLOG字典它確實有像我想要的所有文件。

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

但是當我的新形象的NSLog字典它給了我這樣的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; 
    }; 

如果我NSLogUIImage它給我更少的信息。

謝謝!

+0

對於初學者來說,您的代碼正在由變量「destination」所保存的位置生成元數據豐富的圖像數據,但您嘗試使用變量「data」保存它。難怪它不起作用! –

+0

最近我正在處理圖像,花了很多時間試圖用Apple的框架取得好成績。但是,即使您設法更改元數據,您也需要重新處理圖像本身,但我的意思是您必須創建您正在處理的圖像的副本。即使它看起來相同的文件大小變化等。經過本地框架的一點搜索替代之後,我找到了Adobe的XMP Toolkit。不僅僅是圖像文件,您可以使用XMP工具包在幾乎所有媒體文件中更改元數據。它可以讀取/寫入/更改所有元數據名稱空間。 – mohacs

+0

@BenjaminWheeler no ... CGImageDestinationCreateWithData「創建一個寫入Core Foundation可變數據對象的映像目標」,通過傳遞給它一個NSMutableData引用,我直接寫入「data」。 – Pochi

回答

3

UIImageCIImage不包含所有的元數據。實際上,將它從NSData轉換爲這兩種格式中的任意一種都會剝離大量元數據,因此,恕我直言,UIImage和應該僅在您計劃在UI中顯示或將其傳遞到CoreImage時使用。

你可以這樣寫的圖像屬性:

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

然後,您可以將您的NSDictionaryNSMutableDictionary

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

之後,添加你想什麼領域。需要注意的是EXIF數據由kCGImagePropertyGPSDictionary抓住kCGImagePropertyExifDictionaryGPS數據發現,依此類推:

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

看那CGImageProperties頭文件中所有可用的鑰匙。

好了,現在你已作出任何所需的更改需要元數據,其重新添加需要幾多個步驟:

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

有你有它。

+0

嘿!好的代碼在這裏!但是,@mikeho,我有一個問題: newImage存儲在哪裏? 我相信我必須用'[newImage writeToFile:@「/ Users/nikola/Desktop/newImage.jpg」atomically:YES];'來自己存儲它,'但是如果我通過記錄該文件的屬性來檢查它,我寫的新鑰匙... –

+0

@NikolaMarkovic嘿,對不起。沒有機會迴應。是的,你必須按照你所做的方式來寫。但是你在看哪些物業?您需要一個EXIF查看器來查看數據(或將數據加載到Photoshop中,並且它應該會顯示您)。 – mikeho

+0

對不起,這個答案遲到了.. 我將新圖像保存在桌面上,但它的EXIF保持不變..我不明白爲什麼..它的行爲像它的保護/不可變,但我不明白爲什麼。 –

相關問題