JPEGファイルのXMPメタデータ取得
下の記事のように、PDFファイルのXMPメタデータは何とか取得できるようになったので、今度はJPEGファイルです。JPEGファイルのXMPメタデータは、以前、Meta Data Extractor in C#というライブラリを利用すると書いたのですが、結局日本語をうまく処理することができず、同じ記事で力技として紹介した方法を採用しました。(その時の情報源となったASPAllianceのページはなくなってしまいましたが...)
JPEGファイルを読み込み、XMPメタデータの開始・終了タグを頼りにXMLで記述されたXMPメタデータを抜き出し、XmlDocumentクラスを利用して読み込みと解析を行っています。ファイルを丸ごと読み込むと重いので、XMPメタデータがありそうな先頭20,000bytes程度読み込み、見つからないときだけすべて読み込むようにしました。リアルタイム処理をしているわけではないのでまぁいいかと...また、XMPメタデータの開始・終了タグがPhotoshop (Elements)のバージョンによって"<x:xmpmeta>"と"<x:xapmeta>"の2種類あるようで、処理を分ける必要がありました。
確かに力技ではありますが、.NET FrameworkがXMLのパーシングやら文字コードなどの面倒を一手に引き受けてくれるので、今のところこんな感じでも特に問題なく読み取れています。こんな感じで多量の画像ファイルに埋め込まれたXMPメタデータをインデックス化し、データベースにインポートしようというわけです。
ちょっと不細工ですけど、ソースコードは以下のような感じ...
・XMPメタデータ抽出部分
// Photoshop Elements 3.0
const string BEGIN_CAPTURE1 = "<x:xmpmeta";
const string END_CAPTURE1 = "</x:xmpmeta>";
// Photoshop Elements 2.0, Photoshop 7.0
const string BEGIN_CAPTURE2 = "<x:xapmeta";
const string END_CAPTURE2 = "</x:xapmeta>";
System.IO.StreamReader sr = new System.IO.StreamReader(filename, Encoding.GetEncoding("utf-8"));
string xmp = "";
char[] buf1 = new char[MAX_BUFFER];
sr.Read(buf1, 0, buf1.Length);
string buf2 = new String(buf1);
int bpos1 = buf2.IndexOf(BEGIN_CAPTURE1, StringComparison.CurrentCultureIgnoreCase);
int epos1 = buf2.IndexOf(END_CAPTURE1, StringComparison.CurrentCultureIgnoreCase);
int bpos2 = buf2.IndexOf(BEGIN_CAPTURE2, StringComparison.CurrentCultureIgnoreCase);
int epos2 = buf2.IndexOf(END_CAPTURE2, StringComparison.CurrentCultureIgnoreCase);
if (bpos1 >= 0 & epos1 >= 0)
{
// <x:xmpmeta </x:xmpmeta>
xmp = buf2.Substring(bpos1, (epos1 - bpos1) + END_CAPTURE1.Length);
}
else if (bpos2 >= 0 & epos2 >= 0)
{
// <x:xapmeta </x:xapmeta>
xmp = buf2.Substring(bpos2, (epos2 - bpos2) + END_CAPTURE2.Length);
}
else
{
sr.Close();
sr = new System.IO.StreamReader(fi.FullName, Encoding.GetEncoding("utf-8"));
buf2 = sr.ReadToEnd();
bpos1 = buf2.IndexOf(BEGIN_CAPTURE1, StringComparison.CurrentCultureIgnoreCase);
epos1 = buf2.IndexOf(END_CAPTURE1, StringComparison.CurrentCultureIgnoreCase);
bpos2 = buf2.IndexOf(BEGIN_CAPTURE2, StringComparison.CurrentCultureIgnoreCase);
epos2 = buf2.IndexOf(END_CAPTURE2, StringComparison.CurrentCultureIgnoreCase);
if (bpos1 >= 0 & epos1 >= 0)
{
// <x:xmpmeta </x:xmpmeta>
xmp = buf2.Substring(bpos1, (epos1 - bpos1) + END_CAPTURE1.Length);
}
else if (bpos2 >= 0 & epos2 >= 0)
{
// <x:xapmeta </x:xapmeta>
xmp = buf2.Substring(bpos2, (epos2 - bpos2) + END_CAPTURE2.Length);
}
else
{
xmp = "";
}
}
sr.Close();
・XMPメタデータ解析部分
xd.LoadXml(xml);
XmlNodeList xn = xd.GetElementsByTagName("dc:title");
string title = xn.Item(0).ChildNodes[0].InnerText;
xn = xd.GetElementsByTagName("dc:description");
string description = xn.Item(0).ChildNodes[0].InnerText;
http://pub.ne.jp/tb.php/405181