UIImagePickerControllerが選択後に写真のメタデータを返さないことはよく知られています。ただし、アプリストア内のいくつかのアプリ(Mobile Fotos、PixelPipe)は、元のファイルとその中に保存されているEXIFデータを読み取ることができるようであるため、アプリは選択した写真から地理データを抽出できます。
/ private/var/mobile/Media/DCIM/100Apple /フォルダーから元のファイルを読み取り、EXIFライブラリーを介して実行することで、これを行うようです。
ただし、UIImagePickerControllerから返された写真をディスク上のファイルに一致させる方法を見つけることはできません。ファイルサイズを調べましたが、元のファイルはJPEGであり、返された画像は生のUIImageであるため、選択された画像のファイルサイズを知ることができません。
ハッシュのテーブルを作成し、各画像の最初のxピクセルと照合することを検討しています。しかし、これは少し上に見え、おそらくかなり遅いでしょう。
助言がありますか?
このexif iPhoneライブラリをご覧になりましたか?
http://code.google.com/p/iphone-exif/
私の側で試してみます。 UIImagePickerControllerで撮影した写真からGPS(geotags)座標を取得したい
詳細を見ると、このライブラリはNSData情報を入力として受け取り、UIImagePickerControllerはスナップショットを取得した後にUIImageを返します。理論的には、UIImageのUIkitカテゴリから選択したものを使用すると
NSData * UIImageJPEGRepresentation (
UIImage *image,
CGFloat compressionQuality
);
次に、UIImageをNSDataインスタンスに変換し、iPhone exifライブラリで使用します。
更新:
上記のライブラリにテストを行ったところ、動作するようです。ただし、EXIF形式に関する知識が限られているため、ライブラリに高レベルAPIがないため、EXIFタグの値を取得することができません。誰かがさらに先に進むことができる場合の私のコードは次のとおりです
#import "EXFJpeg.h"
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
NSLog(@"image picked %@ with info %@", image, editingInfo);
NSData* jpegData = UIImageJPEGRepresentation (image,0.5);
EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
[jpegScanner scanImageData: jpegData];
EXFMetaData* exifData = jpegScanner.exifMetaData;
EXFJFIF* jfif = jpegScanner.jfif;
EXFTag* tagDefinition = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_DateTime]];
//EXFTag* latitudeDef = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_GPSLatitude]];
//EXFTag* longitudeDef = [exifData tagDefinition: [NSNumber numberWithInt:EXIF_GPSLongitude]];
id latitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLatitude]];
id longitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLongitude]];
id datetime = [exifData tagValue:[NSNumber numberWithInt:EXIF_DateTime]];
id t = [exifData tagValue:[NSNumber numberWithInt:EXIF_Model]];
....
....
タグ定義の取得は問題ありませんが、すべてのタグ値はnil
:(を返します
ライブラリを試してみたい場合は、グローバル変数を定義して実行する必要があります(ドキュメントで説明されていますが、ハム..:/)
BOOL gLogging = FALSE;
更新2
回答: iPhone-写真から位置情報にアクセス UIImageはメタ情報をカプセル化しません、私たちは立ち往生しています:確かに、このインターフェイスを介してEXIF情報は提供されません。
最終更新
はい、少なくともピッカーから返された写真を適切にジオタグ付けするために、なんとか動作させました。
UIImagePickerControllerをトリガーする前に、CLLocationManagerを使用して現在のCLocationを取得するのはユーザー次第です
一度入手したら、exif-iPhoneライブラリを使用するこのメソッドを使用して、CLLocationからUIImageにジオタグを付けることができます。
-(NSData*) geotagImage:(UIImage*)image withLocation:(CLLocation*)imageLocation {
NSData* jpegData = UIImageJPEGRepresentation(image, 0.8);
EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
[jpegScanner scanImageData: jpegData];
EXFMetaData* exifMetaData = jpegScanner.exifMetaData;
// end of helper methods
// adding GPS data to the Exif object
NSMutableArray* locArray = [self createLocArray:imageLocation.coordinate.latitude];
EXFGPSLoc* gpsLoc = [[EXFGPSLoc alloc] init];
[self populateGPS: gpsLoc :locArray];
[exifMetaData addTagValue:gpsLoc forKey:[NSNumber numberWithInt:EXIF_GPSLatitude] ];
[gpsLoc release];
[locArray release];
locArray = [self createLocArray:imageLocation.coordinate.longitude];
gpsLoc = [[EXFGPSLoc alloc] init];
[self populateGPS: gpsLoc :locArray];
[exifMetaData addTagValue:gpsLoc forKey:[NSNumber numberWithInt:EXIF_GPSLongitude] ];
[gpsLoc release];
[locArray release];
NSString* ref;
if (imageLocation.coordinate.latitude <0.0)
ref = @"S";
else
ref =@"N";
[exifMetaData addTagValue: ref forKey:[NSNumber numberWithInt:EXIF_GPSLatitudeRef] ];
if (imageLocation.coordinate.longitude <0.0)
ref = @"W";
else
ref =@"E";
[exifMetaData addTagValue: ref forKey:[NSNumber numberWithInt:EXIF_GPSLongitudeRef] ];
NSMutableData* taggedJpegData = [[NSMutableData alloc] init];
[jpegScanner populateImageData:taggedJpegData];
[jpegScanner release];
return [taggedJpegData autorelease];
}
// Helper methods for location conversion
-(NSMutableArray*) createLocArray:(double) val{
val = fabs(val);
NSMutableArray* array = [[NSMutableArray alloc] init];
double deg = (int)val;
[array addObject:[NSNumber numberWithDouble:deg]];
val = val - deg;
val = val*60;
double minutes = (int) val;
[array addObject:[NSNumber numberWithDouble:minutes]];
val = val - minutes;
val = val*60;
double seconds = val;
[array addObject:[NSNumber numberWithDouble:seconds]];
return array;
}
-(void) populateGPS:(EXFGPSLoc* ) gpsLoc :(NSArray*) locArray{
long numDenumArray[2];
long* arrPtr = numDenumArray;
[EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:0]];
EXFraction* fract = [[EXFraction alloc] initWith:numDenumArray[0]:numDenumArray[1]];
gpsLoc.degrees = fract;
[fract release];
[EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:1]];
fract = [[EXFraction alloc] initWith:numDenumArray[0] :numDenumArray[1]];
gpsLoc.minutes = fract;
[fract release];
[EXFUtils convertRationalToFraction:&arrPtr :[locArray objectAtIndex:2]];
fract = [[EXFraction alloc] initWith:numDenumArray[0] :numDenumArray[1]];
gpsLoc.seconds = fract;
[fract release];
}
これは、iOS5(ベータ4)とカメラロールで機能します(.hのブロックにはtype defが必要です)。
-(void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
if (url) {
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) {
CLLocation *location = [myasset valueForProperty:ALAssetPropertyLocation];
// location contains lat/long, timestamp, etc
// extracting the image is more tricky and 5.x beta ALAssetRepresentation has bugs!
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror) {
NSLog(@"cant get image - %@", [myerror localizedDescription]);
};
ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
[assetsLib assetForURL:url resultBlock:resultblock failureBlock:failureblock];
}
}
iOS 8
には方法があります
なしサードパーティを使用EXIF
ライブラリ。
#import <Photos/Photos.h>
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
PHAsset *asset = fetchResult.firstObject;
//All you need is
//asset.location.coordinate.latitude
//asset.location.coordinate.longitude
//Other useful properties of PHAsset
//asset.favorite
//asset.modificationDate
//asset.creationDate
}
Appleは、画像からEXIFデータを読み取るために使用できるiOS4にImage I/O Frameworkを追加しました。 UIImagePickerController
がEXIFデータが埋め込まれた画像を返すかどうかはわかりません。
編集: iOS4では、UIImagePickerControllerMediaMetadata
デリゲートに渡される情報ディクショナリのUIImagePickerControllerDelegate
キーの値を取得することにより、EXIFデータを取得できます。
写真が撮られた日付だけが欲しいという同様の質問がありましたが、上記のどれも簡単な方法で問題を解決するようには見えません(例えば、外部ライブラリなし)、ここにあなたが抽出できるすべてのデータがありますピッカーで選択した後の画像から:
// Inside whatever implements UIImagePickerControllerDelegate
@import AssetsLibrary;
// ... your other code here ...
@implementation MYImagePickerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = info[UIImagePickerControllerMediaType];
UIImage *originalImage = info[UIImagePickerControllerOriginalImage];
UIImage *editedImage = info[UIImagePickerControllerEditedImage];
NSValue *cropRect = info[UIImagePickerControllerCropRect];
NSURL *mediaUrl = info[UIImagePickerControllerMediaURL];
NSURL *referenceUrl = info[UIImagePickerControllerReferenceURL];
NSDictionary *mediaMetadata = info[UIImagePickerControllerMediaMetadata];
NSLog(@"mediaType=%@", mediaType);
NSLog(@"originalImage=%@", originalImage);
NSLog(@"editedImage=%@", editedImage);
NSLog(@"cropRect=%@", cropRect);
NSLog(@"mediaUrl=%@", mediaUrl);
NSLog(@"referenceUrl=%@", referenceUrl);
NSLog(@"mediaMetadata=%@", mediaMetadata);
if (!referenceUrl) {
NSLog(@"Media did not have reference URL.");
} else {
ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
[assetsLib assetForURL:referenceUrl
resultBlock:^(ALAsset *asset) {
NSString *type =
[asset valueForProperty:ALAssetPropertyType];
CLLocation *location =
[asset valueForProperty:ALAssetPropertyLocation];
NSNumber *duration =
[asset valueForProperty:ALAssetPropertyDuration];
NSNumber *orientation =
[asset valueForProperty:ALAssetPropertyOrientation];
NSDate *date =
[asset valueForProperty:ALAssetPropertyDate];
NSArray *representations =
[asset valueForProperty:ALAssetPropertyRepresentations];
NSDictionary *urls =
[asset valueForProperty:ALAssetPropertyURLs];
NSURL *assetUrl =
[asset valueForProperty:ALAssetPropertyAssetURL];
NSLog(@"type=%@", type);
NSLog(@"location=%@", location);
NSLog(@"duration=%@", duration);
NSLog(@"assetUrl=%@", assetUrl);
NSLog(@"orientation=%@", orientation);
NSLog(@"date=%@", date);
NSLog(@"representations=%@", representations);
NSLog(@"urls=%@", urls);
}
failureBlock:^(NSError *error) {
NSLog(@"Failed to get asset: %@", error);
}];
}
[picker dismissViewControllerAnimated:YES
completion:nil];
}
@end
したがって、画像を選択すると、次のような出力が得られます(日付を含む!):
mediaType=public.image
originalImage=<UIImage: 0x7fb38e00e870> size {1280, 850} orientation 0 scale 1.000000
editedImage=<UIImage: 0x7fb38e09e1e0> size {640, 424} orientation 0 scale 1.000000
cropRect=NSRect: {{0, 0}, {1280, 848}}
mediaUrl=(null)
referenceUrl=assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG
mediaMetadata=(null)
type=ALAssetTypePhoto
location=(null)
duration=ALErrorInvalidProperty
assetUrl=assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG
orientation=0
date=2014-07-14 04:28:18 +0000
representations=(
"public.jpeg"
)
urls={
"public.jpeg" = "assets-library://asset/asset.JPG?id=AC072879-DA36-4A56-8A04-4D467C878877&ext=JPG";
}
とにかく、誰かの時間をいくらか節約できることを願っています。
ビルドするように契約されたアプリケーションについても、この作業にしばらく時間を費やしています。基本的に、APIは現在のところ有効ではありません。基本的な問題は、UIImageクラスが向きを除くすべてのEXIFデータをSTRIPSすることです。また、カメラロールに保存する機能は、このデータを取り除きます。したがって、基本的に余分なEXIFデータを取得して維持する唯一の方法は、アプリケーションのプライベート「カメラロール」に保存することです。私はこのバグをAppleで提出し、私たちが連絡してきたアプリのレビュー担当者に必要性を強調しました。いつか追加することを望みます。 「ストック」カメラアプリケーションでのみ機能するため、タグ付けはまったく役に立ちません。
[〜#〜] note [〜#〜]アプリストアの一部のアプリケーションhack私が見つけたのは、カメラロールに直接アクセスし、写真を直接保存してGEOデータを保存することです。ただし、これはカメラロール/保存された写真でのみ機能し、残りの写真ライブラリでは機能しません。お使いのコンピューターから携帯電話に「同期」された写真には、向きが取り除かれた以外のすべてのEXIFデータが含まれています。
これらのアプリケーションが承認された理由(カメラロールからDELETEすることもある)と、それを実行しないアプリケーションがまだ抑制されていないことを、まだ理解できません。
IOS 8以降では、 Photos Framework。 を使用できます
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let url = info[UIImagePickerControllerReferenceURL] as? URL
if url != nil {
let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [url!], options: nil)
let asset = fetchResult.firstObject
print(asset?.location?.coordinate.latitude)
print(asset?.creationDate)
}
}
UIImagePickerControllerMediaURL
辞書キーを使用して、元のファイルへのファイルURLを取得します。ドキュメントに書かれていることにもかかわらず、映画だけでなく写真のファイルURLを取得できます。
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Try to get the original file.
NSURL *originalFile = [info objectForKey:UIImagePickerControllerMediaURL];
if (originalFile) {
NSData *fileData = [NSData dataWithContentsOfURL:originalFile];
}
}
これは、パブリックAPIが提供していないものですが、多くの人々に役立つ可能性があります。主な手段は Appleにバグを報告する です。これは必要なものを説明します(また、なぜそれが必要なのかを説明することも役立ちます)。あなたのリクエストが将来のリリースになることを願っています。
バグを提出した後、iPhone開発者プログラムメンバーシップに付属する開発者テクニカルサポート(DTS)インシデントの1つを使用することもできます。これを行う公的な方法がある場合、Appleエンジニアが知っています。
このメタデータを取得するには、低レベルのフレームワークAVFoundationを使用する必要があります。
AppleのSquarecamの例をご覧ください(http://developer.Apple.com/library/ios/#samplecode/SquareCam/Introduction/Intro.html)
以下のメソッドを見つけて、行を追加します。コードに追加しました。返されるメタデータディクショナリには、診断NSDictionaryオブジェクトも含まれます。
- (BOOL)writeCGImageToCameraRoll:(CGImageRef)cgImage withMetadata:(NSDictionary *)metadata
{
NSDictionary *Exif = [metadata objectForKey:@"Exif"]; // Add this line
}
カメラロール画像にこれを使用しています
-(CLLocation*)locationFromAsset:(ALAsset*)asset
{
if (!asset)
return nil;
NSDictionary* pickedImageMetadata = [[asset defaultRepresentation] metadata];
NSDictionary* gpsInfo = [pickedImageMetadata objectForKey:(__bridge NSString *)kCGImagePropertyGPSDictionary];
if (gpsInfo){
NSNumber* nLat = [gpsInfo objectForKey:(__bridge NSString *)kCGImagePropertyGPSLatitude];
NSNumber* nLng = [gpsInfo objectForKey:(__bridge NSString *)kCGImagePropertyGPSLongitude];
if (nLat && nLng)
return [[CLLocation alloc]initWithLatitude:[nLat doubleValue] longitude:[nLng doubleValue]];
}
return nil;
}
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL];
// create the asset library in the init method of your custom object or view controller
//self.library = [[ALAssetsLibrary alloc] init];
//
[self.library assetForURL:assetURL resultBlock:^(ALAsset *asset) {
// try to retrieve gps metadata coordinates
CLLocation* myLocation = [self locationFromAsset:asset];
// Do your stuff....
} failureBlock:^(NSError *error) {
NSLog(@"Failed to get asset from library");
}];
}
画像にgpsメタ情報が含まれている場合は明らかに機能します
それが役に立てば幸い
画像から位置データを抽出する特定の理由はありますか?別の方法として、CoreLocationフレームワークを使用して場所を個別に取得することもできます。必要なジオデータのみである場合、これにより頭痛の種を軽減できます。
ちょっと考えましたが、GitHubのThree20プロジェクトでTTPhotoViewControllerを試しましたか?
これにより、複数のソースから読み取ることができる画像ピッカーが提供されます。 UIImagePickerControllerの代替として使用できる場合があります。または、ソースから、必要な情報を取得する方法の手がかりが得られる場合があります。
UIImagePickerControllerによって返された画像データとディレクトリ内の各画像をハッシュし、それらを比較できる場合があります。
これはSwift 3です。iOS8のサポートが必要な場合:
import AssetsLibrary
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if picker.sourceType == UIImagePickerControllerSourceType.photoLibrary,
let url = info[UIImagePickerControllerReferenceURL] as? URL {
let assetLibrary = ALAssetsLibrary()
assetLibrary.asset(for: url, resultBlock: { (asset) in
if let asset = asset {
let assetRep: ALAssetRepresentation = asset.defaultRepresentation()
let metaData: NSDictionary = assetRep.metadata() as NSDictionary
print(metaData)
}
}, failureBlock: { (error) in
print(error!)
})
}
}
uIImagePickerControllerMediaURLで取得した写真にはexifタグがまったくないようです