【PHP】画像をリサイズして軽くする(GD)

当サイトでは外部サイトの OGP 画像(SNS シェア等に用いられる画像)をキャッシュしているのですが、OGP 画像はサイズが大きく重たい場合が多いので、リサイズして比較的軽い JPEG に変換しています。以下ではその流れについて説明します。
まず、全体のソースコードは以下のようになります。なお、GD というライブラリを使用しているため、実行環境にインストールされているか確認してみてください。
// 画像サイズの取得
$img_path = '画像のファイルパス';
$src_image_size = getimagesize(img_path);
$src_img_w = $src_image_size[0];
$src_img_h = $src_image_size[1];
// MIME タイプに応じて、画像の読み込み
if($src_image_size['mime'] == ("image/jpeg")){
$src_image = imagecreatefromjpeg(img_path);
}elseif($src_image_size['mime'] == ("image/png")){
$src_image = imagecreatefrompng(img_path);
}elseif($src_image_size['mime'] == ("image/gif")){
$src_image = imagecreatefromgif(img_path);
}elseif($src_image_size['mime'] == ("image/bmp")){
$src_image = imagecreatefrombmp(img_path);
}elseif($src_image_size['mime'] == ("image/webp")){
$src_image = imagecreatefromwebp(img_path);
}else{
$src_image = NULL;
}
// 読み込んだ画像が JPEG/PNG/GIF/BMP/WEBP だった場合
if(!is_null($src_image)){
// 画像が特定のサイズを超えていた場合
if(($src_img_w > 768) || ($src_image_size['mime'] != ("image/jpeg"))){
$dst_img_w = 768;
$dst_img_h = (int)($dst_img_w/$src_img_w*$src_img_h);
// リサイズ後の空画像を作る
$dst_image = imagecreatetruecolor($dst_img_w, $dst_img_h);
// 画像のリサイズ
imagecopyresampled($dst_image, $src_image, 0, 0, 0, 0, $dst_img_w, $dst_img_h, $src_img_w, $src_img_h);
// JPG (品質 90) で保存
imagejpeg($dst_image, $img_path, 85);
// リサイズ後の画像のメモリ解放
imagedestroy($dst_image);
}
// 読み込んだ画像のメモリ解放
imagedestroy($src_image);
}
最初に、getimagesize() で画像サイズと MIME タイプ(拡張子のようなもの)を取得します。(GD不要)返り値の 0 番目および 1 番目の要素は、それぞれ画像の幅と高さを表します。また、mime は画像の MIME タイプに一致します。ここで、画像サイズを取得するのは、画像のアスペクト比を計算するためです。
次に、MIME タイプに応じて、画像ファイル読み込み(正確にはメモリ内に画像を作成)を行います。imagecreatefrom ~ がそれにあたり、GD ライブラリの関数になります。
画像ファイルが読み込めたら、次に(画像サイズが大きかった場合)リサイズに移ります。
今回は幅 768 px になるように、アスペクト比を守ってリサイズします。画像の高さは、
(リサイズ後の高さ) = (リサイズ後の幅)÷(リサイズ前の幅)×(リサイズ前の高さ)
なので、この値を int (整数型)で計算します。
リサイズ後の画像の幅と高さが決まったら、この画像サイズのメモリ確保(空画像を作成)します。imagecreatetruecolor()(GDライブラリ)を使いますが、ここで imagecreate() を使ってしまうと、画像の MIME タイプによってはリサイズ後の画像が変な色になる場合があります。
リサイズには、imagecopyresampled()(GDライブラリ)を使います。引数が多いですがこちらを参照してください。imagecopyresized() という関数もありますが、こちらは CPU 負荷が小さい反面、画質は imagecopyresampled() に劣るみたいです。
最後に、imagejpeg() で JPG 画像として保存します。imagejpeg() は第三引数で JPEG の画質(圧縮具合)を選択できるのですが、100 だと PNG と重さが大して変わらず、メリットが小さいためここでは 85 としています。95 だと見分けがつかず、90 でも画質影響はほぼないといわれています。Google の Web 制作ガイドでは圧縮効果の高い 85 を推奨しています(参考)。(それ以下だと画質劣化が著しい。)
以上のようにして、色々な画像ファイルをリサイズして、JPEG として保存できました。
ちょっと宣伝
当サイトは地図を使った海外旅ブログまとめサイトとなっています。トップページに地図がありますが、地名を押すと画像が開き、画像を押すと関連記事一覧(クリック数順)が開きます。記事数が多い国ほど赤く、地名もその国で記事が多い都市の文字が大きくなるようにしています。ぜひ覗いてみてください。
当サイトで海外旅ブログを執筆することも可能です(もちろん無料です)! また既にブログをお持ちの方も、当サイトからリンクを貼ることができるようになっています。パントレ開発部までお気軽にお問い合わせください。
パントレ開発部