写真ネタが続いたので、ちょっとプログラミングネタを。といっても写真絡みであるのは間違いない。デジタルカメラで撮影すると、写真の画像ファイル(JPEG形式)にEXIFという撮影時の情報が記録される。これは非常に便利なもので、EXIF情報を解釈するソフトを使うと、写真の整理などがかんたんにできてしまうし、あとから撮影条件などを確認するのにも便利だ。今回は、このEXIF情報をC#などのプログラムから扱うにはどうするか、どいうことをまとめてみた。
EXIF:Exchangeable Image File=交換可能なイメージファイルの意
まず環境を、.NET Framework上と想定しておきたい。すると使用言語はVisual BasicやC#ということになるのだが、個人的に使用頻度の高いC#にしておきたい。Visual Basicでもほぼ同じ書きかたで使えるはずである。
.NET Framework上では、EXIF情報を扱うのは非常にカンタンで、System.Drawing名前空間のBitmapオブジェクトを使うだけである。Bitmapオブジェクトに画像をロードし、PropertyItemプロパティを使ってアクセスするだけである。PropertyItemはSystem.Drawing.Imagingのコレクション型であるので、foreach構文を使って各要素を取得することになる。
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(filename);
foreach (System.Drawing.Imaging.PropertyItem item in bmp.PropertyItems)
{
………
}
System.Drawing.Imaging.PropertyItemは、Id, Type, Valueという3つのプロパティから構成される。IdはEXIF情報を識別する番号であり、Typeは情報の形式を、Valueはデータそのものを表す。
Idは膨大であるが、以下のサイトが非常に参考になる。実際に、どの情報を引っ張ってくるかはIdがわからないとどうしようもないので、資料と首っ引きになる。
Exif file format: Exif file format
Exif Tags: EXIF Tags (英語)
ちなみにTypeを抜粋すると、以下のようになっている。
Typeプロパティの値 | データの型 |
---|---|
1 | Byte |
2 | ASCII形式でエンコードされたByteオブジェクトの配列 |
3 | 16ビット整数 |
4 | 32ビット整数 |
5 | 有理数を表す2つのByteオブジェクトの配列 |
6 | 未使用 |
7 | 未使用 |
8 | 未使用 |
9 | SLong |
10 | SRational |
上記のコードの省略部分では、Idを判別し、Typeに応じてValueを処理することになる。ちなみに、代表的な情報は文字列と整数値であり、前者ではたとえばカメラモデル、後者はたとえばISO感度が該当する。これを取り出すコードを書いてみると、こんな感じになる。
//カメラモデル情報を取得
if (item.Id == 0x0110 )
{
string val = System.Text.Encoding.ASCII.GetString(item.Value);
string model = val.Trim(new char[] { '\0' });
}
//ISO感度情報を取得
if (item.Id == 0x8827)
{
short val = BitConverter.ToInt16(item.Value, 0);
short iso = val;
}
………
あるいは、Typeプロパティの値に応じて処理してもいい。
//エンコードされたASCII文字列を取得
string str;
short int16;
if (item.Type == 2 )
{
str = System.Text.Encoding.ASCII.GetString(item.Value);
}
//16ビット整数値を取得
if (item.Type == 3)
{
int16 = BitConverter.ToInt16(item.Value, 0);
}
………
バイト列データの文字列への変換には、System.Text.Encoding.ASCIIクラスのGetStringメソッドを使える。16ビット整数への変換にはBitConverterクラスのToInt16メソッドが使える。自前で書くと面倒な処理も、一発で済ませられるのが.NET Frameworkの持つ膨大なクラスライブラリのメリットだ。
処理が終わったら、bmpオブジェクトをDisposeすればいい。
bmp.Dispose();
ちなみに日付情報は文字列で入っているなど、その形式には注意しなければならないので、上記のページを参考にしてひとつずつ処理をしていった方が確実である。