Image::Magick でサムネールを正方形に切り抜く方法


Perl モジュール Image::Magick を使って CGI プログラムでアップロードした画像のサムネールを正方形に切り抜く方法の紹介です。

ホームページ上の表示のためにCSS(スタイルシート)で切り抜きを行う方法はこちらをどうぞ
「形の違う画像の表示サイズを揃える方法」

これはシリーズ記事「Image::Magick の使い方」の 6/8 番目です。 目次を表示

サムネールを正方形に切り抜き

Image::Magickの使い方サンプルコード元画像

元画像

Image::Magickで正方形に切り取ったサムネール

50x50 の正方形に切り取ったサムネール

サムネールを正方形に切り抜く手順

サムネールを正方形に切り抜く場合、以下の手順で行います。

  1. 元画像のサイズ計測
  2. 縮小
  3. 正方形に切り抜き

元画像のサイズ計測

まずは、元画像が元画像が縦長(portrait)なのか横長(landscape)なのかを調べます。
横長の画像であれば高さがサムネールサイズなるように、縦長の画像であれば横幅がサムネールサイズになるように縮小する訳です。

正方形サムネールの切り取り方 - 縦長画像と横長画像の違い

正方形サムネールの切り取り方 - 縦長画像と横長画像の違い

Image::Magick サンプルコード:画像のサイズ計測

#元のサイズ取得
my ($w, $h);
eval{($w,$h) = $img->Get(
‘width’,
‘height’
)};
unless ($w && $h){
print “サイズの取得に失敗しました。: $ret $@\n”;
exit;
}

#縦長か横長かを判別
my $type = ‘landscape’; #正方形も便宜上 landscape
if ($w < $h){
$type = ‘portrait’;
}

サムネール用に縮小

画像が縦長か横長かが分かったら、縮小を行います。幅または高さのみ指定してそのサイズまで縮小します。
Image::Magick のリサイズ指定は「(幅)x(高さ)」で行いますので、高さだけ指定する時は「x(高さのピクセル)」、幅だけを指定する時は「(幅のピクセル)」と指定します。

Image::Magick サンプルコード:短い方の辺に合わせて画像を縮小

この例では 50×50 のサムネールにしますので、短い辺が 50px になるように縮小します。

#サムネールサイズ
my $thumb;
my $thumb_geo = “x50“; #横長画像は縦をサムネールサイズに縮小
if ($type eq ‘portrait’){
$thumb_geo = “50“; #縦長画像は横をサムネールサイズに縮小
}
eval{
$thumb = $img->Clone();
$ret = $thumb->Thumbnail(geometry=>$thumb_geo);
};
if ($ret||$@){
print “サムネールの縮小に失敗しました。: $ret $@\n”;
exit;
}

縮小用のメソッドは Resize でもOKです。Thubmnail を使うと画像メタデータを削除します。

正方形に切り抜き

縮小した画像を、正方形からはみ出る分は切り取ります。
リサイズ後の画像サイズをもう一度測って、「(幅と高さの差)÷2」ずつを余っている方向から切り取ります。

Image::Magick サンプルコード:画像を正方形に切り抜き

Image::Magick の切り抜きメソッド Crop のパラメータは以下の通りです。
「(切り抜き後の幅)x(切り抜き後の高さ)+(A:切り抜き開始点X)+(B:切り抜き開始点Y)」

Xは左端からの距離、Yは上端からの距離です。

元の画像が横長であれば、A=縦横の差÷2の位置、B=0です。
元の画像が縦長であれば、切り抜き開始点は A=0、B=縦横の差÷2の位置です。

正方形サムネールの切り取り方 - 切り抜き指定の指定方法

正方形サムネールの切り取り方 - 切り抜き指定の指定方法

my ($tw, $th);
eval{($tw, $th) = $thumb->Get(
‘width’,
‘height’
)};
unless ($tw && $th){
print “縮小後サムネールサイズの取得に失敗しました。: $ret $@\n”;
exit;
}
my $crop_geo = sprintf(‘50×50+%d+%d‘,
($type eq ‘landscape’)?int(($tw-50)/2):0, #(幅-高さ)÷2
($type eq ‘portrait’)?int(($th-50)/2):0, #(高さ-幅)÷2
);
eval{$ret = $thumb->Crop(geometry=>$crop_geo);};
if ($ret||$@) {
print “サムネール画像の正方形化に失敗しました。: $ret $@”;
exit;
}
$saved{thumb} = “$dir/thumbnail$ext”;
eval{$ret = $thumb->Write($saved{thumb})};
if ($ret||$@){
print “サムネールファイルの保存に失敗しました。: $ret $@\n”;
exit;
}