2

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?

codacopia
  • 2,369
  • 9
  • 39
  • 58

1 Answers1

1

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.

Ayan Sengupta
  • 5,238
  • 2
  • 28
  • 40
  • I am going through this now, I'll let you know what I find, thanks. – codacopia Nov 20 '13 at 20:59
  • This line `NSString *dateString = [dateFormatter stringFromDate:localDate];` is throwing errors stating 1) implicit conversion of a non objective c pointer type disallowed by ARC and 2) Semantic Issue of undeclared identifier suggesting that I change the name to `localtime` So I can easily change the name to test, but what about ARC problem? – codacopia Nov 20 '13 at 21:13
  • Sorry, as I told you that the portion of the code has been taken from GusUtils, it might have some undeclared properties/variables. I would try to give it a recap but plz make sure that you understand what we are going to implement and modify whatever you feel is required. Also, you might use GusUtils categories directly(plz follow the link) in your code for better modularization. – Ayan Sengupta Nov 20 '13 at 21:25
  • @Presto Made an edit right there. changed `localDate` to `location.timestamp`. Please give it a try now. – Ayan Sengupta Nov 20 '13 at 21:29
  • I am still working with this. I have added GusUtils `.m` and `.h` files, but these seem to be built with ARC turned off so I am trying to adjust that to match. The `location.timestamp` adjustmement worked well so far, thanks. I'll let you know if I have any more questions. – codacopia Nov 20 '13 at 23:39
  • I have added `#import ` but `CLLocation *location;` is still coming up `null`. Do you have any suggestions on how I can make this connection to gather location info? Sorry for the difficulty, I am new to all this. – codacopia Nov 21 '13 at 00:57
  • thank you for the edit, I can tell it is getting closer. Now, when I run the app for the first time I get the prompt "AppName would like to use your current location." Which tells me that Location SErvices are active. I then took a photo through the `UIImagePickerControllerSourceTypeCamera` but when I review the info on that photo the GPS data is still `NULL`. I'll keep you posted on any progress, thanks again for staying on this question with me. – codacopia Nov 21 '13 at 13:29
  • @Presto I have tried to describe the basic methods, required to compensate your requirements. Unfortunately, I cant review your code to find out whats going wrong in there :(. But I believe you will be able to make it your own after you know the basics. And you are welcome dude. – Ayan Sengupta Nov 21 '13 at 13:34
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/41634/discussion-between-presto-and-ayan-sengupta) – codacopia Nov 21 '13 at 13:42
  • after a great deal of work in the chat room we found the resolution. THank you soo much for all the assistance :) – codacopia Nov 21 '13 at 17:23