Androidアプリ開発 Exif 画像のExif情報を取得する

2017年06月04日(編集2017年06月04日)
このエントリーをはてなブックマークに追加

Androidアプリ開発で画像処理を実装する機会は多いです。
画像を表示する場合は、画像の向きを考慮する必要があります。 でないと、画像が回転した状態で表示されてしまう可能性があります。こういったことを防ぐために、画像の向きをExifで取得できます。
この記事は、AndroidアプリでExifを扱う方法を記載した記事です。

環境はAndroid 7.1 (API level 25) です。

環境

  • macOS Sierra
  • android sdk 25
  • Oracle jdk version 1.8.0_72
  • Android Studio 2.3.2

難易度

中級者向け

サンプルコード

Android-Media-Demo

Exif

Exifは、デジタルカメラで撮影した画像データに、撮影条件に関する情報(メタデータ)を追加して保存できる画像ファイル形式の規格です。
撮影した日時やデジタルカメラの機種、画素数、方向、といった情報を記録することができます。

ライブラリ

AndroidでExifを扱う場合は、Supportライブラリを使うことをおすすめします。
Supportライブラリを使うと、コンテンツUriの差異をラップして、InputStreamを通してExifInterfaceを扱うことができます。

インストール

ExifInterface Support Libraryのインストールの設定をgradleにします。

{project_folder}/app/build.gradle
ext {
    buildToolsVersion = "25.0.2"
    supportLibVersion = "25.3.1"
}
          

app/build.gradleには、次のように記述します。

{project_folder}/app/build.gradle
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })

    compile 'com.android.support:appcompat-v7:' + rootProject.supportLibVersion
    compile 'com.android.support:design:' + rootProject.supportLibVersion
    compile 'com.android.support:support-v4:' + rootProject.supportLibVersion
    compile "com.android.support:exifinterface:" + rootProject.supportLibVersion
}
          

ビルド後に、ExifInterfaceのサポートライブラリが利用できるようになります。

画像回転

Exifのorientationが設定されてる画像をそのまま表示すると以下のようになります。

fig1. Exif Orientation 未考慮

画像が回転して表示されてしまってます。
正しい向きで表示するには、画像のExifを取得して画像を回転させる必要があります。

実装

画像UriからExifを取得するには、以下のようなコードを書きます。

{project_folder}/ExifActivity.java
    private int getOrientation(@NonNull Uri uri) {
        int orientation = ExifInterface.ORIENTATION_UNDEFINED;
        InputStream in = null;
        try {
            in = getContentResolver().openInputStream(uri);
            ExifInterface exifInterface = new ExifInterface(in);
            orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
        } catch (IOException e) {
            e.getStackTrace();
            Log.e("ExifActivity", e.getMessage());
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ignored) {
                }
            }
        }
        Log.d("ExifActivity", "orientation" + orientation);
        return orientation;
    }
        

■ 実装の解説

1. ExifInterface

ExifInterfaceは、openInputStreamメソッドでUriからInputStreamを取得して、ExifInterfaceのコンストラクタにinputStreamを設定します。

in = getContentResolver().openInputStream(uri);
ExifInterface exifInterface = new ExifInterface(in);
        

サポートライブラリを使うと、Uriのpathの差異を吸収することが可能です。

2. 方位

方位は、exifInterface#getAttributeIntメソッドで、keyにExifInterface.TAG_ORIENTATIONを指定して取得します。

orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
        

90度回転している画像の場合は、6の値が返ってきます。

3. 回転度数

方位を取得したら、画像の回転度数を取得します。

{project_folder}/ExifActivity.java
    public int getRotation(int exifOrientation) {
        int rotation;
        switch (exifOrientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
            case ExifInterface.ORIENTATION_TRANSPOSE:
                rotation = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
            case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                rotation = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
            case ExifInterface.ORIENTATION_TRANSVERSE:
                rotation = 270;
                break;
            default:
                rotation = 0;
        }
        return rotation;
    }
        

方位定数で必要な回転度数がわかるので、orientationと定数を比較して回転度数を返します。

4. 画像回転

最後に、画像を回転させます。

{project_folder}/ExifActivity.java
Matrix transformMatrix = new Matrix();
transformMatrix.setRotate(rotation);
        

Matrix#setRotateメソッドで回転度数を設定します。
最後に、このmatrixオブジェクトを使ってBitmapを生成します。

{project_folder}/ExifActivity.java
    public Bitmap transformBitmap(@NonNull Bitmap bitmap, @NonNull Matrix transformMatrix) {
        try {
            Bitmap converted = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), transformMatrix, true);
            if (!bitmap.sameAs(converted)) {
                bitmap = converted;
            }
        } catch (OutOfMemoryError error) {
            Log.e("", "transformBitmap: ", error);
        }
        return bitmap;
    }
        

以上で、画像を回転させたBitmapが取得できます。

ビルド

上記のコードの動作を確認してみましょう。

fig2. Exif Orientation 考慮済

画像が回転して表示されました。

結論

Support Libraryを使うと、UriからInputStreamを通してExifが取得できるので、非常に便利です。
Exifは位置情報も含んでいるので、サーバーに画像を送るときに、ローカルでExifを消したりも可能です。

関連記事

タグ検索で調べてみよう

Android7.1 画像処理