Using UIImagePickerController I am attempting to gather GPS info from the metadata of the image. Here is my code sample:
NSDictionary *imageMetadata = [info objectForKey: UIImagePickerControllerMediaMetadata];
NSLog(@"Working META: %@",imageMetadata);
CGDataProviderRef dataProvider = CGImageGetDataProvider(originalImage.CGImage);
CFDataRef data = CGDataProviderCopyData(dataProvider);
CGImageSourceRef imageSource = CGImageSourceCreateWithData(data, nil);
NSDictionary *metaDict = (__bridge NSDictionary *)(CGImageSourceCopyProperties(imageSource, nil));
NSLog(@"Not WOrking META: %@",metaDict);
In the output from NSLog I can see that Working Meta has all associated content. Unfortunately the Not Working Meta is outputting null. From what I can tell I need to enhance the options on the image source and CFDictionary rather than using nil. Am I on the right path? If so, what change should I make to pull the GPS data through?
Try obtaining your mutable copy of the source EXIF dictionary like this:
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *jpeg = UIImageJPEGRepresentation(image,image.scale);
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)jpeg, NULL);
NSDictionary *metadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source,0,NULL);
NSMutableDictionary *mutableMetadata = [metadata mutableCopy];
Now set GPS data to that EXIF dictionary (code courtesy GusUtils):
[mutableMetadata setLocation:self.currentLocation]
And finally you need to populate this data to some destination
CFStringRef UTI = CGImageSourceGetType(source);
NSMutableData *data = [NSMutableData data];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef) data, UTI, 1, NULL);
CGImageDestinationAddImageFromSource(destination,source, 0, (__bridge CFDictionaryRef) mutableMetadata);
BOOL success = CGImageDestinationFinalize(destination);
At this point the variable data
should contain all information(image+GPS metadata+other metadata) and you can use this data
to store wherever you like.
EDIT:
To add core location functionality in your class declare CLLocationManagerDelegate protocol in
the header. Instantiate a location manager in your viewDidLoad
:
self.locManager = [CLLocationManager new];
self.locManager.delegate = self;
self.locManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
self.locManager.distanceFilter = 5.0f; //location would be updated if moved by 5 miter
[self.locManager startUpdatingLocation];
And implement following methods to gather location info:
-(void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray*)locations {
if (!locations || [locations count] == 0) {
return;
}
CLLocation* loc = locations[[locations count] - 1];
if (loc.horizontalAccuracy < 0) {
return;
}
self.currentLocation = loc;
}
-(void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation {
if (newLocation.horizontalAccuracy < 0) {
return;
}
self.currentLocation = newLocation;
}
-(void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error {
NSLog(@"core location error: %@",[error localizedDescription]);
if ([error code] != kCLErrorLocationUnknown) {
NSLog(@"location service will terminate now");
self.locManager.delegate = nil;
[self.locManager stopUpdatingLocation];
self.currentLocation = nil;
}
}
Also make sure to stop the service before leaving the VC
self.locManager.delegate = nil;
[self.locManager stopUpdatingLocation];
Then you can use self.currentLocation
for your `location variable.
EDIT2
Ok its seems that you are already using "NSMutableDictionary+ImageMetadata.h" category from GusUtils. So I have made some modifications to my answer. Please give it a try.