【2/17】今年は「濃厚」技術トーク!@ITメールセミナー スラッシュドット    はてなブックマーク  Yahoo!ブックマークに登録  印刷
 

.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」

ホワイトペーパーTechTargetジャパン

Insider.NET フォーラム 新着記事

@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

RSSフィード

スキルアップ/キャリアアップ(JOB@IT)

- PR -
- PR -

お勧め求人情報

キャリアアップ 〜JOB@IT
@IT Special -PR-
  企業の仮想化に足りない“発想”とは?
仮想化運用管理のキモは意外なところに!

New!
  操作もマニュアルも分かりやすい!
ユーザー視点で開発されたPC管理ツール

New!
  仮想化すればコストは削減できるか?
仮想化に必要な「3つの視点」を解説する

  セキュリティを知り尽くす上野氏が登壇!
@ITメールソリューションLive! in Tokyo

  運用管理の課題を“2つの観点”から分析
ユーザー満足度の高い「仮想環境」とは?

  世界に通用するストレージの作り方とは?
製品に込めた思いを富士通の開発者に聞く

  OSSで手間も時間も、障害も減った――
「マピオンの事例」オープンソース活用法

  「ノートPCの持ち出し禁止」で大丈夫?
情報漏えいを防ぐ管理手法とインフラは?

  1日の処理を1秒に――MySQLの達人が語る
「コスト削減」できるチューニング

  ドキュメント作成を自動化して、SEの作業
効率を大幅アップ! Visio 2007の魅力

  急速に広がるHyper-Vでのサーバ仮想化
そのベストプラクティスをデルが解説

  @IT主催セミナーで語られた、「担当者に
求められるセキュリティ対策」をレポート

  @IT「Windows 7」 特設サイトオープン!
最新情報・移行ノウハウを公開しています