Получить данные Exif из UIImage - UIImagePickerController

Как мы можем получить информацию Exif из UIImage, выбранного из UIImagePickerController?

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

Я прошел через это, это и эта ссылка

Пожалуйста, помогите мне решить эту проблему.

Заранее спасибо..

6 ответов

Решение

Я нашел решение и получил ответ отсюда

Отсюда мы также можем получить информацию GPS.

Удивительно и спасибо всем за помощь в решении этой проблемы.

ОБНОВИТЬ

Это еще одна функция, которую я создал сам, которая также возвращает данные Exif, а также данные GPS, и в этой функции нам не нужна никакая сторонняя библиотека... но для этого вам нужно включить службы определения местоположения. и использовать текущую широту и долготу для этого. так что надо использовать CoreLocation.framework

//FOR CAMERA IMAGE

-(NSMutableData *)getImageWithMetaData:(UIImage *)pImage
{
    NSData* pngData =  UIImagePNGRepresentation(pImage);

    CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);
    NSDictionary *metadata = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);

    NSMutableDictionary *metadataAsMutable = [[metadata mutableCopy]autorelease];
    [metadata release];

    //For GPS Dictionary
    NSMutableDictionary *GPSDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]autorelease];
    if(!GPSDictionary) 
        GPSDictionary = [NSMutableDictionary dictionary];

    [GPSDictionary setValue:[NSNumber numberWithDouble:currentLatitude] forKey:(NSString*)kCGImagePropertyGPSLatitude];
    [GPSDictionary setValue:[NSNumber numberWithDouble:currentLongitude] forKey:(NSString*)kCGImagePropertyGPSLongitude];

    NSString* ref;
    if (currentLatitude <0.0)
        ref = @"S"; 
    else
        ref =@"N";  
    [GPSDictionary setValue:ref forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];

    if (currentLongitude <0.0)
        ref = @"W"; 
    else
        ref =@"E";  
    [GPSDictionary setValue:ref forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];

    [GPSDictionary setValue:[NSNumber numberWithFloat:location.altitude] forKey:(NSString*)kCGImagePropertyGPSAltitude];

    //For EXIF Dictionary
    NSMutableDictionary *EXIFDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]autorelease];
    if(!EXIFDictionary) 
        EXIFDictionary = [NSMutableDictionary dictionary];

    [EXIFDictionary setObject:[NSDate date] forKey:(NSString*)kCGImagePropertyExifDateTimeOriginal];
    [EXIFDictionary setObject:[NSDate date] forKey:(NSString*)kCGImagePropertyExifDateTimeDigitized];

    //add our modified EXIF data back into the image’s metadata
    [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];
    [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];

    CFStringRef UTI = CGImageSourceGetType(source);

    NSMutableData *dest_data = [NSMutableData data];
    CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data, UTI, 1, NULL);

    if(!destination)
        dest_data = [[pngData mutableCopy] autorelease];
    else 
    {
        CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);
        BOOL success = CGImageDestinationFinalize(destination);
        if(!success)
            dest_data = [[pngData mutableCopy] autorelease];
    }

    if(destination)
        CFRelease(destination);

    CFRelease(source);

    return dest_data;
}

//FOR PHOTO LIBRARY IMAGE

-(NSMutableData *)getImagedataPhotoLibrary:(NSDictionary *)pImgDictionary andImage:(UIImage *)pImage
{
    NSData* data = UIImagePNGRepresentation(pImage);

    CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL);
    NSMutableDictionary *metadataAsMutable = [[pImgDictionary mutableCopy]autorelease];

    CFStringRef UTI = CGImageSourceGetType(source);

    NSMutableData *dest_data = [NSMutableData data];

    //For Mutabledata
    CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data, UTI, 1, NULL);

    if(!destination)
        dest_data = [[data mutableCopy] autorelease];
    else 
    {
        CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);
        BOOL success = CGImageDestinationFinalize(destination);
        if(!success)
            dest_data = [[data mutableCopy] autorelease];
    }
    if(destination)
        CFRelease(destination);

    CFRelease(source);

    return dest_data;
}

и мы будем получать эти данные, как это

//FOR CAMERA IMAGE
NSData *originalImgData = [self getImageWithMetaData:imgOriginal];

//FOR PHOTO LIBRARY IMAGE
[self getImagedataPhotoLibrary:[[myasset defaultRepresentation] metadata] andImage:imgOriginal];

Для всего этого вы должны импортировать AssetsLibrary.framework а также ImageIO.framework,

Интересный вопрос! Я предложил следующее решение для изображений, выбранных из вашей библиотеки фотографий (обратите внимание, что мой код использует ARC):

Импортировать AssetsLibrary.framework а также ImageIO.framework,

Затем включите необходимые классы в ваш.h-файл:

#import <AssetsLibrary/ALAsset.h>
#import <AssetsLibrary/ALAssetRepresentation.h>
#import <ImageIO/CGImageSource.h>
#import <ImageIO/CGImageProperties.h>

И положи это в свой imagePickerController:didFinishPickingMediaWithInfo: метод делегата:

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL]
    resultBlock:^(ALAsset *asset) {

        ALAssetRepresentation *image_representation = [asset defaultRepresentation];

        // create a buffer to hold image data 
        uint8_t *buffer = (Byte*)malloc(image_representation.size);
        NSUInteger length = [image_representation getBytes:buffer fromOffset: 0.0  length:image_representation.size error:nil];

        if (length != 0)  {

            // buffer -> NSData object; free buffer afterwards
            NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:image_representation.size freeWhenDone:YES];

            // identify image type (jpeg, png, RAW file, ...) using UTI hint
            NSDictionary* sourceOptionsDict = [NSDictionary dictionaryWithObjectsAndKeys:(id)[image_representation UTI] ,kCGImageSourceTypeIdentifierHint,nil];

            // create CGImageSource with NSData
            CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef) adata,  (__bridge CFDictionaryRef) sourceOptionsDict);

            // get imagePropertiesDictionary
            CFDictionaryRef imagePropertiesDictionary;
            imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(sourceRef,0, NULL);

            // get exif data
            CFDictionaryRef exif = (CFDictionaryRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyExifDictionary);
            NSDictionary *exif_dict = (__bridge NSDictionary*)exif;
            NSLog(@"exif_dict: %@",exif_dict);

            // save image WITH meta data
            NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
            NSURL *fileURL = nil;
            CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, imagePropertiesDictionary);

            if (![[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"] isEqualToString:@"public.tiff"])
                     {
                         fileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.%@",
                                                           documentsDirectory,
                                                           @"myimage",
                                                           [[[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"] componentsSeparatedByString:@"."] objectAtIndex:1]
                                                           ]];

                         CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((__bridge CFURLRef)fileURL,
                                                                                     (__bridge CFStringRef)[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"],
                                                                                     1,
                                                                                     NULL
                                                                                    );
              CGImageDestinationAddImage(dr, imageRef, imagePropertiesDictionary);
              CGImageDestinationFinalize(dr);
              CFRelease(dr);
            }
            else
            {
              NSLog(@"no valid kCGImageSourceTypeIdentifierHint found …");
            }

            // clean up
            CFRelease(imageRef);
            CFRelease(imagePropertiesDictionary);
            CFRelease(sourceRef);
        }
        else {
            NSLog(@"image_representation buffer length == 0");
        }
    }
    failureBlock:^(NSError *error) {
        NSLog(@"couldn't get asset: %@", error);
    }
];

Одна вещь, которую я заметил, заключается в том, что iOS попросит пользователя разрешить услуги определения местоположения - если он откажется, вы не сможете получить данные изображения...

РЕДАКТИРОВАТЬ

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

Эти ответы кажутся чрезвычайно сложными. Если изображение было сохранено в Camera Roll, и у вас есть ALAsset (из UIImagePicker или ALAssetLibrary), вы можете получить метаданные следующим образом:

asset.defaultRepresentation.metadata;

Если вы хотите сохранить это изображение с камеры в другое место (скажем, в Песочнице / Документах), просто выполните:

CGImageDestinationRef imageDestinationRef   = CGImageDestinationCreateWithURL((__bridge CFURLRef)urlToSaveTo, kUTTypeJPEG, 1, NULL);
CFDictionaryRef imagePropertiesRef          = (__bridge CFDictionaryRef)asset.defaultRepresentation.metadata;

CGImageDestinationAddImage(imageDestinationRef, asset.defaultRepresentation.fullResolutionImage, imagePropertiesRef);
if (!CGImageDestinationFinalize(imageDestinationRef)) NSLog(@"Failed to copy photo on save to %@", urlToSaveTo);

CFRelease(imageDestinationRef);

Я использовал этот метод для получения словаря exifdata из изображения, я надеюсь, что это также будет работать для вас

-(void)getExifDataFromImage:(UIImage *)currentImage
{

    NSData* pngData =  UIImageJPEGRepresentation(currentImage, 1.0);

    CGImageSourceRef mySourceRef = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);

    //CGImageSourceRef mySourceRef = CGImageSourceCreateWithURL((__bridge CFURLRef)myURL, NULL);
    if (mySourceRef != NULL)
    {
        NSDictionary *myMetadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(mySourceRef,0,NULL);
        NSDictionary *exifDic = [myMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary];
        NSDictionary *tiffDic = [myMetadata objectForKey:(NSString *)kCGImagePropertyTIFFDictionary];
        NSLog(@"exifDic properties: %@", myMetadata); //all data
        float rawShutterSpeed = [[exifDic objectForKey:(NSString *)kCGImagePropertyExifExposureTime] floatValue];
        int decShutterSpeed = (1 / rawShutterSpeed);
        NSLog(@"Camera %@",[tiffDic objectForKey:(NSString *)kCGImagePropertyTIFFModel]);
        NSLog(@"Focal Length %@mm",[exifDic objectForKey:(NSString *)kCGImagePropertyExifFocalLength]);
        NSLog(@"Shutter Speed %@", [NSString stringWithFormat:@"1/%d", decShutterSpeed]);
        NSLog(@"Aperture f/%@",[exifDic objectForKey:(NSString *)kCGImagePropertyExifFNumber]);


        NSNumber *ExifISOSpeed  = [[exifDic objectForKey:(NSString*)kCGImagePropertyExifISOSpeedRatings] objectAtIndex:0];
        NSLog(@"ISO %ld",[ExifISOSpeed integerValue]);
        NSLog(@"Taken %@",[exifDic objectForKey:(NSString*)kCGImagePropertyExifDateTimeDigitized]);


    }

}

Вам нужен ALAssetsLibrary для фактического получения информации EXIF ​​из изображения. EXIF добавляется к изображению только тогда, когда оно сохраняется в библиотеке фотографий. Даже если вы используете ALAssetLibrary для получения ресурса изображения из библиотеки, он потеряет всю информацию EXIF, если вы установите для него UIImage.

Я попытался вставить GPS-координаты в метаданные изображения, выбранные iPad Camera, как это было предложено Мехулом. Это работает, спасибо за ваш пост.

PS Кто намеревается использовать этот код, просто замените два геолокации в верхней части функции - (NSMutableData *) getImageWithMetaData: (UIImage *) pImage {

double currentLatitude = [locationManager location].coordinate.latitude;
double currentLongitude = [locationManager location].coordinate.longitude;

...

Предположим, что вы уже инициализировали где-то locationManager в своем коде, например так:

    locationManager = [[CLLocationManager alloc] init];
    [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [locationManager setDelegate:self]; // Not necessary in this case
    [locationManager startUpdatingLocation]; // Not neccessary in this case

и путем импорта заголовков CoreLocation/CoreLocation.h и ImageIO/ImageIO.h со связанными инфраструктурами.

Другие вопросы по тегам