{"id":24,"date":"2012-07-12T15:13:09","date_gmt":"2012-07-12T07:13:09","guid":{"rendered":"http:\/\/hmu023267.chinaw3.com\/wordpress\/?p=24"},"modified":"2012-07-12T15:13:09","modified_gmt":"2012-07-12T07:13:09","slug":"ios-exif%e7%9b%b8%e5%85%b3%e6%96%87%e7%ab%a0","status":"publish","type":"post","link":"https:\/\/www.sunyuping.com\/index.php\/2012\/07\/12\/ios-exif%e7%9b%b8%e5%85%b3%e6%96%87%e7%ab%a0\/","title":{"rendered":"ios exif\u76f8\u5173\u6587\u7ae0"},"content":{"rendered":"<div>\n<h2><\/h2>\n<\/div>\n<div id=\"content\">\n<p>1.ALAssetRepresentation* representation = [[self assetAtIndex:index] defaultRepresentation];\/\/ create a buffer to hold the data for the asset&#8217;s image<\/p>\n<p>uint8_t *buffer = (Byte*)malloc(representation.size);\/\/ copy the data from the asset into the buffer<br \/>\nNSUInteger length = [representation getBytes:buffer fromOffset: 0.0 length:representation.size error:nil];<br \/>\nif (length==0) return nil;\/\/ convert the buffer into a NSData object, free the buffer after<br \/>\nNSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:representation.size freeWhenDone:YES];\/\/ setup a dictionary with a UTI hint. The UTI hint identifies the type of image we are dealing with (ie. a jpeg, png, or a possible RAW file)\/\/ specify the source hint<br \/>\nNSDictionary* sourceOptionsDict = [NSDictionary dictionaryWithObjectsAndKeys:(id)[representation UTI] ,kCGImageSourceTypeIdentifierHint,nil];\/\/ create a CGImageSource with the NSData. A image source can contain x number of thumbnails and full images.<br \/>\nCGImageSourceRef sourceRef = CGImageSourceCreateWithData((CFDataRef) adata, (CFDictionaryRef) sourceOptionsDict);<br \/>\n[adata release];<br \/>\nCFDictionaryRef imagePropertiesDictionary;\/\/ get a copy of the image properties from the CGImageSourceRef<br \/>\nimagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(sourceRef,0, NULL);<br \/>\nCFNumberRef imageWidth = (CFNumberRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyPixelWidth);<br \/>\nCFNumberRef imageHeight = (CFNumberRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyPixelHeight);<br \/>\nint w = 0;int h = 0;CFNumberGetValue(imageWidth, kCFNumberIntType, &amp;w);<br \/>\nCFNumberGetValue(imageHeight, kCFNumberIntType, &amp;h);<br \/>\n\/\/ cleanup memory<br \/>\nCFRelease(imagePropertiesDictionary);<br \/>\nCFRelease(sourceRef);<\/p>\n<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>2.<br \/>\n&nbsp;<\/p>\n<p>The API has changed the rules slightly and you dont get direct file system access to the iPhoto library any more. Instead you get asset library URL&#8217;s like this.<\/p>\n<p>assets-library:\/\/asset\/asset.JPG?id=1000000003&amp;ext=JPG<\/p>\n<p>You use the ALAssetLibrary object to access the ALAsset object via the URL.<\/p>\n<p>so from the docs for ALAssetLibrary throw this in a header (or your source)<\/p>\n<p>typedefvoid(^ALAssetsLibraryAssetForURLResultBlock)(ALAsset*asset);<br \/>\ntypedefvoid(^ALAssetsLibraryAccessFailureBlock)(NSError*error);<br \/>\nwhich isnt strictly needed but keeps things pretty.<br \/>\nand then in your source.<\/p>\n<p>-(void)findLargeImage<br \/>\n{<br \/>\nNSString*mediaurl =[self.node valueForKey:kVMMediaURL];<\/p>\n<p>\/\/<br \/>\nALAssetsLibraryAssetForURLResultBlock resultblock =^(ALAsset*myasset)<br \/>\n{<br \/>\nALAssetRepresentation*rep =[myasset defaultRepresentation];<br \/>\nCGImageRef iref =[rep fullResolutionImage];<br \/>\nif(iref){<br \/>\nlargeimage =[UIImage imageWithCGImage:iref];<br \/>\n[largeimage retain];<br \/>\n}<br \/>\n};<\/p>\n<p>\/\/<br \/>\nALAssetsLibraryAccessFailureBlock failureblock \u00a0=^(NSError*myerror)<br \/>\n{<br \/>\nNSLog(@&#8221;booya, cant get image &#8211; %@&#8221;,[myerror localizedDescription]);<br \/>\n};<\/p>\n<p>if(mediaurl &amp;&amp;[mediaurl length]&amp;&amp;![[mediaurl pathExtension] isEqualToString:AUDIO_EXTENSION])<br \/>\n{<br \/>\n[largeimage release];<br \/>\nNSURL *asseturl =[NSURL URLWithString:mediaurl];<br \/>\nALAssetsLibrary* assetslibrary =[[[ALAssetsLibrary alloc] init] autorelease];<br \/>\n[assetslibrary assetForURL:asseturl<br \/>\nresultBlock:resultblock<br \/>\nfailureBlock:failureblock];<br \/>\n}<br \/>\n}<br \/>\nA couple of things to note are that this uses blocks which were new to me before I started my iOS4 porting but you might like to look at<\/p>\n<p><a href=\"http:\/\/www.mikeash.com\/pyblog\/friday-qa-2008-12-26.html\">http:\/\/www.mikeash.com\/pyblog\/friday-qa-2008-12-26.html<\/a><\/p>\n<p>and<\/p>\n<p><a href=\"http:\/\/developer.apple.com\/library\/ios\/#documentation\/Cocoa\/Conceptual\/Blocks\/Articles\/00_Introduction.html\">http:\/\/developer.apple.com\/library\/ios\/#documentation\/Cocoa\/Conceptual\/Blocks\/Articles\/00_Introduction.html<\/a><\/p>\n<p>They bend your head a little but if you think of them as notification selectors or callbacks it kind of helps.<\/p>\n<p>Also<\/p>\n<ul>\n<li>when findLargeImage returns theresultblock wont have run yet as itsa callback. So largeImage wont bevalid yet.<\/li>\n<li>largeImage needs to be aninstance variable not scoped to themethod.<\/li>\n<\/ul>\n<p>I use this construct to do this when using the method but you may find something more suitable to your use.<\/p>\n<p>[node.view findLargeImage];<br \/>\nUIImage*thumb = node.view.largeImage;<br \/>\nif(thumb){ blah blah }<br \/>\nThats what I learned while trying to get this working anyway.<\/p>\n<p><strong>iOS 5 update<\/strong><\/p>\n<p>When the result block fires seems to be a bit slower with iOS5 &amp; maybe single core devices so I couldnt rely on the image to be available directly after calling findLargeImage. So I changed it to call out to a delegate.<\/p>\n<p>@protocolHiresImageDelegate&lt;NSObject&gt;<br \/>\n@optional<br \/>\n-(void)hiresImageAvailable:(UIImage*)aimage;<br \/>\n@end<br \/>\nand comme c\u00e1<\/p>\n<p>\/\/<br \/>\nALAssetsLibraryAssetForURLResultBlock resultblock =^(ALAsset*myasset)<br \/>\n{<br \/>\nALAssetRepresentation*rep =[myasset defaultRepresentation];<br \/>\nCGImageRef iref =[rep fullResolutionImage];<br \/>\nif(iref){<br \/>\nUIImage*largeimage =[UIImage imageWithCGImage:iref];<br \/>\n[delegate hiresImageAvailable:large];<br \/>\n}<br \/>\n};<br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<\/p>\n<p>3.<\/p>\n<p>I am developing one project. The requirements are like that, User will open the cam thru application and on the capture of Image, some data will be appended to the captured image&#8217;s metadata. I have gone thru some of the forums. I tried to code this logic. I guess, I have reached to the point, but something is missing as I am not able to see the metadata that I am appending to the image. My code as follows,<\/p>\n<p>-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)dictionary<br \/>\n{<\/p>\n<p>[picker dismissModalViewControllerAnimated:YES];<\/p>\n<p>NSData*dataOfImageFromGallery =UIImageJPEGRepresentation(image,0.5);<br \/>\nNSLog(@&#8221;Image length: \u00a0%d&#8221;,[dataOfImageFromGallery length]);<\/p>\n<p>CGImageSourceRef source;<br \/>\nsource =CGImageSourceCreateWithData((CFDataRef)dataOfImageFromGallery, NULL);<\/p>\n<p>NSDictionary*metadata =(NSDictionary*)CGImageSourceCopyPropertiesAtIndex(source,0, NULL);<\/p>\n<p>NSMutableDictionary*metadataAsMutable =[[metadata mutableCopy]autorelease];<br \/>\n[metadata release];<\/p>\n<p>NSMutableDictionary*EXIFDictionary=[[[metadataAsMutable objectForKey:(NSString*)kCGImagePropertyExifDictionary]mutableCopy]autorelease];<br \/>\nNSMutableDictionary*GPSDictionary=[[[metadataAsMutable objectForKey:(NSString*)kCGImagePropertyGPSDictionary]mutableCopy]autorelease];<\/p>\n<p>if(!EXIFDictionary)<br \/>\n{<br \/>\n\/\/if the image does not have an EXIF dictionary (not all images do), then create one for us to use<br \/>\nEXIFDictionary=[NSMutableDictionary dictionary];<br \/>\n}<\/p>\n<p>if(!GPSDictionary)<br \/>\n{<br \/>\nGPSDictionary=[NSMutableDictionary dictionary];<br \/>\n}<\/p>\n<p>\/\/Setup GPS dict &#8211;<br \/>\n\/\/I am appending my custom data just to test the logic\u2026\u2026..<\/p>\n<p>[GPSDictionary setValue:[NSNumber numberWithFloat:1.1] forKey:(NSString*)kCGImagePropertyGPSLatitude];<br \/>\n[GPSDictionary setValue:[NSNumber numberWithFloat:2.2] forKey:(NSString*)kCGImagePropertyGPSLongitude];<br \/>\n[GPSDictionary setValue:@&#8221;lat_ref&#8221; forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];<br \/>\n[GPSDictionary setValue:@&#8221;lon_ref&#8221; forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];<br \/>\n[GPSDictionary setValue:[NSNumber numberWithFloat:3.3] forKey:(NSString*)kCGImagePropertyGPSAltitude];<br \/>\n[GPSDictionary setValue:[NSNumber numberWithShort:4.4] forKey:(NSString*)kCGImagePropertyGPSAltitudeRef];<br \/>\n[GPSDictionary setValue:[NSNumber numberWithFloat:5.5] forKey:(NSString*)kCGImagePropertyGPSImgDirection];<br \/>\n[GPSDictionary setValue:@&#8221;_headingRef&#8221; forKey:(NSString*)kCGImagePropertyGPSImgDirectionRef];<\/p>\n<p>[EXIFDictionary setValue:@&#8221;xml_user_comment&#8221; forKey:(NSString*)kCGImagePropertyExifUserComment];<br \/>\n\/\/add our modified EXIF data back into the image\u2019s metadata<br \/>\n[metadataAsMutable setObject:EXIFDictionary forKey:(NSString*)kCGImagePropertyExifDictionary];<br \/>\n[metadataAsMutable setObject:GPSDictionary forKey:(NSString*)kCGImagePropertyGPSDictionary];<\/p>\n<p>CFStringRef UTI =CGImageSourceGetType(source);<br \/>\nNSMutableData*dest_data =[NSMutableData data];<\/p>\n<p>CGImageDestinationRef destination =CGImageDestinationCreateWithData((CFMutableDataRef) dest_data, UTI,1, NULL);<\/p>\n<p>if(!destination)<br \/>\n{<br \/>\nNSLog(@&#8221;&#8212;&#8212;&#8212; Could not create image destination&#8212;&#8212;&#8212;&#8220;);<br \/>\n}<\/p>\n<p>CGImageDestinationAddImageFromSource(destination, source,0,(CFDictionaryRef) metadataAsMutable);<\/p>\n<p>BOOL success = NO;<br \/>\nsuccess =CGImageDestinationFinalize(destination);<\/p>\n<p>if(!success)<br \/>\n{<br \/>\nNSLog(@&#8221;&#8212;&#8212;&#8211; could not create data from image destination&#8212;&#8212;&#8212;-&#8220;);<br \/>\n}<\/p>\n<p>UIImage* image1 =[[UIImage alloc] initWithData:dest_data];<br \/>\nUIImageWriteToSavedPhotosAlbum(image1, self, nil, nil);<br \/>\n}<\/p>\n<p>&nbsp;<\/p>\n<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\n4.<br \/>\n#import &lt;ImageIO\/CGImageSource.h&gt;<br \/>\n#import &lt;ImageIO\/CGImageProperties.h&gt;<\/p>\n<p>NSString* imagePath = resource.file.filePath;<br \/>\nNSURL* url = [NSURL fileURLWithPath:imagePath];<br \/>\nCGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL);<br \/>\nNSDictionary* metadata = (NSDictionary *)(NSString*)CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);<br \/>\nNSDictionary* exifData = [metadata valueForKey:(NSString*)kCGImagePropertyExifDictionary];<br \/>\nNSString* dateString = [[exifData valueForKey:(NSString*)kCGImagePropertyExifDateTimeDigitized] value];<br \/>\nNSLog(dateString);<br \/>\n[metadata release];<br \/>\nCFRelease(source);<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>1.ALAssetRepresentation* representation = [[self assetA &#8230; <a title=\"ios exif\u76f8\u5173\u6587\u7ae0\" class=\"read-more\" href=\"https:\/\/www.sunyuping.com\/index.php\/2012\/07\/12\/ios-exif%e7%9b%b8%e5%85%b3%e6%96%87%e7%ab%a0\/\" aria-label=\"\u9605\u8bfb ios exif\u76f8\u5173\u6587\u7ae0\">\u9605\u8bfb\u66f4\u591a<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[13],"class_list":["post-24","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-uncategorized-2"],"_links":{"self":[{"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/posts\/24","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/comments?post=24"}],"version-history":[{"count":0,"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/posts\/24\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/media?parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/categories?post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sunyuping.com\/index.php\/wp-json\/wp\/v2\/tags?post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}