zoukankan      html  css  js  c++  java
  • 获取图片的metaData

    获取图片的metaData

    获取简易的metaData较为容易,以下是测试图:

    以下是本人提供的源码:

    UIImage+MetaData.h

    //
    //  UIImage+MetaData.h
    //  PictureInfo
    //
    //  Created by YouXianMing on 14-8-27.
    //  Copyright (c) 2014年 YouXianMing. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface UIImage (MetaData)
    
    - (NSDictionary *)JPEGmetaData;
    - (NSDictionary *)PNGmetaData;
    
    @end

    UIImage+MetaData.h

    //
    //  UIImage+MetaData.m
    //  PictureInfo
    //
    //  Created by YouXianMing on 14-8-27.
    //  Copyright (c) 2014年 YouXianMing. All rights reserved.
    //
    
    #import "UIImage+MetaData.h"
    #import <AssetsLibrary/AssetsLibrary.h>
    #import <ImageIO/ImageIO.h>
    
    @implementation UIImage (MetaData)
    
    - (NSDictionary *)JPEGmetaData
    {
        if (self == nil)
        {
            return nil;
        }
        
        // 转换成jpegData,信息要多一些
        NSData *jpegData              = UIImageJPEGRepresentation(self, 1.0);
        CGImageSourceRef source       = CGImageSourceCreateWithData((__bridge CFDataRef)jpegData, NULL);
        CFDictionaryRef imageMetaData = CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
        CFRelease(source);
        
        NSDictionary *metaDataInfo    = CFBridgingRelease(imageMetaData);
        return metaDataInfo;
    }
    
    - (NSDictionary *)PNGmetaData
    {
        if (self == nil)
        {
            return nil;
        }
        
        NSData *pngData               = UIImagePNGRepresentation(self);
        CGImageSourceRef source       = CGImageSourceCreateWithData((__bridge CFDataRef)pngData , NULL);
        CFDictionaryRef imageMetaData = CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
        CFRelease(source);
        
        NSDictionary *metaDataInfo    = CFBridgingRelease(imageMetaData);
        return metaDataInfo;
    }
    
    @end

    使用情况:

    //
    //  AppDelegate.m
    //  GetPictureInfo
    //
    //  Copyright (c) 2014年 Y.X. All rights reserved.
    //
    
    #import "AppDelegate.h"
    #import "UIImage+MetaData.h"
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        
        NSLog(@"%@", [[UIImage imageNamed:@"IMG_0151.JPG"] JPEGmetaData]);
        
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
        return YES;
    }
    
    @end

    以下是打印信息:

    {
        ColorModel = RGB;
        Depth = 8;
        Orientation = 1;
        PixelHeight = 1936;
        PixelWidth = 2592;
        "{Exif}" =     {
            ColorSpace = 1;
            PixelXDimension = 2592;
            PixelYDimension = 1936;
        };
        "{JFIF}" =     {
            DensityUnit = 0;
            JFIFVersion =         (
                1,
                1
            );
            XDensity = 1;
            YDensity = 1;
        };
        "{TIFF}" =     {
            Orientation = 1;
        };
    }
    几个需要注意的地方:

    1. 需要引入两个库

    2. 一些需要注意的细节

    你以为结束了么?没有呢,你还没取到图片的经纬度信息,对吧,一下给你提供资料自己去尝试:)

    http://stackoverflow.com/questions/9766394/get-exif-data-from-uiimage-uiimagepickercontroller

    How can we get Exif information from UIImage selected from UIImagePickerController?

    I had done much R&D for this and got many replies but still failed to implement this.

    I had gone through this this and this link

    Please help me to solve this problem.

    Thanks in advance..

    share|improve this question
     

    5 Answers

    Interesting question! I came up with the following solution working for images picked from your photo library (note my code is using ARC):

    Import AssetsLibrary.framework and ImageIO.framework.

    Then include the needed classes inside your .h-file:

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

    And put this inside your imagePickerController:didFinishPickingMediaWithInfo: delegate method:

    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);
        }
    ];

    One thing I noticed is, that iOS will ask the user to allow location services – if he denies, you won't be abled to get the image data …

    EDIT

    Added code to save the image including its meta data. It's a quick approach, so maybe there is a better way, but it works!

    share|improve this answer
     
        
    Can you plz tell me how to save image after getting exif data? –  iOS developer Mar 19 '12 at 9:40
        
    +1 Cool answer.. –  iOS developer Mar 19 '12 at 9:44
        
    @Marvin Check out my edit :P –  dom Mar 19 '12 at 10:54
        
    plz tell me what is "__bridge" in your code? :-) –  iOS developer Mar 19 '12 at 11:05
        
    @Marvin I'm using ARC. __bridge is one of a hand full of keywords, which tell ARC about the objects ownership so it can properly clean them up. The simplest case is a __bridge cast, for which ARC will not do any extra work (it assumes you handle the object's memory yourself). –  dom Mar 21 '12 at 6:45

    up vote 15 down vote accepted

    I had found solution and got answer from here

    From here We can get GPS info as well..

    Amazing and thanks all for helping me to solve this problem.

    UPDATE

    This is another function that I had created myself, also return Exif data as well as GPS data and in this function we doesn't need any third party library.. but you have to turn on location services for this. and use current latitude and longitude for that. so have to use 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;
    }

    and We will retrieve that data like this

    //FOR CAMERA IMAGE
    NSData *originalImgData = [self getImageWithMetaData:imgOriginal];
    
    //FOR PHOTO LIBRARY IMAGE
    [self getImagedataPhotoLibrary:[[myasset defaultRepresentation] metadata] andImage:imgOriginal];

    For all of this you should have to Import AssetsLibrary.framework and ImageIO.framework.

    share|improve this answer
     
        
    where is currentLatitude coming from? Are you setting this from the standard CoreLocation calls before you invoke the UIImagePicker or are you reading it directly from the image that was returned? –  Paul Cezanne Apr 24 '12 at 14:55
        
    CoreLoation calls before invoking UIImagePickerController –  iOS developer Apr 25 '12 at 4:17
        
    ahhh, it can be inaccurate then. You call CoreLocation, invoke UIImagePicker and then physically move the device a distance before taking the image. You will now have inaccurate latitude and longitude. Drat... –  Paul Cezanne Apr 25 '12 at 8:48
        
    But you can also put distance filter for 5 meters so If use moves then It will automatically take its current location.. –  iOS developer Apr 25 '12 at 9:44
        
    but you'll never know the location when the shutter button is pressed, just the current location. (You can keep on moving after the shutter button is pressed.) –  Paul Cezanne Apr 25 '12 at 9:54

    These answers all seem extremely complex. If the image has been saved to the Camera Roll, and you have the ALAsset (either from UIImagePicker or ALAssetLibrary) you can get the metadata like so:

    asset.defaultRepresentation.metadata;

    If you want to save that image from camera roll to another location (say in Sandbox/Documents) simply do:

    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);
    share|improve this answer
     
    1  
    This is a far superior way to do this than the answers from 2012. –  broughten Oct 18 '13 at 6:13
    1  
    It also return much more info than the other ways: They won't return infos Stored in {TIFF} like Model, Make, Copyright, Artist and so on. This should be marked as answer! –  Benedikt Mokroß Dec 7 '13 at 17:02

    You need ALAssetsLibrary to actually retrieve the EXIF info from an image. The EXIF is added to an image only when it is saved to the Photo Library. Even if you use ALAssetLibrary to get an image asset from the library, it will lose all EXIF info if you set it to a UIImage.

    share|improve this answer
     

    I have tried to insert GPS coordinates into image metadata picked by iPad Camera as it was suggested by Mehul. It Works, Thank you for your post.

    P.S. Who intends to use that code, just substitude the two geolocations at the top of the function -(NSMutableData *)getImageWithMetaData:(UIImage *)pImage {

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

    ...

    By supposing that you have already initializied somewhere locationManager in your code, like this:

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

    and by importing CoreLocation/CoreLocation.h and ImageIO/ImageIO.h headers with associated frameworks.

     
  • 相关阅读:
    03 JVM 从入门到实战 | 简述垃圾回收算法
    02 JVM 从入门到实战 | 什么样的对象需要被 GC
    01 JVM 从入门到实战 | 什么是 JVM
    从一道面试题探究 Integer 的实现
    程序员如何写一份更好的简历
    自己动手实现分布式任务调度框架(续)
    一个excel(20M)就能干趴你的poi,你信吗?
    一个普通类就能干趴你的springboot,你信吗?
    自己动手实现springboot配置(非)中心
    自己动手实现分布式任务调度框架
  • 原文地址:https://www.cnblogs.com/YouXianMing/p/3940792.html
Copyright © 2011-2022 走看看