今日のCPANモジュール(跡地)

宣伝と注意書き

このサイトが元になったCPANモジュールガイドという本を書きました。

本書でも画像編集の定番として取り上げています。だいたいこのページの内容と同じですが、EXIFの取り方やImager::Filter::RoundedCornerを使った角丸画像の作り方なども扱いました。

2007-05-24

use Imager;

今日は画像編集用モジュール Imager を説明します。サムネールを作ったり形式を変換したりなどなど画像操作のいろんな要望に応えてくれるモジュールです。

他の画像編集ライブラリ GDImageMagick の Perl インターフェースに比べ、できることは多く、必要とする外部ライブラリが少なめで、同じくらい速く、品質も悪くなく、そしてAPI がきれいです。使わない手はありません。

Imager も他の画像編集ライブラリのようにコアは C ですが、コアと Perl インターフェースが別々ではなく、セットで Perl 専用に開発されているという点が強みになっているのだと思います。公開から数年たっていますが、Subversion レポジトリのログを見るとわかりますが今なお開発が活発です。(開発は imager.perl.org ドメインで行なわれています)

どうでもいい点ですが、C ライブラリの Perl binding はメソッドが camelCase になる場合が多いですが、ぼくは perlstylePBP で推奨されている non_camelcase の方が好みで、このあたりでも GD などより Imager がお気に入りだったりします。

インストール

開発者たちの Good Job に付いていくには cpan で最新版を入れるのがよいかと。ただ、apt や yum とかに Imager そのものがあります。なお、事前に jpeglib libtiff libpng libgif libttf libfreetype あたりのライブラリが入ってるか確認しておくとよいです。なくても Imager は入りますが、対応形式が少なくなってしまいます。Debian の場合だとこんな感じですかね

# aptitude install libjpeg-dev libtiff-dev libpng-dev giflib-dev libttf-dev libfreetype6-dev
# cpan Imager

インストールされた Imager が対応したファイル形式は %Imager::formats ハッシュのキーとして入っていますので、以下のようなワンライナーで対応形式一覧を見れます。

perl -MImager -e 'print join ", ", sort keys %Imager::formats'

OSX はもちろん Windows もサポートされているのも心強いところです。README によると ActivePerl と cygwin でテストされているようです。今回のサンプルは Debian、cygwin で同じスクリプトで動作することを確認してます。

使い方

使い方は単純で、Imager->new で Imager のインスタンスを作成した後、それが持つ たくさんのメソッドのいずれかを使って画像操作します。

サムネール作成

よくあるサムネール作成をやってみます。

use Imager;

my $img = Imager->new;

# ある画像を開き...(type を指定しない = 自動認識)
$img->read( file => 'nya.png' )
    or die $img->errstr;

# 縦か横が160pxになるように縮小し...
# (新しい Imager オブジェクトが返るので、それで元のを上書き)
$img = $img->scale(
    xpixels => 160,
    ypixels => 160,
);

# Jpeg、画質 90% で保存
$img->write( file => 'nya-scaled.jpg', jpegquality => 90 )
    or die $img->errstr;

この画像が こうなります。

この例では Imager のメソッドの read()scale()write() を使ってます。その他のたくさんのメソッドは POD に

の2系統でまとめれられていて、たいへんわかりやすいです。各リンク先にあるのメソッドの説明も、オプションに何が指定できるのか、何が返ってくるのか、サンプル中心で英語もわかりやすいと思います。

例えば scale() の項目を見ると、200x200に「収まるように」小さくするには、type => 'min'、縦横比を無視してそのサイズに引き伸ばしたい場合は type => 'nonprop' というオプションをつければいいことがわかります。

元画像の50%というように指定したい場合は、逆引きのところ を「size」で検索すると size, image - "getwidth" in Imager::ImageTypes, "getheight" in Imager::ImageTypes とあり、getwidth() で画像のサイズが取れるようですので、こんな風に。

$img = $img->scale(
    xpixels => $img->getwidth * 0.5,
);

画像を縮小するときはシャープマスクをかけるときれいです。これも逆引きのところ を「sharp」で探してみると以下のようなのが見つかります。

sharpen - "unsharpmask" in Imager::Filters, "conv" in Imager::Filters ...と、2種類方法があるようですが、アンシャープマスクの方を弱めにかけるには、以下のコードを先ほどの例の $img->write() の前に入れる感じですね。

$img->filter( type => 'unsharpmask', stddev => 1 )
    or die $img->errstr;

こんな感じになりました。

ちなみに、アンシャープマスクは「シャープにしない」という意味ぽい名前ですが、そうじゃなく、ボケた(アンシャープな)画像との差を計算して逆にシャープにするというロジックの名前です。

図形描画

図形を描画することもできます。四角を描くには box() を使って以下のようにします。

$img->box(
    xmin =>  20, ymin => 320,
    xmax => 170, ymax => 370,
    color => '#ffffff',
    filled => 1,
);

こんな感じの画像ができます。ソース全文

画像の貼り付け

四角以外に、丸とか、座標を指定してもっと複雑な図形もかけますが、ふきだしを追加したい場合とかならそのような画像を貼り付けるほうが楽です。

このふきだし画像 (背景が透過な GIF)を貼り付けるには、rubthrough() で以下のようにします。

# ふきだし画像を透過を考慮して貼り付け...
$img->rubthrough(
    src  => do {
        my $tmp = Imager->new;
        $tmp->read( file => 'caption.png' ) or die $tmp->errstr;
        $tmp; # srcへふきだし画像のImagerオブジェクトを渡す
    },
    tx => 22,
    ty => 567,
);

こんな風になります。透過処理をしない場合は paste() ですが、貼り付けたいのはたいてい透過な部分がある画像なので、結局いつも rubthrough() を使ってます。

テキスト

こうなってくると そろそろ文字も追加してみたくなるころですので、逆引きのところを調べると、drawing text - "string" in Imager::Draw, "align_string" in Imager::Drawとあります。

string() を見ると、文字については特別で、Imager::Font オブジェクトとの組み合わせになります。全体では以下のようなコードになります。

# IPA Pゴシックフォントをオブジェクト化
my $font = Imager::Font->new( file => 'ipagp.ttf' );

# 文字を書き込み...
$img->string(
    x => 40,
    y => 650,
    string => "潜入成功ニャ!",
    utf8 => 1,
    font => $font,
    size => 38,
    aa => 1,
    color => '#000000',
);

こんな風になりました。全体のコードはこちら

string パラメータの文字列は、

必要があります。このあたりは、メルマガでまだ utf8 まわりを取り上げてないので、詳細は省略します。いずれまとめて説明します。

さて、テキストの入力を考え始めると、

などのめんどうな話がでてきます。しかし、そこは CPAN。このあたりの文字組み処理は、Imager からの派生モジュールで Imager::DTP というのがあり、これがかなりいい感じにやってくれます。これはまた別の機会に取り上げます。

とはいえ Imager だけでも、デジカメ写真の撮影日とかを EXIF から取りたいよ(→ tags() )とか、モザイク画像にしたいよ(→ filter( type => "mosaic" ) )とか、使える機能がいろいろです。一度 逆引きのところ を通してながめておくことをおすすめします。