Image::Magick を使って大量画像のサムネイル画像を一括自動生成

お仕事で素材集 CD-ROM 内の画像ファイル全2万点を全てリサイズして欲しいという依頼が来た。自社のコンテンツに使うためのリサイズ作業です。初めは OPTPiX webDesigner のバッチ処理で何も考えず 50 x 40 px にリサイズ。縦横比が違う画像が一杯なので何とも無惨な画像が数時間後にできあがった・・・orz

仕方がないので、PhotoShop のバッチ機能でトリミング〜リサイズ処理をやってみた。どうやら素材集の jpeg の圧縮パラメータが違うようでリサイズ後の保存時にダイアログが開いて圧縮パラメータをどうするかいちいち聞いてくる。OK ボタンを押すだけなのだが、全然バッチになってない・・・orz

仕方がないのでリターンキーを押下状態にしてセロハンテープを貼り付けて帰宅時に放置。今日の朝に完成しているはずだったけど、しっかりと PC がフリーズしてました・・・orz

- スポンサーリンク -

しょうがないので、Perl + Image::Magick で一斉処理をすることにしました。自端末に ActivePerl は入っているものの Image::Magick は入っていないのでインストールからの作業。


Windows 版 Image::Magick のインストール

Image::Magick の公式サイトへ行きます。わかりづらいかもしれないけど、左目ニューから下の図のところをクリック。

imagemagick01.jpg

Windows 版バイナリをインストール。static 版と dll 版の2つがあるので取りあえずどちらもインストール。Perl から Image::Magick を使うには、dll 版が必要。static 版が必要かどうかはよくわかんない。

imagemagick02.jpg

現時点での最新版は 6.3.3-6 の模様。

インストールしたら、コマンドプロンプトを開いて以下を実行。

cd C:\Program Files\ImageMagick-6.3.3-Q16\PerlMagick
ppm install Image::Magick.ppd

ここまでやったらマシンを再起動すれば Perl から Image::Magick が使えるようになっています。
Image::Magick についてより多くの情報が知りたい場合はこちらをどうぞ。


あるディレクトリ配下の画像を固定サイズにリサイズするスクリプト

今回の要件は、

1. 縦横比が違う画像がいっぱいあるけど、何しろ 50 x 40 px にリサイズすること。
2. 必要に応じてなるべく賢くトリミングすること。

です。なので、取りあえずアルゴリズム的には、

1. width : height = 5 : 4 の比率を元に、width を軸にしてリサイズするか height を軸にリサイズするか判定
2. リサイズ後に飛び出た部分をトリミング。取りあえず画像の両端を同じ px 分切ることにする
3. ディレクトリ名に _s を付けて別の場所にリサイズ画像を保存
4. 元画像が jpg で出力は png

で、後は File::Find 使ってディレクトリ配下を総なめしてガンガンリサイズ。ファイル検索イテレータ Find::File::Iterator って便利かも?なんて記事を書いているにもかかわらず、相変わらずクセで File::Find を使い続けてます・・・。

use Image::Magick;
use File::Find;

our $RESIZE_X = 50;
our $RESIZE_Y = 40;

find( { wanted => \&filter, no_chdir => 1 }, './image' );

sub filter {
    my $name;
    my $dir;
    eval {
        $name = $File::Find::name;
        $dir  = $File::Find::dir;
        return if ( $name !~ /jpg$/ );

        ## 画像縮小
        my $img = Image::Magick->new;
        $img->Read($name);
        my ( $x, $y ) = $img->Get( 'width', 'height' );
        if ( $x > $y * $RESIZE_X / $RESIZE_Y ) {
            $img->Resize( width => $x * $RESIZE_Y / $y, height => $RESIZE_Y );
            $img->Crop( width => $RESIZE_X, height => $RESIZE_Y, x => ( $x * $RESIZE_Y / $y - $RESIZE_X ) / 2, y => 0 );
        }
        else {
            $img->Resize( width => $RESIZE_X, height => $y * $RESIZE_X / $x );
            $img->Crop( width => $RESIZE_X, height => $RESIZE_Y, x => 0, y => ( $y * $RESIZE_X / $x - $RESIZE_Y ) / 2 );
        }
        binmode(STDOUT);
        my ($newname) = $name =~ m!.+(/.+)\..+$!;
        my $newdir = $dir . '_s';
        mkdir($newdir) unless ( -e $newdir );
        print qq{$name -> $newdir$newname.png\n};
        $img->Write("png:$newdir$newname.png");
    };
    if ($@) {
        warn "$name : $@ \n";
    }
}

実行してみたら2万点の画像が僅か5分程度で処理完了!すげぇ〜Σ(゚Д゚;!!!
初めからこうしておけば良かったと後悔・・・

無保証ですが、スクリプトをご利用になる際は、path 設定とかリサイズ変数とかの値を自分向けにカスタマイズしてご利用下さい。いやぁ〜あいかわらず Image::Magick 便利だわぁ〜

- スポンサーリンク -