ホーム ] 実行時間計測ラブラリ ] EXIF情報ライブラリ ] 文字式演算 ] クイックソートライブラリ ] 多倍長演算ライブラリ ] 多倍長演算ライブラリU ] 画像処理ライブラリ ]

上へ
実行例
EXIF情報の獲得
EXIF情報の保存

技術解説

EXIF情報の獲得

最終更新日:2007/04/26  全面改訂

●概要

 EXIF情報を読む方法には二通りある。一つはバイナリファイルを直接読み取る方法*である。もう一つは、GDI+ に標準装備のPropertyItemクラスを利用する方法で、複雑怪奇なメタ構造を持ったEXIF形式を熟知する必要がなく、比較的簡単なコードで実現できるのでお勧めで、このライブラリでも利用している。

*:筆者はその昔、バイナリファイルから読んでいた。しかし、メタデータに完全対応するのが面倒だったので、決め打ち方式で行っていたが、メーカの都合や、メーカ提供のソフトバージョンやファイルバージョンで結構 変更があり、その都度悪戦苦闘していた。やはり、原理的に対応しておくのが結局良い。 

●原理

○全てを知る

 その写真にどんな情報があるかは、全てのTag をPropertyIdListで列挙する。そのリストから必要なTagを検索する。

○特定のアイテムを知る

 Tag を知りたいアイテムのタグ番号とすれば、

      Image.GetPropertyItem(Tag)

とすれば、PropertyItem オブジェクトが得られる。

○PropertyItemクラスの構造

 生のEXIFのIFDのディレクトリエントリ に相当する。

  • ID       :Integer EXIFのTag

  • Type   :Short   EXIFのデータ型

  • Len     :Integer バイト数
    EXIFではデータの繰り返し数であるが、これは、総バイト数

  • Value  :Byte() バイト配列
    EXIFではポインタであってもリンク処理され最終データが確保される
    ←ここが便利!。またバイトオーダは常にリトルエンディアン(インテル形式)に統一される。

●方法(アイテムの獲得)

 今、bmpをExifファイルを読み込んだBitmapとすると、先ずは、

 Imports System.Drawing.Imaging

 Dim IDList() As Integer = bmp.PropertyIdList

 として、そのファイルにある全てのTagのIDコレクションをIDListに得る。これがあれば、個々のTagへのアクセスやTagの列挙などができる。

1.列挙(中身も含めて)

For Each ID As Integer In IDList
    Dim p As PropertyItem = bmp.GetPropertyItems(ID)
   ・・・・・・・・・・・・・・・・・・・・・・
Next

2.個々のTag

 Dim p As PropertyItem
  p = bmp.GetPropertyItems(Tag)
  If p Is Nothing Then ・・・・・  

●方法(値の獲得)

 個々のPropertyItem の実際の値は、Value なるバイト配列(UByte)として得られる。このままでは、処理ができないので、Type に従って型変換を行い、通常の数値や文字列にする必要がある。

 また、EXIFのバイナリ形式は二つの方式がある。ビッグエンディアン(モトローラ形式)とリトルエンディアン(インテル形式)である。これは、一般のバイナリ形式と同じであるが、メーカによって一定しないし、同じメーカでもバージョンによっては変化するし、混在する場合がある。これらは、ファイルのヘッダ部分に記録されているので、それに従って変換処理を行う。

●分数(表現)の処理

 小数点がある数値は分数になっている。(U)Int32の分子と(U)Int32の分母が並んでいる。小数点表現がいい場合と、分数表現がいい場合があるので、Tagによって 以下の切り替えると良い。

○シャッタ速度

  伝統的に、1秒以下の場合は、1/200などと表現する。まさか、0.005秒とは言わない。データとしては、1、200の場合もあるし、10、2000の場合もあるので、

If 分子 < 分母 Then
   表現 = "1/"+(分母 \ 分子).ToString("0")
Else
   表現 = (分子 / 分母).ToString()     'General 形式
End If

などとする。ただ、データベースでシャッタ速度で検索などするには、時間として浮動小数点で持っていると便利。

○絞り値

 F5.6などと表す。

 表現 = "F" + (分子 / 分母).ToString()     'General 形式

で良い。焦点距離なども同じ。General 形式では、少数以下がなければ整数で表現される。大抵は、伝統的な絞り値系列になるようになっている。

○露出補正値

 0.3や -0.7 などと表現する。符号付数値で処理をする。

 表現 =  (分子 / 分母).ToString()     'General 形式

○日付

 日付は、2005:04:10 11:12:15 のように、年月日部分も":"で区切られている。気持ち悪ければ、"/"で置き換える。DTが元の日付文字列とすれば、共通関数のReplaceで、

 DT = Replace(DT, ":", "/", 1, 2, CompareMethod.Text)

とすれば良い。上式の 2 は、最初の2箇所のみ置き換えると言う指示。