.NET TIPS

デジカメ画像のExif情報を取得するには?

デジタルアドバンテージ
2003/07/04

 現在、ほとんどのデジタル・カメラ(以下デジカメ)は、撮影した画像をExif(EXchangeable Image File)という形式のファイルとして保存する。Exifフォーマットの画像ファイルは、画像フォーマットの1つであるJPEGフォーマットに、撮影したデジカメの情報(メーカーやモデル)や、撮影日時、撮影時の条件(露光時間、フラッシュのON/OFFなど)などのさまざまな付加情報を含めたものだ(ファイルの拡張子は「.jpg」。無圧縮の場合はTIFFフォーマットの場合もある)。

 Windowsの描画エンジンであるGDI+は、このExifフォーマットに対応しており、GDI+をベースとしている.NET Frameworkクラス・ライブラリの画像関連クラスにおいても、比較的簡単にExifフォーマットの画像ファイルから、それに埋め込まれた付加情報を取得することができる。

 Exif付加情報の構造について簡単に解説しておくと、付加情報内の個々のデータは次の形式で記述されている。

  • タグ(項目を識別する2bytesの番号)
  • タイプ(データの型。1:8bit符号なし整数、2:ASCII文字(7bit)の文字列、3:16bit符号なし整数、4:32bit符号なし整数など)
  • カウント(データのサイズ)
  • データへのオフセット
  • 実際のデータ

 Exif付加情報についての詳細は、その規格書を参照していただきたい。Exifフォーマットの最新バージョンは2.2のようだが、GDI+が準拠しているバージョンはExif 2.1のようだ。

 タグ番号とタイプについては、取得したいデータのものを規格書であらかじめ調べておく必要がある。例えば、デジカメのメーカーについては、タグ番号が「0x010f」で、タイプは「文字列」である。

PropertyItemsプロパティとPropertyIdListプロパティ

 さて、.NET Frameworkクラス・ライブラリではまず、Exif付加情報内の各データ(画像ファイルの「メタデータ」と呼ばれる)は、PropertyItemクラス(System.Drawing.Imaging名前空間)で表される。このクラスの持つ4つのプロパティは次のようにExif付加情報に対応している。

  • Id(タグ番号に対応)
  • Type(タイプに対応)
  • Len(カウントに対応)
  • Value(実際のデータ)

 そして、このPropertyItemオブジェクトは、画像ファイルを読み込んだBitmapクラス(System.Drawing名前空間)のインスタンスから、PropertyItemsプロパティにより配列として取得することができる。この処理をコードで示すと次のようになる。

Bitmap bitmap = new Bitmap("mypicture.jpg");
PropertyItem[] pis = bitmap.PropertyItems;

 画像の読み込みに関しては、「TIPS:画像を読み込むには?」を参照していただきたい。

 上記のコードにより、画像ファイルに含まれている付加情報の各データはすべて列挙できるが、このままでは配列内にあるそれぞれの要素のIdプロパティをいちいちチェックしないと、必要なデータにたどりつけない。このためBitmapクラスには、Id(タグ番号)のみをint型の配列で返すPropertyIdListプロパティも用意されている。これを利用すれば、次のようにして特定のタグ番号のデータを取得することができる。

Bitmap bitmap = new Bitmap("mypicture.jpg");

int[] pils = bitmap.PropertyIdList;
int index  = Array.IndexOf(pils, 0x010f);

PropertyItem pi = bitmap.PropertyItems[index];

string maker = Encoding.ASCII.GetString(pi.Value);

 Arrayクラス(System名前空間)のIndexOfメソッドは、指定した配列から、指定した値を持つ要素のインデックス番号を返す(見つからなかった場合は-1)。また、最後の行ではEncodingクラス(System.Text名前空間)のGetStringメソッドにより、デジカメのメーカー名を含んだバイト配列を文字列として取得している。

 次のコード例は同様にして、デジカメ画像から撮影時に使用されたISO感度(タグ番号は0x8827)を整数値として取り出す。

Bitmap bitmap = new Bitmap("mypicture.jpg");

int[] pils = bitmap.PropertyIdList;

int index  = Array.IndexOf(pils, 0x8827);
PropertyItem pi = bitmap.PropertyItems[index];

int iso = BitConverter.ToUInt16(pi.Value, 0);

 ISO感度については、タイプ(Type)が「3:16bit符号なし整数」であるため、BitConverterクラス(System名前空間)のToUInt16メソッドにより、2bytesの値を整数に変換する必要がある。これについては「TIPS:バイト列と数値を変換するには?」を参照していただきたい。エンディアンについては、多くのデジカメ画像で問題はなさそうだ。

ファイル名を撮影日付にリネーム

 最後に、Exifファイルから撮影日時を取り出し、画像ファイルのファイル名をその撮影日時で置き換えるほんの少し実用的なサンプル・プログラムを示しておこう。このプログラムはコマンドラインのパラメータで指定されたデジカメ画像のファイルを、「YYYY-MM-SS_HH-MM-SS.jpg」という形式のファイル名に変更する(例:「2002-12-31_23-59-59.jpg」)。

// exifname.cs

using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

class ExifName {
  public static void Main(string[] args) {

    if (args.Length <= 0) {
      Console.WriteLine("デジカメ画像を指定してください。");
      return;
    }

    string oldName = args[0];

    Bitmap bitmap = new Bitmap(oldName);

    int[] pils = bitmap.PropertyIdList;

    int index  = Array.IndexOf(pils, 0x9003);
    if (index == -1) {
      Console.WriteLine("画像に撮影日時が含まれていません。");
      return;
    }

    PropertyItem pi = bitmap.PropertyItems[index];

    string date = Encoding.ASCII.GetString(pi.Value, 0, 19);
    date = date.Replace(':', '-').Replace(' ', '_');

    string newName = date + ".jpg";

    bitmap.Dispose();

    try {
      Console.WriteLine(oldName + " -> " + newName);
      File.Move(oldName, newName);
    } catch (Exception e) {
      Console.WriteLine(e.Message);
    }
  }
}

// コンパイル方法:csc exifname.cs
ファイル名を撮影日付にリネームするC#のサンプル・プログラム(exifname.cs)

 撮影日時のタグ番号は「0x9003」であり、「YYYY:MM:DD HH:MM:SS」の形式で文字列として記録されている。ただし文字列の最後にはNULL文字が含まれているため、上記のプログラムでは19文字分だけを正確に切り出している。なお、File.Moveメソッドによるファイル名の変更については「TIPS:ファイルをコピー/削除/リネーム/移動するには?」を参照していただきたい。

 より実用的に使えるよう改造して活用していただければ幸いである。End of Article

カテゴリ:クラス・ライブラリ 処理対象:ビットマップ
使用ライブラリ:PropertyItemクラス(System.Drawing.Imaging名前空間)
使用ライブラリ:Bitmapクラス(System.Drawing名前空間)
使用ライブラリ:Arrayクラス(System名前空間)
使用ライブラリ:BitConverterクラス(System名前空間)
関連TIPS:画像を読み込むには?
関連TIPS:バイト列と数値を変換するには?
関連TIPS:ファイルをコピー/削除/リネーム/移動するには?
 
この記事と関連性の高い別の.NET TIPS
画像を読み込むには?
より高速にサムネイル画像(縮小画像)を作成するには?
画像をファイルに保存するには?
画像ファイルのフォーマットを知るには?
画像ファイルを高速に読み込むには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間