【WPF】C#でjpgのExif情報を読み込む


概要

C#(WPF)で、jpg画像の中のEXIF情報を取り出し/書き込みする。
読み書きには、BitmapMetadataクラスのGetQuery/SetQueryを使用する。

読み出し

流れは下記のようにする。

  • ファイルパスからBitmapFrameクラスのインスタンスを作成(画像を読み込み)。
  • BitmapMetadataクラスで、EXIF情報を含むMetadataを取り出し。
  • 取り出したMetadataから、GetQueryメソッドを使って必要なデータを取り出す。

具体的には、下記のようにする。

// ファイル/Metadata読み込み
Uri uri = new Uri(tb_FileName.Text, UriKind.Absolute);
BitmapFrame frame = BitmapFrame.Create(uri);
BitmapMetadata metadata = frame.Metadata as BitmapMetadata;

// GetQueryしてエラーになる場合、
// クエリの中の型(「ushort」の部分)が間違っているかもしれない。
// その時は、「読み込み位置の指定(クエリ)の実験」で行ったMetadataの列挙のところで
// 出力される型を確認する。(画像ファイルによって、型が異なる?)

// varの型が実際何かは、デバッグ実行して、この下でとめて、ウォッチの「種類」欄で帰ってきた値の型を見る。
var GPSLatitudeRef = metadata.GetQuery("/app1/ifd/gps/subifd:{ushort=1}");  // 北緯or南緯
var GPSLatitude = metadata.GetQuery("/app1/ifd/gps/subifd:{ushort=2}");     // 緯度
var GPSLongitudeRef = metadata.GetQuery("/app1/ifd/gps/{ushort=3}");        // 東経or西経
var GPSLongitude = metadata.GetQuery("/app1/ifd/gps/{ushort=4}");           // 経度

var Maker = metadata.GetQuery("/app1/ifd/{ushort=271}");                    // メーカー名
var Model = metadata.GetQuery("/app1/ifd/{ushort=272}");                    // モデル名

var MakerExif = metadata.GetQuery("/app1/ifd/exif/{ushort=34864}");         // Exifバージョン

metadata.GetQuery()で各idの値をとれるが、何の型で帰ってくるのか、がよくわからなかった。
結果、ソース中にも書いているが、帰ってきたところでbreakで止めて、ウォッチで中身の型を見て判定した。

読み出し(実験)

GetQueryに引数として渡すクエリは、
"/app1/ifd/exif" のように名前?で指定もできるし、
"/app1/ifd/{ushort=34665}"のようにIDで指定もできる。
 ※IDが何かは、規格資料(参考資料参照)の中に書いてある。
  /app1/ifd/{ushort=34665}は、下の「Exifタグ」のところのIDを使う。

名前を使った場合と、IDを使った場合の例は、下記の通り。


// ファイル/Metadata読み込み
Uri uri = new Uri(tb_FileName.Text, UriKind.Absolute);
BitmapFrame frame = BitmapFrame.Create(uri);
BitmapMetadata metadata = frame.Metadata as BitmapMetadata;

BitmapMetadata metadata2 = (BitmapMetadata)metadata.GetQuery("/app1");
Debug.WriteLine("Metadataを列挙 /app1");
foreach (string str in metadata2)
{
    Debug.WriteLine(str);
}

#if true
BitmapMetadata metadata4 = (BitmapMetadata)metadata.GetQuery("/app1/ifd");
Debug.WriteLine("Metadataを列挙 /app1/ifd");
foreach (string str in metadata4)
{
    Debug.WriteLine(str);
}
#else
// 以下は、上の処理と同じ
BitmapMetadata metadata4 = (BitmapMetadata)metadata.GetQuery("/app1/{ushort=0}");
Debug.WriteLine("Metadataを列挙 /app1/{ushort=0}");
#endif

#if true
BitmapMetadata metadata6 = (BitmapMetadata)metadata.GetQuery("/app1/ifd/exif");
Debug.WriteLine("Metadataを列挙 /app1/ifd/exif");
foreach (string str in metadata6)
{
    Debug.WriteLine(str);
}
#else
// 以下は、上の処理と同じ
BitmapMetadata metadata6 = (BitmapMetadata)metadata.GetQuery("/app1/ifd/{ushort=34665}");
Debug.WriteLine("Metadataを列挙 /app1/ifd/{ushort=34665}");
#endif

#if true
BitmapMetadata metadataGPS = (BitmapMetadata)metadata.GetQuery("/app1/ifd/gps");
Debug.WriteLine("Metadataを列挙 /app1/ifd/gps");
foreach (string str in metadataGPS)
{
    Debug.WriteLine(str);
}
#else
// 以下は、上の処理と同じ
BitmapMetadata metadataGPS = (BitmapMetadata)metadata.GetQuery("/app1/ifd/{ushort=34853}");
Debug.WriteLine("Metadataを列挙 /app1/ifd/{ushort=34853}");
#endif

それぞれ「Debug.WriteLine(str);」で、そのIDにぶら下がっている項目が一覧表示される。

コード

参考

EXIF規格
http://www.cipa.jp/std/documents/j/DC-008-2012_J.pdf

わかりやすいEXIFの規格のイメージ(図がわかりやすい)
http://dsas.blog.klab.org/archives/52123322.html

書き込みのサンプル
http://puni-o.hatenablog.com/entry/2017/12/15/113053

読み込みのサンプル
http://funct.hatenablog.com/entry/20151007/1444231916