Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImagePickerController and extracting EXIF data from existing photos

It's well known that UIImagePickerController doesn't return the metadata of the photo after selection. However, a couple of apps in the app store (Mobile Fotos, PixelPipe) seem to be able to read the original files and the EXIF data stored within them, enabling the app to extract the geodata from the selected photo.

They seem to do this by reading the original file from the /private/var/mobile/Media/DCIM/100APPLE/ folder and running it through an EXIF library.

However, I can't work out a way of matching a photo returned from the UIImagePickerController to a file on disk. I've explored file sizes, but the original file is a JPEG, whilst the returned image is a raw UIImage, making it impossible to know the file size of the image that was selected.

I'm considering making a table of hashes and matching against the first x pixels of each image. This seems a bit over the top though, and probably quite slow.

Any suggestions?

like image 679
tomtaylor Avatar asked Aug 06 '09 13:08

tomtaylor


People also ask

How do I get EXIF data from a photo?

Viewing EXIF data in Windows is easy. Just right-click on the photo in question and select “Properties”. Click on the “Details” tab and scroll down—you'll see all kinds of information about the camera used, and the settings the photo was taken with.

What is EXIF Extractor?

Details. Retrieve Exif Data from image binary data. This extension can be used in page or logic actions, to retrieve stored Exif data from an image. The image binary can be presented as a parameter to one of the functions in the XIF.

What happens to EXIF data once an image is uploaded to Facebook?

When you upload a photo to Facebook, the EXIF data is stripped from the image when it is uploaded. You can test this yourself: Take a photo with a smartphone (with GPS and location services enabled), then use the aforementioned online EXIF viewer to see all the data from the EXIF data recorded for the image.


1 Answers

Have you took a look at this exif iPhone library?

http://code.google.com/p/iphone-exif/

Gonna try it on my side. I'd like to get the GPS (geotags) coordinates from the picture that has been taken with the UIImagePickerController :/

After a deeper look, this library seems to take NSData info as an input and the UIImagePickerController returns a UIImage after taking a snapshot. In theory, if we use the selected from the UIkit category for UIImage

NSData * UIImageJPEGRepresentation (    UIImage *image,    CGFloat compressionQuality ); 

Then we can convert the UIImage into a NSData instance and then use it with the iPhone exif library.

UPDATE:
I gave a test to the library mentioned above and it seems to work. However because of my limited knwoledge about the EXIF format and the lack of high level API in the library, I don't manage to get the values for the EXIF tags. Here's my code in case any of you can go further :

 #import "EXFJpeg.h"  - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {     NSLog(@"image picked %@ with info %@", image, editingInfo);     NSData* jpegData = UIImageJPEGRepresentation (image,0.5);     EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];     [jpegScanner scanImageData: jpegData];     EXFMetaData* exifData = jpegScanner.exifMetaData;     EXFJFIF* jfif = jpegScanner.jfif;     EXFTag* tagDefinition = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_DateTime]];     //EXFTag* latitudeDef = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_GPSLatitude]];     //EXFTag* longitudeDef = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_GPSLongitude]];     id latitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLatitude]];     id longitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLongitude]];     id datetime = [exifData tagValue:[NSNumber numberWithInt:EXIF_DateTime]];     id t = [exifData tagValue:[NSNumber numberWithInt:EXIF_Model]]; .... .... 

The retrieving of tags definition is OK, but all tag values returns nil :(

In case you want to give a try to the library, you need to define a global variable to get it running (as explained in the doc but hum.. :/)

BOOL gLogging = FALSE;

UPDATE 2
Answer here : iPhone - access location information from a photo A UIImage does not encapsulate the meta information, so we're stuck : for sure, no EXIF info will be given through this interface.

FINAL UPDATE
Ok I managed to get it working, at least to geotag properly pictures returned by the picker.
Before triggering the UIImagePickerController, it's up to you to use the CLLocationManager to retrieve the current CLocation
Once you have it, you can use this method that uses exif-iPhone library to geotag the UIImage from the CLLocation :

  -(NSData*) geotagImage:(UIImage*)image withLocation:(CLLocation*)imageLocation {     NSData* jpegData =  UIImageJPEGRepresentation(image, 0.8);     EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];     [jpegScanner scanImageData: jpegData];     EXFMetaData* exifMetaData = jpegScanner.exifMetaData;     // end of helper methods      // adding GPS data to the Exif object      NSMutableArray* locArray = [self createLocArray:imageLocation.coordinate.latitude];      EXFGPSLoc* gpsLoc = [[EXFGPSLoc alloc] init];      [self populateGPS: gpsLoc :locArray];      [exifMetaData addTagValue:gpsLoc forKey:[NSNumber numberWithInt:EXIF_GPSLatitude] ];      [gpsLoc release];      [locArray release];      locArray = [self createLocArray:imageLocation.coordinate.longitude];      gpsLoc = [[EXFGPSLoc alloc] init];      [self populateGPS: gpsLoc :locArray];      [exifMetaData addTagValue:gpsLoc forKey:[NSNumber numberWithInt:EXIF_GPSLongitude] ];      [gpsLoc release];      [locArray release];     NSString* ref;     if (imageLocation.coordinate.latitude <0.0)         ref = @"S";      else         ref =@"N";      [exifMetaData addTagValue: ref forKey:[NSNumber numberWithInt:EXIF_GPSLatitudeRef] ];      if (imageLocation.coordinate.longitude <0.0)         ref = @"W";      else         ref =@"E";      [exifMetaData addTagValue: ref forKey:[NSNumber numberWithInt:EXIF_GPSLongitudeRef] ];      NSMutableData* taggedJpegData = [[NSMutableData alloc] init];     [jpegScanner populateImageData:taggedJpegData];     [jpegScanner release];     return [taggedJpegData autorelease]; }  

// Helper methods for location conversion -(NSMutableArray*) createLocArray:(double) val{ val = fabs(val); NSMutableArray* array = [[NSMutableArray alloc] init]; double deg = (int)val; [array addObject:[NSNumber numberWithDouble:deg]]; val = val - deg; val = val*60; double minutes = (int) val; [array addObject:[NSNumber numberWithDouble:minutes]]; val = val - minutes; val = val*60; double seconds = val; [array addObject:[NSNumber numberWithDouble:seconds]]; return array; } -(void) populateGPS:(EXFGPSLoc* ) gpsLoc :(NSArray*) locArray{ long numDenumArray[2]; long* arrPtr = numDenumArray; [EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:0]]; EXFraction* fract = [[EXFraction alloc] initWith:numDenumArray[0]:numDenumArray[1]]; gpsLoc.degrees = fract; [fract release]; [EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:1]]; fract = [[EXFraction alloc] initWith:numDenumArray[0] :numDenumArray[1]]; gpsLoc.minutes = fract; [fract release]; [EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:2]]; fract = [[EXFraction alloc] initWith:numDenumArray[0] :numDenumArray[1]]; gpsLoc.seconds = fract; [fract release]; }

like image 136
yonel Avatar answered Oct 08 '22 13:10

yonel