Objective-C/ALAssetslibrary - Получить широту GPS из информации exif изображения

Я нашел на одном изображении некоторую информацию exif о GPS, используя библиотеку ALAssetslibrary. Я могу правильно показать всю информацию о выходе, но когда я пытаюсь взять только Широту, я всегда получаю ноль. Это информация exif о GPS:

"{GPS}" =     {
    Altitude = 0;
    AltitudeRef = 1;
    DateStamp = "0111:06:09";
    Latitude = "45.84633333333333";
    LatitudeRef = N;
    Longitude = "12.58";
    LongitudeRef = E;
    TimeStamp = "10:39:04.00";
};

И это код, который я использую для получения информации:

__block NSConditionLock * assetsReadLock = [[NSConditionLock alloc] initWithCondition:WDASSETURL_PENDINGREADS];
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
__block ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
__block NSString *description = [[NSString alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
    if (group) {
        [group setAssetsFilter:[ALAssetsFilter allPhotos]];
        [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
            if (asset){
                NSDictionary *data = [[asset defaultRepresentation] metadata];
                NSLog(@"DATA: %@", data);

                NSNumber *width = [[[asset defaultRepresentation] metadata] objectForKey:@"PixelWidth"];
                NSString *widthString = [NSString stringWithFormat:@"%@", width];
                [widthList addObject:widthString];

                NSNumber *height = [[[asset defaultRepresentation] metadata] objectForKey:@"PixelHeight"];
                NSString *heightString = [NSString stringWithFormat:@"%@", height];
                [heightList addObject:heightString];

                NSString *latitude = [[[asset defaultRepresentation] metadata] objectForKey:@"Latitude"];
                NSLog(@"latitude %@", latitude);
                NSString *latitudeString = [NSString stringWithFormat:@"%@", latitude];
                if(latitude != NULL){
                    [latitudeList addObject:latitude];
                } else {
                    NSString *noLatitude = [[NSString alloc] init];
                    noLatitude = @"No latitude available";
                    [latitudeList addObject:noLatitude];
                }
            }
        }];
    }

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

Спасибо за помощь!


person Hieicker    schedule 30.08.2013    source источник


Ответы (1)


Есть подвох. Представление по умолчанию, возвращенное из библиотеки ресурсов, лишило изображения таких вещей, как данные EXIF, поэтому вы не можете его найти.

Я обнаружил, что если я вручную извлеку байты, формирующие изображение, я смогу реконструировать изображение, а затем получить из него данные EXIF.

Вот функция, которая получит байты и вернет их как объект NSData:

@implementation PhotoLibrary

...

#define MAX_IMAGE_SIZE_LIKELY (700 * 1024)

static uint8_t assetBytes[MAX_IMAGE_SIZE_LIKELY];

+ (NSData*) getDataFromAsset:(ALAsset*)asset {
ALAssetRepresentation* rep = [asset representationForUTI:(NSString*)kUTTypeJPEG];

    if (rep != nil) {
      [rep getBytes:assetBytes fromOffset:0 length:[rep size] error:NULL];
      return [NSData dataWithBytes:assetBytes length:[rep size]];
    } else {
      // Return nil, indicating that the image was no good.
      //
      return nil;
    }
}

...

@end

Обратите внимание, что в моем случае я ограничил размер изображения до 700 КБ (у меня был другой контрольный код, который не имел отношения к вашему вопросу).

Теперь некоторый код (в том же служебном классе), который вызывает эту функцию, есть у меня в uAlertMe, которая сканирует библиотеку ресурсов на наличие изображений, соответствующих различным критериям:

// Return an array of matching images.
//
+ (void) getImagesForDate:(NSDate *)forDate
         matchDateAndTime:(BOOL)matchDateAndTime
      andMatchUserComment:(NSString*)userComment
      withCompletionBlock:(PhotoLibraryRetrievalCompletetionBlock)completionBlock {
    NSMutableArray* result = [[NSMutableArray alloc] init];

    if ([PhotoLibrary isAssetsLibraryAvailable]) {
        ALAssetsGroupEnumerationResultsBlock assetEnumerator =
        ^(ALAsset *asset, NSUInteger index, BOOL *stop) {
            if(asset != NULL) {
                NSDictionary *dict = [asset valueForProperty:ALAssetPropertyURLs];

                if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto] == YES) {

                    // We've been asked to match the date and time, so that means
                    // that we need to get the image data itself so that we can
                    // get the EXIF metadata from within it.
                    //
                    NSData* repData = [PhotoLibrary getDataFromAsset:asset];

                    if (repData != nil) {
                        NSString* comment = [EXIFUtility userCommentForPhoto:repData];

                        if ((userComment != nil) && [comment isEqualToString:userComment]) {
                            // OK so the user comment matches.  Does the date match?
                            NSDate* date = [EXIFUtility dateDigitizedForPhoto:repData];

                            if (matchDateAndTime) {
                                // We want an exact match.
                                if ([date isEqualToDate:forDate]) {
                                    [result addObject:[UIImage imageWithData:repData]];
                                }
                            } else {
                                // We simply want a match on date, regardless of the time of day.
                                if ([date isSameDay:forDate]) {
                                    [result addObject:[UIImage imageWithData:repData]];
                                }
                            }
                        }
                    }
                }
            }
        };

        ALAssetsLibraryGroupsEnumerationResultsBlock assetGroupEnumerator =
        ^(ALAssetsGroup *group, BOOL *stop) {
            @try {
                if(group != nil) {
                    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                        [group enumerateAssetsUsingBlock:assetEnumerator];
                        completionBlock(result);
                        [result removeAllObjects];
                        [result release];
                    });
                }
            }
            @catch (NSException *exception) {
                DDLogError(@"Exception whilst enumerating group: %@", exception);
                *stop = true;
            }
        };

        ALAssetsLibrary *library = [PhotoLibrary defaultAssetsLibrary];

        [library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
                               usingBlock:assetGroupEnumerator
                             failureBlock: ^(NSError *error) {
                                 DDLogError(@"getImagesForDate:forDate matchDateAndTime:  failed with error: %@", error);
                                 completionBlock(nil);
                                 [result removeAllObjects];
                                 [result release];
                             }];
    } else {
        completionBlock(nil);
        [result removeAllObjects];
        [result release];
    }
}

Версию класса EXIFUtility для Mac OS X можно найти по адресу:

EXIFUtility.h EXIFUtility.m

Они очень похожи на то, что есть у меня в uAlertMe, и должны предоставить вам достаточно информации.

person PKCLsoft    schedule 31.08.2013