Get Exif data from UIImage - UIImagePickerController

IphoneObjective CIpadExif

Iphone Problem Overview


How can we get Exif information from UIImage selected from UIImagePickerController?

I had done much R&D for this and got many replies but still failed to implement this.

I had gone through this this and this link

Please help me to solve this problem.

Thanks in advance..

Iphone Solutions


Solution 1 - Iphone

Interesting question! I came up with the following solution working for images picked from your photo library (note my code is using ARC):

Import AssetsLibrary.framework and ImageIO.framework.

Then include the needed classes inside your .h-file:

#import <AssetsLibrary/ALAsset.h>
#import <AssetsLibrary/ALAssetRepresentation.h>
#import <ImageIO/CGImageSource.h>
#import <ImageIO/CGImageProperties.h>

And put this inside your imagePickerController:didFinishPickingMediaWithInfo: delegate method:

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL]
    resultBlock:^(ALAsset *asset) {
        
        ALAssetRepresentation *image_representation = [asset defaultRepresentation];
        
        // create a buffer to hold image data 
        uint8_t *buffer = (Byte*)malloc(image_representation.size);
        NSUInteger length = [image_representation getBytes:buffer fromOffset: 0.0  length:image_representation.size error:nil];
        
        if (length != 0)  {
            
            // buffer -> NSData object; free buffer afterwards
            NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:image_representation.size freeWhenDone:YES];
            
            // identify image type (jpeg, png, RAW file, ...) using UTI hint
            NSDictionary* sourceOptionsDict = [NSDictionary dictionaryWithObjectsAndKeys:(id)[image_representation UTI] ,kCGImageSourceTypeIdentifierHint,nil];
            
            // create CGImageSource with NSData
            CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef) adata,  (__bridge CFDictionaryRef) sourceOptionsDict);
            
            // get imagePropertiesDictionary
            CFDictionaryRef imagePropertiesDictionary;
            imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(sourceRef,0, NULL);
            
            // get exif data
            CFDictionaryRef exif = (CFDictionaryRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyExifDictionary);
            NSDictionary *exif_dict = (__bridge NSDictionary*)exif;
            NSLog(@"exif_dict: %@",exif_dict);
            
            // save image WITH meta data
            NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
            NSURL *fileURL = nil;
            CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, imagePropertiesDictionary);
                     
            if (![[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"] isEqualToString:@"public.tiff"])
                     {
                         fileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.%@",
                                                           documentsDirectory,
                                                           @"myimage",
                                                           [[[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"] componentsSeparatedByString:@"."] objectAtIndex:1]
                                                           ]];
                         
                         CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((__bridge CFURLRef)fileURL,
                                                                                     (__bridge CFStringRef)[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"],
                                                                                     1,
                                                                                     NULL
                                                                                    );
              CGImageDestinationAddImage(dr, imageRef, imagePropertiesDictionary);
              CGImageDestinationFinalize(dr);
              CFRelease(dr);
            }
            else
            {
              NSLog(@"no valid kCGImageSourceTypeIdentifierHint found …");
            }

            // clean up
            CFRelease(imageRef);
            CFRelease(imagePropertiesDictionary);
            CFRelease(sourceRef);
        }
        else {
            NSLog(@"image_representation buffer length == 0");
        }
    }
    failureBlock:^(NSError *error) {
        NSLog(@"couldn't get asset: %@", error);
    }
];

One thing I noticed is, that iOS will ask the user to allow location services – if he denies, you won't be abled to get the image data …

EDIT

Added code to save the image including its meta data. It's a quick approach, so maybe there is a better way, but it works!

Solution 2 - Iphone

These answers all seem extremely complex. If the image has been saved to the Camera Roll, and you have the ALAsset (either from UIImagePicker or ALAssetLibrary) you can get the metadata like so:

asset.defaultRepresentation.metadata;

If you want to save that image from camera roll to another location (say in Sandbox/Documents) simply do:

CGImageDestinationRef imageDestinationRef   = CGImageDestinationCreateWithURL((__bridge CFURLRef)urlToSaveTo, kUTTypeJPEG, 1, NULL);
CFDictionaryRef imagePropertiesRef          = (__bridge CFDictionaryRef)asset.defaultRepresentation.metadata;

CGImageDestinationAddImage(imageDestinationRef, asset.defaultRepresentation.fullResolutionImage, imagePropertiesRef);
if (!CGImageDestinationFinalize(imageDestinationRef)) NSLog(@"Failed to copy photo on save to %@", urlToSaveTo);

CFRelease(imageDestinationRef);

Solution 3 - Iphone

I had found solution and got answer from here

From here We can get GPS info as well..

Amazing and thanks all for helping me to solve this problem.

UPDATE

This is another function that I had created myself, also return Exif data as well as GPS data and in this function we doesn't need any third party library.. but you have to turn on location services for this. and use current latitude and longitude for that. so have to use CoreLocation.framework

//FOR CAMERA IMAGE

-(NSMutableData *)getImageWithMetaData:(UIImage *)pImage
{
	NSData* pngData =  UIImagePNGRepresentation(pImage);
	
	CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);
	NSDictionary *metadata = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
	
	NSMutableDictionary *metadataAsMutable = [[metadata mutableCopy]autorelease];
	[metadata release];
	
	//For GPS Dictionary
	NSMutableDictionary *GPSDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]autorelease];
	if(!GPSDictionary) 
		GPSDictionary = [NSMutableDictionary dictionary];

	[GPSDictionary setValue:[NSNumber numberWithDouble:currentLatitude] forKey:(NSString*)kCGImagePropertyGPSLatitude];
	[GPSDictionary setValue:[NSNumber numberWithDouble:currentLongitude] forKey:(NSString*)kCGImagePropertyGPSLongitude];

	NSString* ref;
    if (currentLatitude <0.0)
        ref = @"S"; 
    else
        ref =@"N"; 	
	[GPSDictionary setValue:ref forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
	
    if (currentLongitude <0.0)
        ref = @"W"; 
    else
        ref =@"E"; 	
	[GPSDictionary setValue:ref forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
	
	[GPSDictionary setValue:[NSNumber numberWithFloat:location.altitude] forKey:(NSString*)kCGImagePropertyGPSAltitude];
	
	//For EXIF Dictionary
	NSMutableDictionary *EXIFDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]autorelease];
	if(!EXIFDictionary) 
		EXIFDictionary = [NSMutableDictionary dictionary];
	
	[EXIFDictionary setObject:[NSDate date] forKey:(NSString*)kCGImagePropertyExifDateTimeOriginal];
	[EXIFDictionary setObject:[NSDate date] forKey:(NSString*)kCGImagePropertyExifDateTimeDigitized];
	
	//add our modified EXIF data back into the image’s metadata
	[metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];
	[metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
	
	CFStringRef UTI = CGImageSourceGetType(source);
	
	NSMutableData *dest_data = [NSMutableData data];
	CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data, UTI, 1, NULL);
	
	if(!destination)
		dest_data = [[pngData mutableCopy] autorelease];
	else 
	{
		CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);
	 	BOOL success = CGImageDestinationFinalize(destination);
		if(!success)
			dest_data = [[pngData mutableCopy] autorelease];
	}
	
	if(destination)
		CFRelease(destination);
	
	CFRelease(source);
	
	return dest_data;
}

//FOR PHOTO LIBRARY IMAGE

-(NSMutableData *)getImagedataPhotoLibrary:(NSDictionary *)pImgDictionary andImage:(UIImage *)pImage
{
	NSData* data = UIImagePNGRepresentation(pImage);
	
	CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL);
	NSMutableDictionary *metadataAsMutable = [[pImgDictionary mutableCopy]autorelease];
	
	CFStringRef UTI = CGImageSourceGetType(source);
	
	NSMutableData *dest_data = [NSMutableData data];
	
	//For Mutabledata
	CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data, UTI, 1, NULL);
	
	if(!destination)
		dest_data = [[data mutableCopy] autorelease];
	else 
	{
		CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);
	 	BOOL success = CGImageDestinationFinalize(destination);
		if(!success)
			dest_data = [[data mutableCopy] autorelease];
	}
	if(destination)
		CFRelease(destination);
	
	CFRelease(source);

	return dest_data;
}

and We will retrieve that data like this

//FOR CAMERA IMAGE
NSData *originalImgData = [self getImageWithMetaData:imgOriginal];

//FOR PHOTO LIBRARY IMAGE
[self getImagedataPhotoLibrary:[[myasset defaultRepresentation] metadata] andImage:imgOriginal];

For all of this you should have to Import AssetsLibrary.framework and ImageIO.framework.

Solution 4 - Iphone

I have used this method for getting the exifdata dictionary from image , I hope this will also work for you

-(void)getExifDataFromImage:(UIImage *)currentImage
{

    NSData* pngData =  UIImageJPEGRepresentation(currentImage, 1.0);
    
    CGImageSourceRef mySourceRef = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);
    
    //CGImageSourceRef mySourceRef = CGImageSourceCreateWithURL((__bridge CFURLRef)myURL, NULL);
    if (mySourceRef != NULL)
    {
        NSDictionary *myMetadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(mySourceRef,0,NULL);
        NSDictionary *exifDic = [myMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary];
        NSDictionary *tiffDic = [myMetadata objectForKey:(NSString *)kCGImagePropertyTIFFDictionary];
        NSLog(@"exifDic properties: %@", myMetadata); //all data
        float rawShutterSpeed = [[exifDic objectForKey:(NSString *)kCGImagePropertyExifExposureTime] floatValue];
        int decShutterSpeed = (1 / rawShutterSpeed);
        NSLog(@"Camera %@",[tiffDic objectForKey:(NSString *)kCGImagePropertyTIFFModel]);
        NSLog(@"Focal Length %@mm",[exifDic objectForKey:(NSString *)kCGImagePropertyExifFocalLength]);
        NSLog(@"Shutter Speed %@", [NSString stringWithFormat:@"1/%d", decShutterSpeed]);
        NSLog(@"Aperture f/%@",[exifDic objectForKey:(NSString *)kCGImagePropertyExifFNumber]);
        
        
        NSNumber *ExifISOSpeed  = [[exifDic objectForKey:(NSString*)kCGImagePropertyExifISOSpeedRatings] objectAtIndex:0];
        NSLog(@"ISO %ld",[ExifISOSpeed integerValue]);
        NSLog(@"Taken %@",[exifDic objectForKey:(NSString*)kCGImagePropertyExifDateTimeDigitized]);
        
        
    }
    
}

Solution 5 - Iphone

You need ALAssetsLibrary to actually retrieve the EXIF info from an image. The EXIF is added to an image only when it is saved to the Photo Library. Even if you use ALAssetLibrary to get an image asset from the library, it will lose all EXIF info if you set it to a UIImage.

Solution 6 - Iphone

I have tried to insert GPS coordinates into image metadata picked by iPad Camera as it was suggested by Mehul. It Works, Thank you for your post.

P.S. Who intends to use that code, just substitude the two geolocations at the top of the function -(NSMutableData *)getImageWithMetaData:(UIImage *)pImage {

double currentLatitude = [locationManager location].coordinate.latitude;
double currentLongitude = [locationManager location].coordinate.longitude;

...

By supposing that you have already initializied somewhere locationManager in your code, like this:

    locationManager = [[CLLocationManager alloc] init];
    [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [locationManager setDelegate:self]; // Not necessary in this case
    [locationManager startUpdatingLocation]; // Not neccessary in this case

and by importing CoreLocation/CoreLocation.h and ImageIO/ImageIO.h headers with associated frameworks.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMehul MistriView Question on Stackoverflow
Solution 1 - IphonedomView Answer on Stackoverflow
Solution 2 - IphoneAndrew TheisView Answer on Stackoverflow
Solution 3 - IphoneMehul MistriView Answer on Stackoverflow
Solution 4 - IphoneGourav DixitView Answer on Stackoverflow
Solution 5 - IphoneATOzTOAView Answer on Stackoverflow
Solution 6 - IphoneklusinyanView Answer on Stackoverflow