获取图片的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, , 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, , 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..

asked Mar 19 '12 at 7:22
iOS developer
8,688124776
 

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!

answered Mar 19 '12 at 8:42

dom
6,80132550
 
    
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.

answered Mar 27 '12 at 13:26

iOS developer
8,688124776
 
    
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);
answered Mar 13 '13 at 23:19
Andrew Theis
829512
 
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.

answered Dec 13 '12 at 13:24

ATOzTOA
9,17042158
 

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.

 

获取图片的metaData的更多相关文章

  1. jsoup获取图片示例

    import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.Inp ...

  2. 【记录】JS 获取图片原始尺寸-防止图片溢出

    示例代码: <div id="div_content"> <img src="http://static.cnblogs.com/images/logo ...

  3. C#获取图片的后缀名

    最近在学习过程中遇到一个问题,就是如何获取图片的格式,对于一张知道全路径的照片,如果其路径包含后缀名的话,要取得后缀名,只需要一行代码即可: var ext = System.IO.Path.GetE ...

  4. js和jquery如何获取图片真实的宽度和高度

    按照插入的图片的尺寸来判断图片是横图还是竖图.然后判断过后给予不同的展示方式,下面为大家介绍下js和jquery如何获取图片真实的宽度和高度   1.什么时候需要获取图片真实的宽度和高度 在做pc网页 ...

  5. 限制Xamarin获取图片的大小

    限制Xamarin获取图片的大小在App开发中,经常会使用网络图片.因为这样不仅可以减少App的大小,还可以动态更新图片.但是手机使用网络环境千差万别.当网络环境不是理想的情况下,加载网络图片就是一个 ...

  6. js和jquery获取图片真实的宽度和高度

    1.什么时候需要获取图片真实的宽度和高度 在做pc网页的时候,有时候会考虑按照插入的图片的尺寸来判断图片是横图还是竖图.然后判断过后给予不同的展示方式! 另外一种就是在手机页面上,在新闻页插入的图片往 ...

  7. java获取图片原始尺寸

    java获取图片原始尺寸 URL url = null; InputStream is = null; BufferedImage img = null; try { url = new URL(pi ...

  8. Js获取图片原始宽高

    如果我们页面看到的图片都是缩略图,那就需要做个图片点击放大效果,那么怎样获取图片的原始宽高呢?方法如下: //获取图片原始宽度 function getNaturalWidthAndHeight(im ...

  9. 获取图片工具类:BitmapUtil

    package com.example.administrator.filemanager.utils;import android.content.Context;import android.gr ...

随机推荐

  1. Eth 部署智能合约

    首先要开发以太坊的智能合约,需要EVM(以太坊虚拟机),也就是需要运行的环境,我们可以通过 geth 来设置开发环境: geth --datadir testNet --dev console 2&g ...

  2. MOss213获得用户登录名

    因SharePoint2013默认使用claims based authentication,所以其帐号会是i:0#.w|/domain name这样的格式,如何去掉前面的内容,只保留登录帐号呢? 参 ...

  3. c#基础学习(0806)之StringBuilder的使用

    以前字符串的拼接基本都是用string来完成的,从来没有考虑过性能或者速度的问题,自从学习了StringBuilder之后才发现两者的差距有多大,当然,数据量比较小的时候,用string还是挺方便的, ...

  4. resize定义元素尺寸大小

    为了增强用户体验,CSS3增加了很对的新属性,其中一个重要的属性就是resize,它允许用户通过拖动的方式改变元素的尺寸,到目前为止,主要用于可以使用overtflow属性的任何容器元素中 resiz ...

  5. C# 的逻辑运算

    &.^.!和|操作符称为逻辑操作符,用逻辑操作符把运算对象连接起来符合C#语法的式子称为逻辑表达式.逻辑 操作符“!”和“^”只作用于其后的操作数,故称为一元操作符.而“&&” ...

  6. PHP错误日志和内存查看

    1.通过命令查看服务器上一共开了多少的 php-cgi 进程: ps -fe |grep "php-fpm"|grep "pool"|wc -l 2.查看FPM ...

  7. CodeForces762A

    A. k-th divisor time limit per test:2 seconds memory limit per test:256 megabytes input:standard inp ...

  8. Linux : task work 机制

    task work机制可以在内核中向指定的进程添加一些任务函数,这些任务函数会在进程返回用户态时执行,使用的是该进程的上下文.包括下面的这些API: task_work_add task_work_c ...

  9. vue-cli脚手架的安装

    https://github.com/vuejs/vue-cli 官网 使用官方推荐的webpack 条件:node在4.以上,npm在3以上,查看版本号打开cmd输入,node -v     npm ...

  10. setInterval和setTimeout的区别以及setInterval越来越快问题的解决方法

    setInterval()和setTimeout()方法都是js原生的定时方法,当然它们两个的作用也是不同的,并且最近在做上下滚动公告栏的时候,发现了setInterval()非常令人抓狂的问题,那就 ...