Добавляем координаты в EXIF-тег в собственном приложении для iOS

Всем известно, что приложение «Фото», установленное на всех iOS-девайсах, позволяет просматривать не только фотографии пользователей, но и отметки на карте, где были сделаны эти фотографии. Если вы делаете фотографию с помощью стандартной камеры, то информация о вашем текущем местоположении автоматически заносится в EXIF-тег, находящийся внутри изображения и вы увидите новую отметку на карте. Это изображение можно отправить друзьям или разместить в интернете. А с помощью записанных координат все смогут увидеть, где был сделан столь замечательный кадр. Все красиво и удобно.

Этот небольшой топик-подсказка поможет вам, когда необходимо сделать собственное приложение с камерой, которое будет повторять данный функционал и (скорее всего) выполнять какие-то действия с полученным изображением (в моем случае свежую фотографии необходимо было загружать на веб-сайт, где пользователи могут просматривать фотографии и места на карте).

Выделим три маленьких этапа, реализовав которые, можно получить желаемый результат:
  1. Получение изображения с камеры девайса
  2. Определение координат пользователя
  3. Запись коодринат в изображение

Надеюсь, что вам не составит труда справиться с первыми двумя пунктами самостоятельно и мы остановимся более подробно на самом интересном — как записать координаты.

Получаем изображение (у меня из UIImagePickerController)
UIImage *pickedImage = [[info objectForKey:UIImagePickerControllerOriginalImage] retain];

Далее у нас уже должен быть объект location (класса CLLocation)
CLLocationDegrees exifLatitude  = location.coordinate.latitude;
CLLocationDegrees exifLongitude = location.coordinate.longitude;

Сделаем конвертацию наших координат в строки, которые будет записаны в EXIF-тег
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";
}

Создаем словарик с нашими данными и названием ключей:
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];

Создаем еще один словарик и включаем в него созданный строчкой выше locDict. Здесь используется ключ kCGImagePropertyGPSDictionary
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init];
[metadata setObject:locDict forKey:(NSString*)kCGImagePropertyGPSDictionary];
[locDict release];

Создаем объект класса NSData и наполняем его байтами из нашего изображения
NSData *image = UIImageJPEGRepresentation(pickedImage, 90);

Следующие волшебные строчки кода создают объект класса ALAssetsLibrary, который предоставляет доступ к вашим фото- и видеоальбомам (и не только, более подробно можно ознакомиться в документации). Далее сохраняем фотографию в фотоальбом на девайсе с использованием созданного нами словаря metadata. Метод writeImageDataToSavedPhotosAlbum поможет нам в этом и заодно запишет необходимые нам EXIF-теги.
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];

На этом можно было бы остановиться, если фотография нужна вам только в фотоальбоме. Но мы пойдем дальше. Создаем объект dest_data, который нам понадобится для хранения фотографии
NSMutableData *dest_data = [NSMutableData data];

Создаем референс для фотографии
CGImageSourceRef  source = CGImageSourceCreateWithData((CFDataRef)image, NULL); 
if (!source)
{
    NSLog(@"***Could not create image source ***");
}

Указываем тип
CFStringRef UTI = CGImageSourceGetType(source);

Указываем куда нужно записать полученные данные (в dest_data)
CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data,UTI,1,NULL);
if(!destination) {
    NSLog(@"***Could not create image destination ***");
}

Записываем данные с использованием словаря metadata (да, все тот же).
CGImageDestinationAddImageFromSource(destination,source,0, (CFDictionaryRef) metadata);
[metadata release];

Делаем проверку
BOOL success = NO;
success = CGImageDestinationFinalize(destination);
if(!success) {
    NSLog(@"***Could not create data from image destination ***");
}

Не забываем почистить память
CFRelease(destination);
CFRelease(source);        

Теперь у нас есть объект dest_data, который хранит изображение с нужными тегами. Его можно использовать на ваше усмотрение.

Добавьте следующие строчки в ваш заголовочный файл
#import <CoreFoundation/CoreFoundation.h>
#import <AssetsLibrary/ALAssetsLibrary.h>
#import <ImageIO/ImageIO.h>

И не забудьте подключить нужные фреймворки.

Спасибо stackoverflow за ответы на мои бесконечные вопросы и всем кто дочитал до конца.
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 4

    0
    Отлично! Спасибо.
      +1
      Спасибо за интерес к статье.
      +1
      Спасибо, информативно и просто
        +1
        Спасибо за комментарий

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое