にほんブログ村 写真ブログ デジタル写真へ
にほんブログ村のランキングに参加中です

Exiftool : 自分が作ったPerlスクリプトがあまりにも遅過ぎるから・・・

2014年07月28日 00:00

光と影

光と影

Pentax K10D, Tokina RMC 70-210mmF3.5

※ブログに視覚要素を加えるlightboxを導入しています。上記画像をクリックすると少し大きな画像をポップアップして見る事が出来、暗くなった部分をクリックするか、画像下部のCloseをクリックすると元に戻ります。



前回の記事で作ったスクリプトを実行したところ、あまりにも遅く、これじゃぁ運用していて腹が立つので書き直し・・・。

先ず1つ。こうやってスクリプトを公開しているが、あくまでもうちの環境で上手く行っているだけなので、これらをそれぞれのパソコンで実行したらどうなるか判らない。

特に焦点距離を書き換える場合、xmpサイドカーでなくRawFile本体を書き換えるので(他社のカメラでは不明)、もし興味を持たれてここで紹介しているスクリプトを参考にされるにせよ、バックアップを取ってから実行して頂きたい。流石に責任は持てない。

ではそのあまりにも遅かったスクリプトを改変。これはLightroomで「K or M Lens」と表示されているRawファイルに任意のレンズ名、そして正しい焦点距離情報に書き換えるスクリプトで、予め、Exiftoolの検索用のユニークなキーとして、Lightroomの自由に記載出来るキーワードタグにレンズ名が入っているものとする。

引数は「登録したいレンズ名」、「キーワードタグのレンズ名」、「焦点距離」、「135換算焦点距離」、そして「ファイル名」。詳細は前回の記事を!。


#!/usr/bin/perl

use Image::ExifTool;
use File::Basename;

# 引数チェック
if ($#ARGV == -1) {
   print "Usage : set_k_or_m.pl [lensname] [keyword] [focallength] [35mm frocallength] [*.*]\n";
   print "\tex) set_k_or_m.pl \"SMC P24mmF2.8\" \"24mmF2.8\" \"24\" \"36\" *.*\n\n";
   exit(0);
}

# レンズ名、Lrキーワード、焦点距離、35mm換算焦点距離
my $dstLens = $ARGV[0];
my $keyWord = $ARGV[1];
my $FocalLength = $ARGV[2];
my $FocalLengthIn35mmFormat = $ARGV[3];

# Exiftoolクラス
my $exifTool = new Image::ExifTool;

# パス名、ファイルベースネーム、拡張子
my ($dirName, $baseName, $ext) = "";
my ($xmpBaseName, $pefBaseName, $pefFullName) = "";

#カウンター
my $cnt = 0;

# ファイル名以外の先頭文字列を削除
shift(@ARGV); shift(@ARGV); shift(@ARGV); shift[@ARGV];

# 変更したxmpファイルのベース名を列記するバッファ
my $fileStr = "";

# xmpファイルを対象としたループ
for(my $i = 0; $i <= $#ARGV; $i++) {
   # フルパスを分割
   ($baseName, $dirName, $ext) = fileparse($ARGV[$i], '\..*$');
	
   # xmpファイルなら
   if($ext =~ /xmp/) {
      $exifTool->ImageInfo($ARGV[$i]);

      # exiftoolデータセット
      if ($exifTool->GetValue('Subject') =~ /$keyWord/) {
         $exifTool->SetNewValue('Lens', $dstLens);
         $exifTool->SetNewValue('LensModel', $dstLens);
         $exifTool->SetNewValue('FocalLength', $FocalLength);
         $exifTool->SetNewValue('FocalLengthIn35mmFormat', $FocalLengthIn35mmFormat);
         $exifTool->WriteInfo($ARGV[$i]);

        // 次のループ用にヒットしたベースファイル名を保持
         $fileStr = $fileStr . ", " . $baseName;

         print "$ARGV[$i] update!\n";
         $cnt++;
      }
   }
}

# PEFファイルを対象としたループ
for(my $i = 0; $i <= $#ARGV; $i++) {
   # フルパスを分割
   ($baseName, $dirName, $ext) = fileparse($ARGV[$i], '\..*$');

   # PEFファイルなら
   if ($ext =~ /PEF/) {
      # 変更したxmpファイル名と同一なら
      if ($fileStr =~ /$baseName/) {
         $exifTool->ImageInfo($ARGV[$i]);
         $exifTool->SetNewValue('FocalLength', $FocalLength);
         $exifTool->SetNewValue('FocalLengthIn35mmFormat', $FocalLengthIn35mmFormat);
         $exifTool->WriteInfo($ARGV[$i]);

         print "$ARGV[$i] update!\n";
         $cnt++;
      }
   }
}

print "$cnt files update!\n";
#----end of file



このロジックだと最初にxmpファイルだけを変更し、次に変更したxmpファイルと同名のPEFファイルを探し出し、それに対してだけExiftoolでデータを書き換えるから、無関係のPEFファイルを読み込まず時短に繋がる。フォルダ内の総ファイル数に比べて、書き換える必要のあるPEFファイルが少ない程、処理が早く終わる。

それと今日の方法だと引数のワイルドカード展開されたファイル名がソートされていようがなかろうが、はたまたxmp、PEFファイル以外の拡張子のファイルがフォルダ内にあっても問題なく動作する。

ただ、これは完成形じゃない。あくまでも前回の記事で作ったスクリプトが遅過ぎるのと制約が多過ぎるから、そこを修正しただけ。

実際、現在利用しているスクリプトはさらに進化し、引数にレンズ名や焦点距離名なんて要らないし、ファイル名を与えるだけ。使っているレンズは限られているから、スクリプト内部でXMP:Subject(Lightroomで入力したキーワード)のレンズ名を見て分岐する完全オートマチック仕様にしている。

また前回までのはPentaxカメラにしか作用しないが、同じく電子接点のないマイクロフォーサーズ用のHolga 25mmF8レンズを使ったOlympus E-P3のデータも書き換えられ、今後、その手のレンズが増えても対応が可能になった(その都度、若干、スクリプトを修正するが)。

ここで紹介するには分岐だらけで100行を超えてしまうので割愛した。まぁやっている事は一緒だ。

単純な話で・・・。


# レンズ名、Lrキーワード、焦点距離、35mm換算焦点距離
my @lensSMCP24mm = ("SMC P24mmF2.8", "P24mmF2.8", "24", "36");
my @lensXR50mm = ("Rikenon XR50mmF2", "XR50mmF2", "50", "76");
my @lensSMCM50mm = ("SMC M50mmF2", "M50mmF2", "50", "76");
my @lensSMCP55mm = ("SMC P55mmF1.8", "P55mmF1.8", "55", "86");
my @lensTokina70_210mm = ("Tokina RMC 70-210mmF3.5", "Tokina 70-210mmF3.5", "210", "320");
my @lensXR135mm = ("Rikenon XR135mmF2.8", "XR135mmF2.8", "135", "206");
my @lensSMCM200mm = ("SMC M200mmF4", "M200mmF4", "200", "306");
my @lensHolga25mm = ("Holga 25mmF8", "HOLGA", "25", "50");



上のような所持しているレンズ毎の配列を作り、配列の要素2番目がLightroomのキーワードだから、これをユニークなキーとしてEIXFの中身と比較、合致したらそれぞれの値をxmp、PEF、ORFファイルに代入しているだけだ。

この進化版はあくまでも私の環境では便利ってだけで、例えば、マウントアダプターを介して大量のレンズを使われている方は、そのレンズの数だけif ~ elsif ~の分岐が増えるので、汎用的なのは今日紹介しているコマンドライン引数を使う方だろう。

レンズ毎の配列の要素をそっくりそのままCSV形式のレンズ情報ファイルとして用意すれば、スクリプト本体をいじる事はないのでその方が汎用的かもしれないし、perlの知識がもっと身に付けばさらにperlらしいスクリプトに作り変えられそうだが、自分専用のツールだし、ここはあくまでも写真、カメラネタのブログであって、perlお勉強ブログじゃないので、この程度で勘弁してちょ!。

ついでに、カメラにAFが採用された創生期時代のSigma 70-210mmF4-5.6がPentaxのレンズIDと重なり、Pentax A35-105mmになっちゃうのも次のスクリプトで実現させた。これはSigma 17-70mmと全く同じ造り。


#!/usr/bin/perl

use Image::ExifTool;

my $exifTool = new Image::ExifTool;
my $dstLens = "Sigma UC ZOOM 70-210mm F4-5.6";
my $i = 0;

foreach (@ARGV) {
  $exifTool->ImageInfo($_);

  my $lensId = $exifTool->GetValue("LensID");
  if ($lensId =~ /35-105/) {
    $exifTool->SetNewValue("Lens", $dstLens);
    $exifTool->SetNewValue("LensModel", $dstLens);
    $exifTool->WriteInfo($_);
	print "$_ update!\n";
	$i++;
  }
}

print "\n$i files update!\n\n";
#end of file



これらのスクリプトで手持ちのSigma 17-70mmF2.8-4、APO70-300mmF4-5.6、70-210mmF4-5.6、そして電子接点のない8本のレンズがLightroom上で正確に表示出来るようになったのは嬉しい限り。

時に、cygwin上のシェルからPerlスクリプトやexitoolを起動すると日本語で文字化けしないので、レンズ名に日本語の入力も可能となり、例えば「カビだらけの40年前の24mmレンズ」、「時折使うと面白いけど毎度使いたいとは決して思わないホルガ25mm」等とLightroom上に表示させる事も可能。

これを書いている今、K-5、K-7、E-P3のxmp、Rawファイルの変更を終え、あとはK10D、K20Dのxmp、Rawファイルを残すのみ(まぁJPGファイルは未着手なので、これはもう幾つか新しいスクリプトが必要かも知れず、なんだかんだとあと1週間以上は掛かりそうだ)。

exiftoolのような痒いところに手が届くツールは皆さんに是非とも使って頂きたいが、何せ、コマンドライン、キャラクターユーザーインターフェースのプログラムだからして、MS-DOSやunix系のシェルを理解していないと難しく、万人向きではないなぁ・・・。

ふと思った。このexiftool、SQLのようにcommit、rollbackなる命令があれば、もっと使い易い。失敗してもcommitする前なら元に戻せるのだから・・・。

Pentaxのカメラを使っていて、電子接点のないKマウントレンズやM42レンズ、最近はPentax Q系にマウントアダプターを介して135換算、500mm、1000mmと言った超望遠レンズとして写真を撮る人も多いと聞く。でもこれに加えて、EXIFデータを書き換えるのにCygwinやperlを使うなんてマニアな人はそうはいない。

これらをご存じない方は恐らくperlにImage::Exiftoolをインストールするだけで躓いてしまうだろう。そんな方達にお勧めなのがActivePerl。

本家perlに準拠しており、Windowsのコンソール(cmd.exe)から使えるperlだ。試しに上に書いた全てのスクリプトをActivePerl、そしてcmd.exe上で動かしてみたが、問題なく動作している。変えるのは最初の1行目だけ。

"#!/usr/bin/perl"をAcivPerlのperl.exeのあるパス名にするだけ。うちの環境では"#!c:/app/Perl64/bin/perl"だ。

余談だが、ActivePerlでもExifToolと言うクラス(モジュール)を使用するよ!、なる設定、インストールをしなくちゃならないんだが、GUI環境からマウスちょいちょいで出来ちゃう。だからcygwinのperlよりもとっつきやすい。

余談だが、今回ここで大きく躓いた。と言うのもモジュールにはExifToolの他にExifってのがあるんだな。最初、間違えてExifの方をインストールしちゃい、スクリプトを実行すると、libフォルダにExifToolをインストールしろ!、と怒られる。

何度見ても記述したソースが間違っているとは思えなかったし、インストールを3度もし、libフォルダを確認した。あっ!、ExifじゃなくてExifToolね!!!・・・、これだけの事で15分以上悩んでしまったんだなぁ~。

さて、Widnwosコマンドシェル(コンソールか?)のcmd.exe。こいつはかなり使い辛い。昔のMS-DOS時代よりもファイル名補完、入力履歴を表示出来たりと進化しているが、とにかくキーバインドを変更出来ないし、パス区切りが"/"でなく"\"なのも不快。そんな人にはnyaosと言うtcsh互換のシェルがお勧め。

ActivePerlとnyaosさえインストールしていれば、あとはコマンドラインの基本をネットでササッと学習すれば、上のようなperlスクリプトを自在に操れるだろう。

注意点はcygwinの反対。cmd.exeもnyaosも漢字コードはShift JISなので、スクリプトをShift JISで保存し、改行コードをCRLFにしちゃくちゃならない(普通はそうなっている)。それとActivePerlはWIndows仕様に準拠からフォルダ名などに漢字が入っているとこける時があるので、exiftoolexeやperlスクリプトを使い際は、必ず、該当するファイルが存在するフォルダをカレントとする事。

またActivePerlはファイル名を引数とするスクリプトだとcygwinのシェルからでは使えない。unixライクな/usr/loca/binだのcygwin独特の/cygdrive/c/・・・と言ったフォルダ(ディレクトリ)をActivePerlが全く認識しないからだ。これを認識させるのな ら、スクリプトに、もし引数に「/cygdirive/c/」、もしくは「/c/」なる文字があったら、「c:/」にする、と言う命令を自分で作らないとならない(Perlだと正規表現が使え置換も楽だけど)。

nyaosはEmacs系のキーバインド、C-n、C-p、C-f、C-b、そしてパス区切りが"/"な人なら非常に使い易いし((私もEmacsな人で秀丸エディターのキーバインドをEmacs風に変更している)、cygwinの各種シェルのように基本設定する必要もほとんどない(変更するのはプロンプトくらい?)。cmd.exeの代わりとしてお勧めだ。

本当はEmacsのWindows版のMeadowを使えば、perlプログラミング用に動作させられるし、Meadow上からcmd.exe等のコンソールからのシェルをコントロール出来(それだと文字コードもUTF-8になるんじゃなかろうか?)、もっと楽になるのだろう。

MeadowがまだMuleだった頃、かなり使い込んだのだが(これも仕事でEmacsからアプリケーション開発をしなくちゃならなかった時期があり、無理矢理に・・・)、自宅でプログラミングなんてしないので、純粋なEmacs系エディターはもう5年以上は触っていない(でもEmacsのキーバインドは気に入って今もずっと使っている)。

いずれにせよ、複雑なコードは書かないからわざわざMeadowを導入する必要もなく、cygwinのtcshとperl、Exiftool.exe、Image::Exiftool、そして使い慣れたエディター(私は秀丸だ)。EIXF操作関連の作業は可能となる。

※これだけの事で、Meadowをインストールするくらいなら、仕事で時折使っているEclipse(フリーの開発統合環境ツールでプログラミングに特化した高機能エディターと言えば良かろうか?)をインストールした方が良い

まぁとにかく今後、Lightroomが認識してくれないSigmaレンズや、古い電子接点のないレンズを購入しても、はたまたOlympus E-P3にマウントアダプターを介して様々なレンズを使っても、Exiftoolがあればへっちゃらだ!。もしフィルムカメラなんかに目が向いたら、1コマ毎に露出データをメモして、デジタル化した際に色々とデータを入力出来るし・・・。

いつになるか判らないが、ちょいと壮大な計画を考えている(己のレベルにて)。と言うのも連れはWindowsでなく、Mac OS Xの人だから、マルチプラットフォームで使えるGUIレベルのExif閲覧、変更ソフトを作ってみようかなと。

GUI for Exiftoolなるフリーソフトがあるけど、これはWidnwos専用だから、このGUI for Exiftoolのようなソフトでマルチプラットフォームなのを作れれば・・・。

昔はその手のソフトを開発するのはTcl/Tkが多く使われていたようだが、先ほど調べた限りでは、フリーで使えるマルチプラットフォームのGUIツールってのが仰山ある。Lightroomのプラグインを開発できるSDKもその1つと言って良いだろう。

まさにゼロからのスタートなのと、自宅で高度なプログラミングなんてしたくない人だから、ベースがCやC++なんて嫌じゃ(笑)。GUIビルダーで外観は半自動でやりたいし、プログラム本体はperlみたいにスクリプトでちょちょい!、って書けちゃうのがあればねぇ。

perl/Tkと言うperlを使ってGUIアプリケーションを作れる開発環境があるが、ゼロからガリガリ書いていくような・・・。定番のwxWidgetsが最適か?。どのGUIツールが使いやすいか、簡単なのか、それを調べる事から始まる。まぁ、Javaで組むのが一番楽なのかな。Javaに移植されたExiftoolクラスもあるみたいだし・・・。

いずれにせ1年後くらいにはと思っている(笑)。何せ自分が使うだけなら、今回紹介したperlスクリプトだけで十分だからして、人間、必要に迫られないとやる気が起きない。

今回でexiftoolネタは終わりかと思いきや・・・、次回はC++で自分専用のラッパーを作ってみたので、まとめと題してお送りしたい。


にほんブログ村 写真ブログ デジタル写真へ
にほんブログ村のランキングに参加中です



コメント

    コメントの投稿

    (コメント編集・削除に必要)
    (管理者にだけ表示を許可する)