ExifInterfaceの利用

## はじめに
この記事は [AdventCalendar Android その2](https://qiita.com/advent-calendar/2017/android_second) の11日目の記事です。

## ExifInterfaceとは？

> Exchangeable image file format（エクスチェンジャブル・イメージ・ファイル・フォーマット）は、富士フイルムが開発し、当時の日本電子工業振興協会 (JEIDA)で規格化された、写真用のメタデータを含む画像ファイルフォーマット。デジタルカメラの画像の保存に使われる。略称はExifで「エグジフ」（もしくは「イグジフ」）。
カメラの機種や撮影時の条件情報を画像に埋め込んでいて、ビューワやフォトレタッチソフトなどで応用することができる。Exif2.2ではExif Printという規格を組み込んでおり、撮影時の条件情報を元に自動的に最適化を行って、的確な状態でプリント出力を可能にしている。また撮影者や著作権情報、コメントなど付随することが出来る。対応画像形式はJPEG、TIFF、JPEG XR（HD Photo）。

引用: [Wikipedia](https://ja.wikipedia.org/wiki/Exchangeable_image_file_format)

だそうです。

## Androidで標準カメラアプリを利用する

Androidでは、標準で搭載されているカメラアプリが存在します。
メーカーごとにカメラデバイスには差異があるため、メーカー(or端末)が違えば、カメラアプリも違います。

実装方法に関しては、[こちら](https://qiita.com/Yuki_Yamada/items/137d15a4e65ed2308787)が非常にわかりやすいです。

1. 起動するカメラアプリIntentに画像のuriのpath、title、mime typeを付与する。(ContentProvider経由でuriを保存する。)
2. カメラ or ドキュメント(ライブラリ)を開く
3. カメラ撮影(ドキュメントから画像選択)後、画像を処理(orientationを利用したrotateなど)する。

カメラ利用時には、Exif情報が付与されます。誰しも見たことがあると思います。
位置情報であったり、orientation(どの回転でカメラが撮影されたか)などです。

## 標準カメラアプリ実装(利用)でちょっと困ること

Androidに標準で搭載されているカメラアプリを利用する場合、ちょっと不便だなと思うことがあります。

* 画像処理しづらい。(Rawデータ(画像)からExifInterfaceの情報を取得できない。)
* Kitkat(4.4)未満では、FileDescriptorが使えない。
* 端末依存により、ExifInterfaceから求めたいorientationが取れない(幾つかの端末では、縦向き状態が0degreeではなく、横向き状態が0degreeであるため、縦向きでとるとdegreeがおかしくなる。)

RawデータからExifInterfaceを利用できなかったのですが、1年ほど前にSupport Libraryがアップデートされていました。
[Introducing the ExifInterface Support Library](https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html)

上記の複数の問題はこのNew APIの登場のおかげで一気に簡単になりました。
既に記載しているように、`Rawデータから、ExifInterfaceを利用できる` ようになりました。
以前まではわざわざContentProvider経由でfile pathを取得するという面倒な作業がありましたが。。。


## 使い方
全体的な利用方法はドキュメントをみてください。

```build.gradle
dependencies{
    // 最新のsupport libraryのversionを入れてください。
    compile "com.android.support:exifinterface:25.1.0"
} 
```

InputstreamからExifInterfaceを生成できるようになりました。

```Activity.java
Uri uri; // the URI you've received from the other app
InputStream in;
try {
  in = getContentResolver().openInputStream(uri);
  // inputstreamを直接渡すことが可能になった。
  ExifInterface exifInterface = new ExifInterface(in);
  // Now you can extract any Exif tag you want
  // Assuming the image is a JPEG or supported raw format
} catch (IOException e) {
  // Handle any errors
} finally {
  if (in != null) {
    try {
      in.close();
    } catch (IOException ignored) {}
  }
}
```


またこのInterfaceからは、以下のサムネイル情報を取得できるようにもなりました。

* Thumbnailの有無
* Bitmap
* Datetime
* 圧縮の有無
* 緯度経度
* バイトデータ

### まとめ
標準カメラアプリを利用しているものとしては、ExifInterfaceの登場は非常に助かりました。
ぜひ使ってください。

### 補足: FileDescriptor

Kitkat以上からは以下のクラス群を利用できます。
FileDescriptorは、ファイルを開いたりする際の端末固有の構造に対する不透明性をハンドリングしてくれます。
ExifInterfaceがInputstreamに対応できるようになったのですが、一応記載しておきます。

```CameraPick.java
public Bitmap getPickerBitmap(@Nonnull Intent data) throws IOException {    
    ParcelFileDescriptor parcelFileDescriptor
            = activity.getContentResolver().openFileDescriptor(uri, "r");
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
    parcelFileDescriptor.close();
    return bitmap;
}
```


## 参考
https://qiita.com/Yuki_Yamada/items/137d15a4e65ed2308787
https://ja.wikipedia.org/wiki/Exchangeable_image_file_format
https://source.android.com/devices/camera/
https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html