人気ブログランキングへ

2008年01月06日

JPEG の Exif 情報を書き換える (Perl)

Perl で、JPEG の Exif 情報を書き換える方法について。

Exif (エグジフ) 規格は、大雑把に言うと、JPEG 画像に、撮影日時やカメラの機種などの付属情報およびサムネイル画像を TIFF 形式で追加した規格、だと思う。
※正確には、規格書を参照していただきたい:
JEIDA 規格 ディジタルスチルカメラ用画像ファイル フォーマット規格(Exif)

追加情報は、JPEG の "APP1" マーカセグメントに格納される。
ほかに、"FlashPix 拡張データ" というのを格納する "APP2" マーカというのもあるが、その詳細はよく知らない。

さて、APP1 セグメントは、TIFF 画像の構造をしていて、0th IFD と 1st IFD の 2 つの IFD (Image File Directory) を含んでいる。
0th IFD には、画像に関する情報が、1st IFD にはサムネイルが格納される。

0th IFD には、複数のフィールドを含むことができ、各フィールドはタグによってその内容が識別される。
タグには、たとえば画像の幅、高さ、ファイルの変更日時、カメラのメーカ名、モデル名、などがある。

1st IFD に格納されるのはサムネイルのみ。

Exif の情報を表示するツールとしては、たとえば
ExifReader
http://www.rysys.co.jp/exifreader/jp/
などがある。
また IrfanView にプラグインをインストールすれば Exif 情報を表示できる。
かみさか氏の JpegAnalyzer Plus は、JPEG ファイルの解析ができる
http://homepage3.nifty.com/kamisaka/JpegAnalyzer/
かみさか氏は、Exif の MakerNote に関する詳細な情報も提供している。
http://homepage3.nifty.com/kamisaka/makernote/index.htm

さて、Perl で JPEG の Exif 情報を書き換えるには、Image::MetaData::JPEG というモジュールが利用できる。
このモジュールは CPAN で公開されている。

使い方の詳細は CPAN サイトを見れば書かれているが、たとえば以下のように使用する。

#!/usr/bin/perl -w
use strict;
use Image::MetaData::JPEG;
my $main_file = '(主画像のファイルパス)';
my $thm_file = '(サムネイル画像のファイルパス)';
my $out_file = '(保存先のファイルパス)';
my $error;
# 主画像 (APP1 マーカセグメントのみ読み込み)
my $image = new Image::MetaData::JPEG($main_file, '^APP1$')
or die "Image::MetaData::JPEG オブジェクトの"
. "インスタンス化に失敗\n";
# 画像タイトル変更
$error = $image->set_Exif_data({ 'ImageDescription' => 'TEST' },
'IFD0_DATA' => 'ADD');
%$error
and die "画像タイトルの書き換え失敗\n"
. $error->{'ERROR'} . "\n";
# サムネイル画像
my $thumbnail = new Image::MetaData::JPEG($thm_file)
or die "Image::MetaData::JPEG オブジェクトの"
. "インスタンス化に失敗 (サムネイル画像)\n";
# サムネイル画像の APPn, COM, DRI マーカセグメントを削除
$thumbnail->drop_segments('^(APP\d+|COM|DRI)$');
# サムネイルを書き換える
$error = $image->set_Exif_data($thumbnail,
'THUMBNAIL' => 'REPLACE');
%$error
and die "サムネイルの書き換え失敗\n"
. $error->{'ERROR'} . "\n";
# ファイルに書き出し
$image->save($out_file);

サムネイル画像の APPn、COM、DRI マーカセグメントを削除しているが、これは Exif の仕様でそのように指定されているため。

なお、APP1 セグメントの最大サイズは JPEG 規格の制約により 64 kB 以下でなければならない。
サムネイル画像にあまり大きな画像を指定すると、Image::MetaData::JPEG は (エラーではなく) 警告を出してサムネイルの書き換えをキャンセルしてしまうので注意が必要。

ちなみに、バージョン 0.15 の Image::MetaData::JPEG には以下のバグがあるようである。
IFD のフィールドエントリはタグ番号の小さいものから順番に並べる必要があるが、タグの値の並べ方は任意である。
しかし、Image::MetaData::JPEG は、フィールドエントリとタグの値の順序が異なると "Jumping back" というエラーで異常終了してしまう。
これを回避するには、Image/MetaData/JPEG/Segment_parsers.pl の $this->die('Jumping back') としている部分をコメントアウトすればよさそうである。
このコメントアウトにともない、この処理を行う foreach 文で、sort keys %$mapping しているが、この sort が必要なく単に keys %$mapping でよくなる。

また、MakerNote タグがあるのに MakerNote のデータ本体が存在しない(?)とエラーになってしまう。
この問題は、Image/MetaData/JPEG/Segment_dumpers.pl の $this->die('ORIGINAL data not found') としているところを、$this->warn('ORIGINAL data not found') とすればよいらしい。
※こちらはなんとなく、警告として残しておきたい気がする。
posted by K/I at 22:21 | 東京 ☀ | Comment(0) | TrackBack(0) | 技術メモ | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:


この記事へのトラックバック