PHPで画像のキャッシュを作ってくれる画像圧縮クラス「PHP Image Cache」を使っています。
なかなかに便利ではありますが、難点もあります。一つは低画質化はできるものの画像サイズの縮小に対応していない(と思う)点、もう一つは画像をキャッシュするルーチンが走ると画面が表示されない点です。
とりあえず画像サイズを縮小できるように改変しようと思います。
PHP Image Cache
画像のファイルサイズを小さくしてくれるPHPクラス(gdが必要)です。ファイルを拾ってきて自分のサーバー上にキャッシュファイルを作ってくれます。PHP Image Cacheの基本的な使い方は前の記事に書いています。
PHP Image Cacheクラスは「フリー」なライセンスですが、Creative Commonsの何ライセンスなのか、ライセンステキストを見てもよくわかりません。README.mdにはCC BY(クリエイティブコモンズ:表示)と書かれています。
使われる場合はご自分でご確認ください。
書き換え箇所
元のコードから改変する関数を転載します。BY (by nielse63 https://github.com/nielse63)
/** * Fetch the image as a resource and save it into the cache directory. * * @source http://stackoverflow.com/questions/9839150/image-compression-in-php * @return If the image was successfully created or not */ private function fetch_image() { $image_size = getimagesize($this->image_src); $image_width = $image_size[0]; $image_height = $image_size[1]; $file_mime_as_ext = end(@explode('/', $this->file_mime_type)); $image_dest_func = 'imagecreate'; if ($this->gd_version >= 2) $image_dest_func = 'imagecreatetruecolor'; if (in_array($file_mime_as_ext, array('gif', 'jpeg', 'png'))) { $image_src_func = 'imagecreatefrom' . $this->file_extension; $image_create_func = 'image' . $this->file_extension; } else { $this->error('The image you supply must have a .gif, .jpg/.jpeg, or .png extension.'); return false; } $image_src = @call_user_func($image_src_func, $this->image_src); $image_dest = @call_user_func($image_dest_func, $image_width, $image_height); $this->increase_memory_limit(); if ($file_mime_as_ext === 'jpeg') { $background = imagecolorallocate($image_dest, 255, 255, 255); imagefill($image_dest, 0, 0, $background); } elseif (in_array($file_mime_as_ext, array('gif', 'png'))) { imagealphablending($image_src, false); imagesavealpha($image_src, true); imagealphablending($image_dest, false); imagesavealpha($image_dest, true); } imagecopy($image_dest, $image_src, 0, 0, 0, 0, $image_width, $image_height); switch ($file_mime_as_ext) { case 'jpeg': $created = imagejpeg($image_dest, $this->cached_filename, $this->quality->jpeg); break; case 'png': $created = imagepng($image_dest, $this->cached_filename, $this->quality->png); break; case 'gif': $created = imagegif($image_dest, $this->cached_filename); break; default: return false; break; } imagedestroy($image_src); imagedestroy($image_dest); $this->reset_memory_limit(); return $created; }
- 元画像の縦横を$image_height・$image_widthとして保存
- 画像ファイルをサーバー上に作成
@call_user_func($image_dest_func, $image_width, $image_height);
- 元画像の中身をサーバー上にコピー
imagecopy($image_dest, $image_src, 0, 0, 0, 0, $image_width, $image_height);
- JPEGなどで保存
imagejpeg($image_dest, $this->cached_filename, $this->quality->jpeg);
という手順でファイルをキャッシュさせています。
改変したコード
imagecopy関数をimagecopyresized関数に置き換えることで縮小しようと思います。もっと良い方法があったら教えて下さい・・・。縮小ではなく切り抜きをする場合はimagecopy関数のままで良いですが引数を変える必要がありそうです。
私の場合は、元画像のライセンスでサイズ変更以外の画像改変を認めていません。Amazonの商品画像なんかも画像の改変は認めていませんが、Amazonはローカルに保存するのもダメです。(なので、Amazonの場合は画像の改変というよりもCSSによる画像表示方法や画像の重ねあわせを禁止していると思います。)
imagecopy関数とimagecopyresized関数は、
bool imagecopy ( resource$dst_im
, resource$src_im
, int$dst_x
, int$dst_y
, int$src_x
, int$src_y
, int$src_w
, int$src_h
)
bool imagecopyresized ( resource$dst_image
, resource$src_image
, int$dst_x
, int$dst_y
,int$src_x
, int$src_y
, int$dst_w
, int$dst_h
, int$src_w
, int$src_h
)
と定義されていますので、追加するのは$dst_w、$dst_hです。目的の大きさをそのまま書き込んでしまうと、縦横比が変わってしまうのと小さい画像も拡大されてしまうので、呼び出し前になんとかします。
私は表示場所の都合上横サイズを優先したいので、そのようにコードを書き換えます。この画像圧縮クラス自体が拡張性を考えて作られていな気がするので、よくあるプラグインで出来るような、縦を優先するとか切り抜きにする、など柔軟に設定できる機能を追加したい場合、かなり面倒そうです。
/** * Fetch the image as a resource and save it into the cache directory. * * @source http://stackoverflow.com/questions/9839150/image-compression-in-php * @return If the image was successfully created or not */ private function fetch_image() { $image_size = getimagesize($this->image_src); $image_width = $image_size[0]; $image_height = $image_size[1]; $file_mime_as_ext = end(@explode('/', $this->file_mime_type)); $image_dest_func = 'imagecreate'; if ($this->gd_version >= 2) $image_dest_func = 'imagecreatetruecolor'; if (in_array($file_mime_as_ext, array('gif', 'jpeg', 'png'))) { $image_src_func = 'imagecreatefrom' . $this->file_extension; $image_create_func = 'image' . $this->file_extension; } else { $this->error('The image you supply must have a .gif, .jpg/.jpeg, or .png extension.'); return false; } $image_src = @call_user_func($image_src_func, $this->image_src); $dest_width = ($image_width > 325) ? (325) : $image_width; $dest_height = ($image_width != $dest_width) ? (int)($image_height*$dest_width/$image_width) : $image_height; $image_dest = @call_user_func($image_dest_func, $dest_width, $dest_height); $this->increase_memory_limit(); if ($file_mime_as_ext === 'jpeg') { $background = imagecolorallocate($image_dest, 255, 255, 255); imagefill($image_dest, 0, 0, $background); } elseif (in_array($file_mime_as_ext, array('gif', 'png'))) { imagealphablending($image_src, false); imagesavealpha($image_src, true); imagealphablending($image_dest, false); imagesavealpha($image_dest, true); } imagecopyresampled($image_dest, $image_src, 0, 0, 0, 0, $dest_width, $dest_height, $image_width, $image_height); switch ($file_mime_as_ext) { case 'jpeg': case 'png': $created = imagejpeg($image_dest, $this->cached_filename, $this->quality->jpeg); break; case 'gif': $created = imagegif($image_dest, $this->cached_filename); break; default: return false; break; } imagedestroy($image_src); imagedestroy($image_dest); $this->reset_memory_limit(); return $created; }
PNGだと巨大なままのファイルになる時があるので、JPEGに変換しておきます。画質の設定値をいくつにするのか悩ましいところですが、サーバー容量を圧迫し始めるまでは70~80の間にしておきます。
ついでに、imagecopyresizedではなくてimagecopyresampledを使うようにしています。何となく。
コメント