phpで画像のリサイズ+トリミング(切り取り)を行ったのでメモ

はじめに

サイト内で画像の一覧ページがあったのだが、画像によってページのデザインが崩れてしまうことがあった。
原因としては画像の幅と高さの比率が同じでないとずれてしまうことがあることが判明。
webデザイナーさんに相談するとcssで対応するのが難しいとのことだったので、とりあえず画像をアップロードする際にサーバ側で画像を加工してしまうことにした

やりたかったこと

画像のアップロード自体は身内の運営が行うので全く想定外のものはアップロードしないでもらうことにした。
で、アップロードする際に横幅=1280px、高さ=780pxで統一してしまうことにした。
とはいえ、そのままリサイズすると画像がつぶれてしまうものもあったので横幅の拡大(または縮小)率に合わせて縦幅もリサイズしてはみ出た分は上下からカットしてしまうという対応を行った。

>例. 元画像 横幅=2560px、高さ=1600px
1. まずはリサイズ
横幅を2560pxを1280pxにしたいので0.5倍する。
次に高さを横幅に合わせるので(1600px)×(0.5)=800pxとする。
ここまでで横=1280px、高さ=800pxの画像ができる

2. 高さのはみ出た分を切り取り
1.でできた画像の高さが20px余分なので上下から10pxずつカットする

phpimagemagickで実装する

//入出力ファイル名
$input = "input.jpg";
$output = "output.jpg";

//圧縮率 ※JPEGの場合は1(高)〜100(低)まで指定可
$quality = 100;

//変換後画像の幅高さ
$resize_x = 1280;
$resize_y = 780;

//元画像の幅高さを取得
list($size_x, $size_y) = getimagesize($input);

//横幅の拡大(または縮小)率をもとめる
$ratio_x = $resize_x / $size_x;

//横幅の拡大(または縮小)率に合わせた場合の高さをもとめる
$tmp_resize_y = $size_y * $ratio_x;

//横幅の拡大(または縮小)率に合わせた高さから上下カットする高さをもとめる
$tmp_cutsize_y = ($tmp_resize_y - $resize_y) / 2;

//リサイズ
$cmd = sprintf(
    "convert -resize %dx%d! -quality %d %s %s"
    ,$resize_x
    ,$tmp_resize_y
    ,$quality
    ,$input_file
    ,$output_file
);
exec($cmd);

//縦で余分な分をカット(上)
$cmd = sprintf(
    "convert -crop %dx%d+%d+%d %s %s"
    ,$resize_x
    ,$tmp_resize_y - $tmp_cutsize_y
    ,0
    ,$tmp_cutsize_y
    ,$output_file
    ,$output_file
);
exec($cmd);

//縦で余分な分をカット(下)
$cmd = sprintf(
    "convert -crop %dx%d+%d-%d %s %s"
    ,$resize_x
    ,$resize_y
    ,0
    ,$tmp_cutsize_y
    ,$output_file
    ,$output_file
);
exec($cmd);

とりあえず上記な様な処理でやりたいことは実現できました。
ついでに最近fuelphpをつかっているのでコレをfuelphpのライブラリなどつかって書き直してみました

//入出力ファイル名
$input = "input.jpg";
$output = "output.jpg";

//圧縮率 ※JPEGの場合は1(高)〜100(低)まで指定可
$quality = 100;

//変換後画像の幅高さ
$resize_x = 1280;
$resize_y = 780;

//元画像の幅高さを取得
list($size_x, $size_y) = getimagesize($input);

//横幅の拡大(または縮小)率をもとめる
$ratio_x = $resize_x / $size_x;

//横幅の拡大(または縮小)率に合わせた場合の高さをもとめる
$tmp_resize_y = $size_y * $ratio_x;

//横幅の拡大(または縮小)率に合わせた高さから上下カットする高さをもとめる
$tmp_cutsize_y = ($tmp_resize_y - $resize_y) / 2;

//リサイズ
Image::load($input)
->resize($resize_x, $tmp_resize_y)
->crop_resize($resize_x, $resize_y)
->save($output);

ほとんど同じなんですけど、リサイズの部分が簡単になりました。
マニュアル見るとcrop_resizeはリサイズとトリミングを行ってくれるとのことなのでした。

// 例えば、300x200 の画像を 200x200 にトリミングするということは、上下 50px を削除するということになります

上記のように書いてあったのでやりたいことそのままで助かりました

今回は身内が画像をアップロードするので色々融通も利きました。こういうの不特定多数のユーザがアップロードするようなサービスだと大変なんだろうなぁと、、、