mini_exiftool で Exif を解析してレンズ名を取り出す

# はじめに

[Exif: Exchangeable image file format](http://www.cipa.jp/std/documents/j/DC-008-2012_J.pdf) とは写真などの画像データのフォーマット情報に関する規約です。

Exif へレンズの情報を載せるようになったのは Exif 2.3 からです。Exif 2.3 では LensModel タグへレンズ名称を記載することとなっています。

しかし、それ以前から各ベンダーは固有領域の Makernote へ独自フォーマットでレンズ名称を記載していました。 

LensModel タグは必須項目ではなく、オプショナル項目であることも相まって、レンズ名称を取得するのに苦労した・・・  
というおはなしです。

# 準備

Exif 解析用のライブラリとしては [Exifr](https://github.com/remvee/exifr) がメジャーですが、[mini_exiftool](https://github.com/janfri/mini_exiftool) を使うこととしました。（固有領域情報を取得しやすいからだったか）

mini_exiftool は exiftool のラッパーですので、exiftool をインストール

```
brew install exiftool
```

そして、gem でインストール

```
gem install mini_exiftool
```

# レンズ名称の取得

## 前提

* 1. Exif バージョン 2.3 以降 LensModel タグへ記載されている可能性がある
* 2. Exif バージョンに依存せず、固有領域の Makernote へ独自フォーマットで記載されている可能性がある
* 3. レンズ名称の記載がない可能性がある

## Exif データをサンプリング

上記を踏まえ、100件ほどの写真（それぞれカメラ・レンズが異なる）の Exif をサンプリングした結果、レンズ名称のタグは以下に書かれていることが多いようです。

* LensModel
* Lens
* LensID

サンプルを検証したデータの一部抜粋
_余分な情報も入ってますが、スルーしてください_

```
"ファイル名,Exifバージョン,モデル名,レンズ名,焦点距離,35mm換算レンズ焦点距離,Fナンバー,LensModel,Lens,LensID" 
"1.jpg,0221,NIKON D90,28-300mm f/3.5-6.3,50.0 mm,-,4.2,-,28-300mm f/3.5-6.3,Tamron AF 28-300mm f/3.5-6.3 XR LD Aspherical (IF) (185D)" 
"10.jpg,230,ILCE-7,FE 55mm F1.8 ZA,55.0 mm,-,4.0,FE 55mm F1.8 ZA,FE 55mm F1.8 ZA,-" 
"2.jpg,220,DSC-N1,-,7.9 mm,-,2.8,-,-,-" 
"3.jpg,0221,Canon PowerShot SX20 IS,5.0 - 100.0 mm,42.4 mm,-,5.0,-,5.0 - 100.0 mm,Unknown 5-100mm" 
"4.jpg,0221,E-420,Olympus Zuiko Digital 25mm F2.8,25.0 mm,-,2.8,-,Olympus Zuiko Digital 25mm F2.8,-" 
"5.jpg,230,X-E1,XF60mmF2.4 R Macro,60.0 mm,-,2.8,XF60mmF2.4 R Macro,XF60mmF2.4 R Macro,-" 
"6.jpg,230,X-E1,XF18-55mmF2.8-4 R LM OIS,27.7 mm,-,11.0,-,XF18-55mmF2.8-4 R LM OIS,-" 
"7.jpg,230,SLT-A57,DT 55-200mm F4-5.6 SAM,120.0 mm,-,22.0,DT 55-200mm F4-5.6 SAM,DT 55-200mm F4-5.6 SAM,-" 
"8.jpg,230,ILCE-7,FE 28-70mm F3.5-5.6 OSS,47.0 mm,-,7.1,FE 28-70mm F3.5-5.6 OSS,FE 28-70mm F3.5-5.6 OSS,-" 
"9.jpg,230,DSLR-A850,35mm F2,35.0 mm,-,2.2,35mm F2,35mm F2,Minolta AF 35mm F2 [New]" 
"100.jpg,230,SLT-A55V,24-105mm F3.5-4.5,22.0 mm,-,7.1,24-105mm F3.5-4.5,24-105mm F3.5-4.5,Sigma 18-200mm F3.5-6.3 DC" 
"91.jpg,230,DSLR-A580,DT 18-55mm F3.5-5.6 SAM,18.0 mm,-,3.5,DT 18-55mm F3.5-5.6 SAM,DT 18-55mm F3.5-5.6 SAM,Sony DT 18-55mm F3.5-5.6 SAM [II] (SAL1855)" 
"92.jpg,230,DSLR-A580,50mm F1.7,50.0 mm,-,1.7,50mm F1.7,50mm F1.7,-" 
"93.jpg,230,DSLR-A580,MACRO 100mm F2.8,100.0 mm,-,18.0,MACRO 100mm F2.8,MACRO 100mm F2.8,Minolta AF 100mm F2.8 Macro [New]" 
"94.jpg,230,DSLR-A580,DT 18-55mm F3.5-5.6 SAM,55.0 mm,-,5.6,DT 18-55mm F3.5-5.6 SAM,DT 18-55mm F3.5-5.6 SAM,-" 
"95.jpg,0221,NIKON D1H,24.0-70.0 mm f/2.8,24.0 mm,-,19.0,-,24.0-70.0 mm f/2.8,-" 
"96.jpg,220,SIGMA SD14,-,500.0 mm,-,9.0,-,-,-" 
"97.jpg,220,SIGMA SD14,-,50.0 mm,-,2.8,-,-,-" 
```

## レンズ名称取得ロジック

サンプルデータを解析した結果、以下の割り切りロジックとしました。  

* Exif バージョンは意識しない
* `LensID`, `LensModel`, `Lens` の順にタグをチェックしていき、値が入っているものをレンズ名とする
* レンズ名称が `unknown` であった場合、`LensModel`, `Lens` を再チェックする

レンズ名称とするタグの順番に関しては、個人的な所感で `LensID` が一番詳細で正確な値が設定されていると判断したためです。

一部、特殊なケースとして、`LendID` に `unknown` と書かれ、`LensModel` に正しい名称を記載しているデータがあったので対応を入れておくこととする。

ソースにすると以下のような形です。

```
exif = MiniExiftool.new path
lens = exif['LensID'] || exif['LensModel'] || exif['Lens']
lens = exif['LensModel'] || exif['Lens'] if lens =~ /unknown/i
```

# 最後に

完璧にレンズ名称を取得するのではなく、８割ほどの情報をカバーできればよいという前提で考えています。

独自調査による解析ロジックにてレンズ名称を取得していますので、ご利用は自己責任でお願いします。