2011年2月16日水曜日

iPhoneの画像からEXIF,GPSデータを取得する

iPhone上の画像からEXIF, GPS情報をどのように取得できるのか調べてみました。
EXIFは以前はAPIが提供されていなかったらしく、GoogleCode:iPhone-Exifのライブラリを使ったりしていたみたいですが、iOS4.1からAssetsLibraryというのが増えてそちらからアクセスできるようになったみたいです。

で、EXIF, GPS情報は、どのカメラから撮った写真か? によって取得できる情報量が変わるようです。
注意:すべてのアプリの位置情報サービスをONになっている前提

iPhone標準のカメラから撮った画像をライブラリから取得するとき


ライブラリから取得した場合、UIImagePickerから取得したときの引数のinfoからは取得できないようです。
ALAssetsLibraryからmetadataを抜き出します。

- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info {
 NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
 ALAssetsLibrary *lib = [[[ALAssetsLibrary alloc] init] autorelease];
[lib assetForURL:url
resultBlock:^(ALAsset *asset){
ALAssetRepresentation *representation = [asset defaultRepresentation];
NSUInteger size = [representation size];
uint8_t *buff = (uint8_t *)malloc(sizeof(uint8_t)*size);
if(buff != nil){
NSError *error = nil;
NSUInteger bytesRead = [representation getBytes:buff fromOffset:0 length:size error:&error];
if (bytesRead && !error) {
NSData *photo = [NSData dataWithBytesNoCopy:buff length:bytesRead freeWhenDone:YES];
NSMutableDictionary *metadata = [self performSelector:@selector(getMetadataFromNSData:) withObject:photo];
NSLog(@"%@", metadata);
}
if (error) {
NSLog(@"error:%@", error);
[error release];
free(buff);
}
}
}
failureBlock:^(NSError *error){
NSLog(@"error:%@", error);
}];
}

これで取得したmetadataには、EXIT, GPS 情報が含まれています。
{
ColorModel = RGB;
DPIHeight = 72;
DPIWidth = 72;
Depth = 8;
Orientation = 1;
PixelHeight = 1936;
PixelWidth = 2592;
"{Exif}" = {
ApertureValue = "2.970854";
ColorSpace = 1;
ComponentsConfiguration = (
1,
2,
3,
0
);
CustomRendered = 2;
DateTimeDigitized = "2011:02:14 17:01:51";
DateTimeOriginal = "2011:02:14 17:01:51";
ExifVersion = (
2,
2,
1
);
ExposureMode = 0;
ExposureProgram = 2;
ExposureTime = "0.05";
FNumber = "2.8";
Flash = 0;
FlashPixVersion = (
1,
0
);
FocalLength = "3.85";
ISOSpeedRatings = (
80
);
MeteringMode = 1;
PixelXDimension = 2592;
PixelYDimension = 1936;
SceneCaptureType = 0;
SensingMethod = 2;
ShutterSpeedValue = "4.322165";
WhiteBalance = 0;
};
"{GPS}" = {
ImgDirection = "142.403";
ImgDirectionRef = T;
Latitude = "35.6635";
LatitudeRef = N;
Longitude = "139.7025";
LongitudeRef = E;
TimeStamp = "08:01:49.65";
};
"{TIFF}" = {
DateTime = "2011:02:14 17:01:51";
Make = Apple;
Model = "iPhone 4";
Orientation = 1;
ResolutionUnit = 2;
Software = "4.2.1";
XResolution = 72;
YResolution = 72;
"_YCbCrPositioning" = 1;
};
}

iPhoneアプリのカメラから撮った画像をライブラリから取得するとき


アプリの作り方に依存しますが、特に情報を付加するコードを書いていないとEXIF, GPSの情報は含まれていません。
instagramで撮った写真には入っていませんでした。
{
ColorModel = RGB;
DPIHeight = 72;
DPIWidth = 72;
Depth = 8;
Orientation = 1;
PixelHeight = 612;
PixelWidth = 612;
"{Exif}" = {
ColorSpace = 1;
ComponentsConfiguration = (
1,
2,
3,
0
);
ExifVersion = (
2,
2,
1
);
FlashPixVersion = (
1,
0
);
PixelXDimension = 612;
PixelYDimension = 612;
SceneCaptureType = 0;
};
"{TIFF}" = {
Orientation = 1;
ResolutionUnit = 2;
XResolution = 72;
YResolution = 72;
"_YCbCrPositioning" = 1;
};
}

カメラを起動して写した画像のとき


UIImagePickerを使って、カメラを起動して写した画像のときは、info にメタ情報が入ってきます。

- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info {
NSMutableDictionary *metadata = (NSMutableDictionary *)[info objectForKey:UIImagePickerControllerMediaMetadata];
}

この中にはEXIF情報は入っているようですが、GPSの情報は入ってきません。
GPSの情報は自分で埋め込んであげないといけないようです。
(kCGImagePropertyGPSDictionary のキーワードでググると情報ありそう)

写した画像をライブラリに保存するときは、

ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
[lib writeImageToSavedPhotosAlbum:image.CGImage
metadata:metadata
completionBlock:^(NSURL* url, NSError* error){
NSLog(@"Saved: %@<%@>", url, error);
}];

とするとmeta情報付きで保存できる様子。



写真の位置情報って、「つけてほしい」時と、「つけてほしくない」時がある。
自宅の写真はつけてほしくないけど、旅行行ったときのはつけてほしい。
でも写真ごとに切り替えるのも面倒。
位置情報がついているのも認識せずにどこかにUploadしちゃったミスも発生したり....

たしか、iPhotoで取り込んだ写真ってJPGにExportするとExifの情報を外した気がするのですが、そんなミスも考慮してなんだろうか...
んが、写した日時はやっぱり残して置いてほしかった気も。。

写真を扱うアプリをつくるなら、
メタ情報をわかりやすく見せてミスを防げるようなアプリを作らないとなー
• • •