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

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

# 読み出し
流れは下記のようにする。

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

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

``` .cs
// ファイル/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を使う。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352601/db08e8e1-6365-8820-9e4a-28ddf238fad6.png)

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

```.cs

// ファイル/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にぶら下がっている項目が一覧表示される。

# コード
https://github.com/tera1707/WPF-/tree/master/017_SetGetExif

# 参考

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