iphone - UIImagePickerControllerと既存の写真からEXIFデータを抽出する




uiimage exif (12)

iOS 10 - Swift 3の場合

ピッカーのコールバックには、 metadata持つキーがあるinfo UIImagePickerControllerMediaMetadataがありますUIImagePickerControllerMediaMetadata

UIImagePickerControllerが選択後に写真のメタデータを返さないことはよく知られています。 しかし、アプリストア(Mobile Fotos、PixelPipe)のいくつかのアプリは、元のファイルとその中に保存されているEXIFデータを読み取ることができるように見えるので、アプリは選択した写真から地理データを抽出できます。

彼らは、 / private / var / mobile / Media / DCIM / 100APPLE /フォルダから元のファイルを読み込み、EXIFライブラリを通してそれを実行することでこれを行うようです。

しかし、UIImagePickerControllerから返された写真をディスク上のファイルにマッチングさせる方法はありません。 私はファイルサイズを調査しましたが、元のファイルはJPEGですが、返されるイメージは未加工のUIImageであり、選択されたイメージのファイルサイズを知ることができません。

私はハッシュのテーブルを作成し、各画像の最初のxピクセルと照合することを検討しています。 しかし、これは少し上のようで、おそらくかなり遅いようです。

助言がありますか?


AppleはiOS4に画像I / Oフレームワークを追加しました。このフレームワークは画像からEXIFデータを読み取るために使用できます。 UIImagePickerControllerがEXIFデータを埋め込んだ画像を返すかどうかはUIImagePickerControllerません。

編集: iOS4では、 UIImagePickerControllerDelegateデリゲートに渡された情報ディクショナリのUIImagePickerControllerMediaMetadataキーの値を取得して、EXIFデータを取得できます。


UIImagePickerControllerによって返されたイメージデータとディレクトリ内の各イメージをハッシュして比較することができます。


iOS 8以降では、 Photosフレームワークを使用できます

- (BOOL)writeCGImageToCameraRoll:(CGImageRef)cgImage withMetadata:(NSDictionary *)metadata
{

   NSDictionary *Exif = [metadata objectForKey:@"Exif"];   // Add this line

}

このexifのiPhoneライブラリを見ましたか?

http://code.google.com/p/iphone-exif/

私の側でそれを試してみよう。 私はUIImagePickerControllerで撮影された画像からGPS(ジオタグ)座標を取得したいと思います:/

より深い外観の後、このライブラリはNSData情報を入力として受け取り、UIImagePickerControllerはスナップショットを取った後にUIImageを返します。 理論的には、UIImageのUIkitカテゴリから選択したものを使用すると

NSData * UIImageJPEGRepresentation (
   UIImage *image,
   CGFloat compressionQuality
);

その後、UIImageをNSDataインスタンスに変換し、iPhone exifライブラリで使用できます。

更新:
私は上記のライブラリにテストを行い、それは動作するようです。 しかし、EXIF形式に関する私の限られたknwoledgeとライブラリの高レベル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]];
....
....

タグ定義の取得はOKですが、すべてのタグ値はnil返します。

ライブラリに試してみたい場合は、グローバル変数を定義して実行させる必要があります(ドキュメントで説明されていますが、:/)

BOOL gLogging = FALSE;

更新2
ここで答えます: iPhone - 写真からの位置情報にアクセス UIImageはメタ情報をカプセル化していないので、私たちは固執しています:このインターフェースを通してEXIF情報は提供されません。

最終更新
少なくとも、ピッカーによって返された適切な画像にジオタグを付けるために、私はそれを動作させることができました。
UIImagePickerControllerをトリガする前に、CLLocationManagerを使用して現在のCLocationを取得する必要があります
いったんそれを持っていれば、exif-iPhoneライブラリを使ってCLLocationからUIImageにジオタグを付けるこのメソッドを使うことができます:

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


このメタデータを取得するには、下位レベルのフレームワークAVFoundationを使用する必要があります。

AppleのSquarecamの例を見てください(http://developer.apple.com/library/ios/#samplecode/SquareCam/Introduction/Intro.html)

以下の方法を見つけて、コードを追加しました。 返されたメタデータディクショナリには、診断NSDictionaryオブジェクトも含まれています。

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

これはパブリックAPIが提供していないものですが、多くの人に役立つ可能性があります。 あなたの主な援助は、必要なものを記述したAppleにバグを報告することです(なぜそれが必要なのかを説明するのにも役立ちます)。 うまくいけばあなたの要求は将来のリリースになるかもしれないことを願っています。

バグを報告した後、iPhoneデベロッパープログラムのメンバーシップに付属のデベロッパーテクニカルサポート(DTS)インシデントのいずれかを使用することもできます。 これを行う一般的な方法がある場合は、Appleのエンジニアが知っているでしょう。 さもなければ、それは少なくともあなたの窮状を母船の中でもう少し注意を引き出すのに役立つかもしれません。 運が良かった!


これを行うためのいたずらな方法は、UIImagePickerViewControllerのビューをトラバースし、デリゲートコールバックで選択したイメージを選択することです。

 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { id thumbnailView = [[[[[[[[[[picker.view subviews] objectAtIndex:0] subviews] objectAtIndex:0] subviews] objectAtIndex:0] subviews] objectAtIndex:0] subviews] objectAtIndex:0]; NSString *fullSizePath = [[[thumbnailView selectedPhoto] fileGroup] pathForFullSizeImage]; NSString *thumbnailPath = [[[thumbnailView selectedPhoto] fileGroup] pathForThumbnailFile]; NSLog(@"%@ and %@", fullSizePath, thumbnailPath); } 

それはフルサイズの画像へのパスを与え、あなたが選んだEXIFライブラリで開くことができます。

しかし、これはプライベートAPIを呼び出し、あなたがこのアプリを提出すると、これらのメソッド名 Appleによって検出されます。 だからやってはいけない、そう?


ちょっと考えましたが、GitHubのThree20プロジェクトでTTPhotoViewControllerを試してみましたか?

これにより、複数のソースから読み取ることができる画像ピッカーが提供されます。 あなたはUIImagePickerControllerの代わりにそれを使うことができるかもしれません。そうでなければ、ソースは必要な情報をどのように得るかを手掛かりにするでしょう。


ファイルURLを元のファイルに取得するには、 UIImagePickerControllerMediaURL辞書キーを使用します。 ドキュメントに記載されている内容にもかかわらず、映画だけでなく写真のファイルURLも取得できます。

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

私はこれをカメラロール画像に使用しています

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!)
        })
    }

}

画像にgpsメタ情報が含まれているかどうかは明らかです

それが役に立てば幸い


私はビルド契約を結んだアプリケーションのためにこれをやっています。 基本的にAPIが現在立っているので不可能です。 基本的な問題は、方向を除いてUIImageクラスSTRIPSのすべてのEXIFデータです。 また、カメラロールに保存する機能は、このデータを取り除きます。 だから、基本的に余分なEXIFデータを取得して維持する唯一の方法は、あなたのアプリケーションのプライベート "カメラロール"に保存することです。 私はこのバグをAppleにも提出し、私たちが接触してきたアプリレビュー担当者の必要性を強調しました。 うまくいけば、いつか彼らはそれを追加してくれるでしょう。そうでなければGEOが完全に無用なタグをつけることになります。

注記アプリケーションの一部のアプリケーションはこれをハックします。 私が見つけたのは、GEOデータを保存するためにカメラのロールに直接アクセスして写真を保存することです。 ただし、これはカメラのロール/保存された写真でのみ動作し、残りの写真ライブラリでは動作しません。 コンピュータから携帯電話に「同期」された写真には、向きが取り除かれていることを除いてすべてのEXIFデータがあります。

私はまだそれらのアプリケーションがなぜ承認されたのか理解できません(カメラロールから削除さえも)





exif