どんな幅の画像を入れられても縦横比を保ちながらサムネイル画像の幅に最適な画像を作る。この記事はどのようにサムネイル画像を作るかという考え方を示したもので、画像の質は保証しません。画像の質向上は別途行っていきます。10月2日記事

目次





正方形のサムネイル画像

instagramやphotohitoなど正方形のサムネイルにしている場合がある。その場合、端を切り取り、中央に寄せた正方形の写真にしていることが多い。 そんな中で、正方形のサムネイル画像を別途出力するコードを書いていく。

設計

  1. 縦横両方とも150px画像より小さい場合は、拡大せず、中央に寄せる。
  2. 縦か横どちらかが150px未満の場合、長い方を基準に縮小率を決定して、短い方も縮小率で縮小し、中央に寄せる
  3. 縦か横両方とも150px以上の場合は、短い方を基準に縮小率を決定して、長い方の(上下あるいは左右)をトリミングして、中央に寄せる。 また、プログラムのディレクトリの中にtmpというフォルダを設け、そこに元画像と出力させる画像を格納しておく。元画像の方は下においてあるのでDLしたければぜひどうぞ。

    1のイメージ(中央に寄せる)
    2のイメージ(縦フィット)
    2のイメージ(横フィット)
    3のイメージ(横フィット)
    3のイメージ(縦フィット)

PHPの画像処理ライブラリであるGDライブラリ使ってみたが汚い。

コード

<?php
//サムネイルの画像サイズの定義
$thum_width = 150;
$thum_height = 150;

//サムネイルのファイル名
date_default_timezone_set('Asia/Tokyo');
$origintime = date("YmdHis").str_replace(".","",microtime(true));

//コピー元の画像オープン
$file = "./tmp/800_500.jpg";
$src_image = imagecreatefromjpeg($file);

//縦と横の長さ取得
list($width ,$height) = getimagesize($file);

//コピー先の画像領域を作成
$copy_image = imagecreatetruecolor($thum_width,$thum_height);
$bgcolor = imagecolorallocate($copy_image , 240, 240 ,240);//150pxに満たない場合背景はグレー

if($width < $thum_width && $height < $thum_height ){//縦横の画像が両方とも150pxに満たない場合
//縦と横の基準点を計算する。
	$refpoint_width = ($thum_width - $width) / 2;
	$refpoint_height = ($thum_height - $height) / 2;

	imagefilledrectangle($copy_image,0,0,$thum_width,$thum_height,$bgcolor);	
	imagecopy($copy_image, $src_image, $refpoint_width, $refpoint_height, 0 , 0, $width, $height);

}elseif($width < $thum_width XOR $height < $thum_height){//どちらかが150px未満の場合。排他的論理和をあえて使用。かつの場合、最初のif文で処理されるから、ORや||でもいいと思うけどね。
	if($width < $thum_width){//横が150px未満で、縦が150px以上の場合
		$percent = $thum_height / $height;//縮小率計算
		$refpoint_width = ($thum_width - $width * $percent) / 2;//横の基準点作成
		
		imagefilledrectangle($copy_image,0,0,$thum_width,$thum_height,$bgcolor);
		$thum_width = $width * $percent;
		$thum_height = $height * $percent;
		
		
		imagecopyresized($copy_image,$src_image,$refpoint_width,0,0,0,$thum_width,$thum_height,$width,$height);
		//出力先、ソース元、出力先の基準位置X、出力先の基準位置Y、ソース元基準位置X、ソース元基準位置Y

	}else{//縦が150px未満で、横が150px以上の場合。
		$percent = $thum_width / $width;//縮小率計算
		$refpoint_height = ($thum_height - $height * $percent) / 2;//縦の基準点作成

		
		imagefilledrectangle($copy_image,0,0,$thum_width,$thum_height,$bgcolor);		
		$thum_width = $width * $percent;
		$thum_height = $height * $percent;
				
		imagecopyresized($copy_image,$src_image,0,$refpoint_height,0,0,$thum_width,$thum_height,$width,$height);
		
	}

}else{//両方とも150px以上の場合 //150pxの正方形はこっちを採用する
	if($width < $height){	//短い方を基準に圧縮率を計算。横を基準に圧縮する。
		$percent = $thum_width / $width;

		//トリミングする基準位置作成 heightの基準位置決定
		$refpoint_height = ($height - ($thum_height / $percent)) / 2;
		
		//イメージコピー
		imagecopyresized($copy_image,$src_image,0,0,0,$refpoint_height,$thum_width,$thum_height,$width,$thum_height / $percent);

				
	}else{	//短い方を基準に圧縮率を計算。縦を順に圧縮する
		$percent = $thum_height / $height;

		//トリミングする基準位置作成 heightの基準位置決定
		$refpoint_width = ($width - ($thum_width / $percent)) / 2;

		//イメージリサイズ
		imagecopyresized($copy_image,$src_image,0,0,$refpoint_width,0,$thum_width,$thum_height,$thum_width/$percent,$height);


	}	
}
//最後に出力

header('Content-Type: image/jpeg');
imagejpeg($copy_image);//ブラウザ確認用コメントアウトしてもいい
imagejpeg($copy_image,'./tmp/thum_'.$origintime.'.jpg');//サムネイル画像ファイル出力

imagedestroy($copy_image);
imagedestroy($src_image);

?>

まとめ

画像が汚すぎなので、GDライブラリについて調べる。

入り口で痛い目にあうと、これ以上続けようとはなかなか思わないものですが、もうすこし踏ん張って、GDの関数を探してみると、imagecreatetruecolor()とimagecopyresampled()に出会います。これらはそれぞれimagecreate()とimagecopyresized()と似たような処理をする関数ですが、imagecreatetruecolor()とimagecopyresampled()を使うだけで、GDによる画像縮小の質が格段によくなるのです。

http://suin.asia/2009/02/08/gd-you-can-do-it.htmlから引用
imagecreatetruecolor()とimagecopyresampled()を使ってみたのですが、あまり変わらないみたいです。 上記のコードのimagecopyresizedをimagecopyresampledに置換してすぐそれが実現できるのですが、あまり変わりませんでした。

以上