📜 ⬆️ ⬇️

Add coordinates to the EXIF ​​tag in your own iOS application

Everyone knows that the “Photos” application installed on all iOS devices allows you to view not only user photos, but also marks on the map where these photos were taken. If you take a photo using a standard camera, then information about your current location is automatically entered into the EXIF ​​tag inside the image and you will see a new mark on the map. This image can be sent to friends or placed on the Internet. And with the help of the recorded coordinates, everyone can see where such a wonderful frame was taken. Everything is beautiful and comfortable.

This small topic tip will help you when you need to make your own application with a camera that will repeat this functionality and (most likely) perform some actions with the resulting image (in my case, you need to upload fresh photos to the website where can view photos and places on the map).

We will single out three small stages, implementing which we can get the desired result:
  1. Obtaining images from the camera device
  2. Determination of user coordinates
  3. Write co-edin to image

I hope that it will not be difficult for you to deal with the first two points on your own and we will dwell in more detail on the most interesting part - how to record the coordinates.

We receive the image (from me from UIImagePickerController)
UIImage *pickedImage = [[info objectForKey:UIImagePickerControllerOriginalImage] retain]; 

Next, we should already have a location object (of class CLLocation)
 CLLocationDegrees exifLatitude = location.coordinate.latitude; CLLocationDegrees exifLongitude = location.coordinate.longitude; 

We will convert our coordinates into strings that will be written to the EXIF ​​tag
 NSString *latRef; NSString *lngRef; if (exifLatitude < 0.0) { exifLatitude = exifLatitude * -1.0f; latRef = @"S"; } else { latRef = @"N"; } if (exifLongitude < 0.0) { exifLongitude = exifLongitude * -1.0f; lngRef = @"W"; } else { lngRef = @"E"; } 

Create a dictionary with our data and the name of the keys:
kCGImagePropertyGPSTimeStamp
kCGImagePropertyGPSLatitude
kCGImagePropertyGPSLongitude
kCGImagePropertyGPSLatitudeRef
kCGImagePropertyGPSLongitudeRef
 NSDictionary* locDict = [[NSDictionary alloc] initWithObjectsAndKeys: location.timestamp, (NSString*)kCGImagePropertyGPSTimeStamp, latRef, (NSString*)kCGImagePropertyGPSLatitudeRef, [NSNumber numberWithFloat:exifLatitude], (NSString*)kCGImagePropertyGPSLatitude, lngRef, (NSString*)kCGImagePropertyGPSLongitudeRef, [NSNumber numberWithFloat:exifLongitude], (NSString*)kCGImagePropertyGPSLongitude, nil]; 

Create another dictionary and include the locDict created above with the line above. The key used here is kCGImagePropertyGPSDictionary
 NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init]; [metadata setObject:locDict forKey:(NSString*)kCGImagePropertyGPSDictionary]; [locDict release]; 

Create an object of class NSData and fill it with bytes from our image.
 NSData *image = UIImageJPEGRepresentation(pickedImage, 90); 

The following magic lines of code create an object of class ALAssetsLibrary, which provides access to your photo and video albums (and not only, you can find more information in the documentation). Next, save the photo to the photo album on the device using the metadata dictionary we created. The writeImageDataToSavedPhotosAlbum method will help us with this and at the same time write down the EXIF ​​tags we need.
 ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; [library writeImageDataToSavedPhotosAlbum:image metadata:metadata completionBlock:^(NSURL *assetURL, NSError *error){ if (error) { // TODO: error handling } else { // TODO: success handling } }]; [library release]; 

You could stop at this if you only need the photo in the photo album. But we will go further. Create a dest_data object that we need to store the photo.
 NSMutableData *dest_data = [NSMutableData data]; 

Create a reference for a photo
 CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)image, NULL); if (!source) { NSLog(@"***Could not create image source ***"); } 

Specify the type
 CFStringRef UTI = CGImageSourceGetType(source); 

Specify where to write the received data (in dest_data)
 CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data,UTI,1,NULL); if(!destination) { NSLog(@"***Could not create image destination ***"); } 

We write data using the metadata dictionary (yes, it's the same).
 CGImageDestinationAddImageFromSource(destination,source,0, (CFDictionaryRef) metadata); [metadata release]; 

We make a check
 BOOL success = NO; success = CGImageDestinationFinalize(destination); if(!success) { NSLog(@"***Could not create data from image destination ***"); } 

Do not forget to clean the memory
 CFRelease(destination); CFRelease(source); 

Now we have the object dest_data, which stores the image with the necessary tags. It can be used at your discretion.
')
Add the following lines to your header file.
 #import <CoreFoundation/CoreFoundation.h> #import <AssetsLibrary/ALAssetsLibrary.h> #import <ImageIO/ImageIO.h> 

And do not forget to connect the necessary frameworks.

Thanks to stackoverflow for the answers to my endless questions and to all who read to the end.

Source: https://habr.com/ru/post/122889/


All Articles