画像表示のときに指定サイズにリサイズする(画像の拡大縮小)

表示のときに、指定サイズに画像をリサイズ(拡大縮小)できます。

画像を登録のときではなく、表示のときにリサイズする方法です。

メリット
画像登録が画像形式・画像容量のチェックだけですむので、登録のプログラムがシンプルになります。
表示位置によって自由に画像サイズを変更できる。
登録時のプログラム言語によらず使用できる。
データベースなどで管理する画像が少なくなる。

デメリット
元画像も保存するので、保存容量が大きくなる。
画像表示にプログラムを通すので、表示が若干遅くなります。

http://127.0.0.1/image/[リサイズ後の横幅]/[リサイズ後の高さ]/[画像のURI]

http://127.0.0.1/image/[リサイズ後の横幅]/[リサイズ後の高さ]/[リサイズ方法]/[画像のURI]

のようにします。

http://127.0.0.1/image/100/100/hoge.gif

のようにすると 画像を縦横比を保ったまま100px×100pxに拡大縮小します。

http://127.0.0.1/image/100/100/3/hoge.gif

のように、拡大縮小するルールを変えることもできます。

使用例

階層を以下のようにすると

ドキュメントルート
└ image
 ├ .htaccess
 ├ imgresize.php
 ├ cache (キャッシュファイル保存ディレクトリ)
 ├ noimage.jpg (リサイズ画像がないときの画像)
 ├ sample.jpg (リサイズする画像)
 ├ ……

そのままの画像を表示する

http://127.0.0.1/image/sample.jpg
または
http://127.0.0.1/image/image/sample.jpg

200px×300pxのサイズにリサイズする

http://127.0.0.1/image/200/300/image/sample.jpg

リサイズの形式を変更する

http://127.0.0.1/image/200/300/2/image/sample.jpg

URLをシンプルにするにはimgresize.phpを編集します。

define('URI_PREFIX', "/image");

とすると次のようにできます。

http://127.0.0.1/image/200/300/sample.jpg

キャッシュ

$is_file_cache=true;

にすると、リサイズした画像をキャッシュさせることができます。
許容する横幅、高さを指定しておいたり、古いキャッシュを削除することで、キャッシュファイルの容量を抑えることできます。
この場合、画像登録時にリサイズする方法と比べると、保存容量は元画像の容量分だけの違いになります。

ソースコード

.htaccess

mod_rewriteが使える場合

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^.*$ imgresize.php [NC,L]
</IfModule>

mod_rewriteが使えない場合
(この場合、サーバにエラーログが残ります。)

ErrorDocument 404 /image/imgresize.php

imgresize.php

<?php

/* ================================
 * imgresize.php
 *
 * @create  2009-10-02
 * @author  pentan
 * @url     http://pentan.info/
 *
 * Copyright (c) 2009 pentan.info All Rights Reserved.
 * 著作権表示部分の変更削除は禁止です
 * ================================
 * 
 * .htaccess Example(1)
 * mod_rewrite is necessary
 * 
 *  <IfModule mod_rewrite.c>
 *    RewriteEngine On
 *    RewriteCond %{REQUEST_FILENAME} !-d
 *    RewriteCond %{REQUEST_FILENAME} !-f
 *  RewriteRule ^.*$ imgresize.php [NC,L]
 *  </IfModule>
 * 
 * 
 * .htaccess Example(2)
 * "/image/imgresize.php" is "imgresize.php" URI
 * 
 * ErrorDocument 404 /image/imgresize.php
 * 
 */

define('DS', DIRECTORY_SEPARATOR);

/* 初期設定ここから */

// 画像がないときに表示される画像
define('NOIMAGE', "/image/noimage.jpg");

// 画像がないときに表示される画像
// /imageのようにする
define('URI_PREFIX', "");

//キャッシュするかどうか
$is_file_cache=true;

//キャッシュをクーロンで消すかどうか
$is_use_cron=false;

//キャッシュを保存するディレクトリ
define('CACHE_DIR', dirname(__FILE__).DS."cache");

//キャッシュを消す時間(秒)
define('CACHE_LIFETIME', 24*60*60*30);

//キャッシュを消す時間帯
define('CACHE_CLEAN', 4);

//キャッシュ削除チェックファイル名
define('CACHE_CLEAN_CHECKFILE', "check");

//最大画像容量(単位:バイト)
define('MAX_FILESIZE', 2048000);

//生成画像の最大横幅
define('MAX_WIDTH', 0);

//生成画像の最大高さ
define('MAX_HEIGHT', 0);

//余白色
define('BG_R', 255);
define('BG_G', 255);
define('BG_B', 255);

//リサイズ方法
define('RESIZE_TYPE_FIX_FIT',     0);// 余白を残す 拡大縮小
define('RESIZE_TYPE_TRIM_FIT',    1);// 余白をトリミング 拡大縮小
define('RESIZE_TYPE_FIX_REDUCT',  2);// 余白を残す 縮小のみ
define('RESIZE_TYPE_TRIM_REDUCT', 3);// 余白をトリミング 縮小のみ

//指定がないときのリサイズ方法
define('DEFAULT_RESIZE_TYPE', RESIZE_TYPE_FIX_FIT);

//許容する横幅
//example
//$allow_width=array(200,400,600);
$allow_width=array();

//許容する高さ
//example
//$allow_height=array(200,400,600);
$allow_height=array();

//mod_rewriteを使用するかどうか
define('IS_MOD_REWRITE', true);

/* 初期設定ここまで */

$dir=preg_replace("/\/[^\/]*$/","/",$_SERVER['SCRIPT_NAME']);
$uri=preg_replace("/\?.*$/","",$_SERVER['REQUEST_URI']);
$root_path=preg_replace("/".preg_quote(str_replace("/",DS,preg_replace("/\/$/","",$dir)),"/")."$/","",dirname(__FILE__));

$resize_type=DEFAULT_RESIZE_TYPE;
if(preg_match("/^".preg_quote($dir,"/")."([0-9]+)\/([0-9]+)\/([0-9]+)\/(.+)$/",$uri,$match)){
  $resize_h=$match[1];
  $resize_w=$match[2];
  $resize_type=$match[3];
  $img_path="/".$match[4];
}elseif(preg_match("/^".preg_quote($dir,"/")."([0-9]+)\/([0-9]+)\/(.+)$/",$uri,$match)){
  $resize_h=$match[1];
  $resize_w=$match[2];
  $img_path="/".$match[3];
}elseif(preg_match("/^".preg_quote($dir,"/")."(.+)$/",$uri,$match)){
  $resize_h=0;
  $resize_w=0;
  $img_path="/".$match[1];
}else{
  $resize_h=0;
  $resize_w=0;
  $img_path=NOIMAGE;
}

if(RESIZE_TYPE_FIX_FIT!=$resize_type &&
    RESIZE_TYPE_TRIM_FIT!=$resize_type &&
    RESIZE_TYPE_FIX_REDUCT!=$resize_type &&
    RESIZE_TYPE_TRIM_REDUCT!=$resize_type){
  $resize_type=DEFAULT_RESIZE_TYPE;
}


if($resize_w>0 && is_array($allow_width) && count($allow_width) && false===array_search($resize_w,$allow_width)){
  rsort($allow_width,SORT_NUMERIC);
  foreach($allow_width as $value){
    if($resize_w > $value){
      break;
    }
  }
  $resize_w = $value;
}

if($resize_h>0 && is_array($allow_height) && count($allow_height) && false===array_search($resize_h,$allow_height)){
  rsort($allow_height,SORT_NUMERIC);
  foreach($allow_height as $value){
    if($resize_h > $value){
      break;
    }
  }
  $resize_h = $value;
}

if(!preg_match("/\.(jpg|jpeg|bmp|gif|png)$/i",$img_path)){
  $img_path=NOIMAGE;
}

$path=$root_path.URI_PREFIX.str_replace("/",DS,$img_path);
$cache_path=CACHE_DIR.DS.$resize_w.DS.$resize_h.DS.$resize_type."_".md5($img_path);

if(!is_file($path)){
  @unlink($cache_path);
  $img_path=NOIMAGE;
  $path=$root_path.URI_PREFIX.str_replace("/",DS,NOIMAGE);
  if(!is_file($path)){
    header("HTTP/1.0 404 Not Found");
    exit;
  }
}

if($resize_w>0 || $resize_h>0){
  if(MAX_FILESIZE>0 && filesize($path)>MAX_FILESIZE){
    @unlink($cache_path);
    $img_path=NOIMAGE;
    $path=$root_path.URI_PREFIX.str_replace("/",DS,NOIMAGE);
  }

  $cache_path=CACHE_DIR.DS.$resize_w.DS.$resize_h.DS.$resize_type."_".md5($img_path);

  if($is_file_cache){
    if(!is_dir(CACHE_DIR)){
      if(!@mkdir(CACHE_DIR,0777)){
        $is_file_cache=false;
      }
    }elseif(!is_writable(CACHE_DIR)){
      $is_file_cache=false;
    }

    if(is_file($cache_path)){
      if(filemtime($path)<filemtime($cache_path)){
        if(preg_match("/\.(jpg|jpeg)$/i",$img_path)){
          $img_contenttype="image/jpeg";
        }elseif(preg_match("/\.gif$/i",$img_path)){
          $img_contenttype="image/gif";
        }elseif(preg_match("/\.png$/i",$img_path)){
          $img_contenttype="image/png";
        }elseif(preg_match("/\.bmp$/i",$img_path)){
          $img_contenttype="image/bmp";
        }
        if(!IS_MOD_REWRITE){
          header("HTTP/1.1 200 OK");
        }
        header("Content-Type: " . $img_contenttype);
        readfile($cache_path);
        exit;
      }
    }
  }
}

$resize_w_cache=$resize_w;
$resize_h_cache=$resize_h;


list($img_width,$img_height,$type)=@getimagesize($path);

switch( $type ){
  case 1:
    $img_create_func ="imagecreate";
    $img_resize_func ="imagecopyresampled";
    $img_input_func ="imagecreatefromgif";
    $img_output_func="imagegif";
    $img_contenttype="image/gif";
    break;
  case 2:
    $img_create_func ="imagecreatetruecolor";
    $img_resize_func ="imagecopyresampled";
    $img_input_func ="imagecreatefromjpeg";
    $img_output_func="imagejpeg";
    $img_contenttype="image/jpeg";
    break;
  case 3:
    $img_create_func ="imagecreatetruecolor";
    $img_resize_func ="imagecopyresampled";
    $img_input_func ="imagecreatefrompng";
    $img_output_func="imagepng";
    $img_contenttype="image/png";
    break;
  default:
    if($type==6){
      $img_contenttype="image/bmp";
    }elseif(preg_match("/\.(jpg|jpeg)$/i",$img_path)){
      $img_contenttype="image/jpeg";
    }elseif(preg_match("/\.gif$/i",$img_path)){
      $img_contenttype="image/gif";
    }elseif(preg_match("/\.png$/i",$img_path)){
      $img_contenttype="image/png";
    }elseif(preg_match("/\.bmp$/i",$img_path)){
      $img_contenttype="image/bmp";
    }
    if(!IS_MOD_REWRITE){
      header("HTTP/1.1 200 OK");
    }
    header("Content-Type: " . $img_contenttype);
    readfile($path);
    exit;
    break;
}

if(($resize_type==RESIZE_TYPE_TRIM_REDUCT && $resize_w>$img_width && $resize_h>$img_height) ||
  ($resize_w==0 && $resize_h==0)){
  if(!IS_MOD_REWRITE){
    header("HTTP/1.1 200 OK");
  }
  header("Content-Type: " . $img_contenttype);
  readfile($path);
  exit;
}

if(!($src=@$img_input_func($path))){
  if(!IS_MOD_REWRITE){
    header("HTTP/1.1 200 OK");
  }
  header("Content-Type: " . $img_contenttype);
  readfile($path);
  exit;
}

while(true){
  if(MAX_WIDTH > 0 && $resize_w>MAX_WIDTH){
    $resize_w=MAX_WIDTH;
  }

  if(MAX_HEIGHT > 0 && $resize_h>MAX_HEIGHT){
    $resize_h=MAX_HEIGHT;
  }
  if($resize_w<=0){
    $resize_w=intval($img_width*$resize_h/$img_height + 0.5);
    $resize_w0=$resize_w;
    $resize_h0=$resize_h;
  }elseif($resize_h<=0){
    $resize_h=intval($img_height*$resize_w/$img_width + 0.5);
    $resize_w0=$resize_w;
    $resize_h0=$resize_h;
  }else{
    if($resize_w/$resize_h==$img_width/$img_height){
      $resize_w0=$resize_w;
      $resize_h0=$resize_h;
    }elseif($resize_w/$resize_h>$img_width/$img_height){
      $resize_h0=$resize_h;
      $resize_w0=intval($img_width*$resize_h/$img_height + 0.5);
    }else{
      $resize_w0=$resize_w;
      $resize_h0=intval($img_height*$resize_w/$img_width + 0.5);
    }
  }

  if($resize_type==RESIZE_TYPE_FIX_REDUCT || $resize_type==RESIZE_TYPE_TRIM_REDUCT){
    if($img_width<$resize_w0 || $img_height<$resize_h0){
      $resize_w0=$img_width;
      $resize_h0=$img_height;
    }
  }

  if((MAX_WIDTH > 0 && $resize_w>MAX_WIDTH) || (MAX_HEIGHT > 0 && $resize_h>MAX_HEIGHT)){
    continue;
  }
  break;
}


if($resize_type==RESIZE_TYPE_TRIM_FIT || $resize_type==RESIZE_TYPE_TRIM_REDUCT){
  $resize_w=$resize_w0;
  $resize_h=$resize_h0;
}

$dst=@$img_create_func($resize_w,$resize_h);
imagefill($dst,0,0,imagecolorallocate($dst,BG_R,BG_G,BG_B));
$img_resize_func($dst,$src,($resize_w-$resize_w0)/2,($resize_h-$resize_h0)/2,0,0,$resize_w0,$resize_h0,$img_width,$img_height);

if(!IS_MOD_REWRITE){
  header("HTTP/1.1 200 OK");
}
header("Content-Type: " . $img_contenttype);
$img_output_func($dst);

if($is_file_cache){
  if(!is_dir(CACHE_DIR.DS.$resize_w_cache)){
    if(!@mkdir(CACHE_DIR.DS.$resize_w_cache,0777)){
      exit;
    }
  }
  if(!is_dir(CACHE_DIR.DS.$resize_w_cache.DS.$resize_h_cache)){
    if(!@mkdir(CACHE_DIR.DS.$resize_w_cache.DS.$resize_h_cache,0777)){
      exit;
    }
  }
  $img_output_func($dst,$cache_path);
  chmod($cache_path,0666);
}

imagedestroy($src);
imagedestroy($dst);

if($is_file_cache && !$is_use_cron){
  clean_cache(CACHE_DIR,CACHE_LIFETIME,CACHE_CLEAN);
}

function clean_cache($dir,$lifetime=0,$starth=99,$endh=99,$is_top=true){
  $check_file=$dir.DIRECTORY_SEPARATOR.CACHE_CLEAN_CHECKFILE;
  if($endh>23){
    $endh=$starth;
  }

  if($starth>23 || $endh>23){

  }elseif($starth>$endh){

  }elseif(date("G")<=$starth && $endh<=date("G")){
    if($is_top){
      if(is_file($check_file) && date("Ymd")*100+$starth<date("YmdH",filemtime($check_file))){
        return true;
      }
      @touch($check_file);
    }
  }else{
    return true;
  }

  if (!is_dir($dir)) {
    return false;
  }

  if (!($dh = @opendir($dir))) {
    return false;
  }

  while ($file = readdir($dh)) {
    if ($file == "." || $file == ".." || preg_match("/^\..+/",$file) || $file==CACHE_CLEAN_CHECKFILE) continue;
    $file0=$dir.DIRECTORY_SEPARATOR.$file;
    if(is_dir($file0)){
      clean_cache($file0,$lifetime,$starth,$endh,false);
    }
    if(!is_file($file0)){
      continue;
    }

    if(filemtime($file0)<time()-$lifetime){
      @unlink($file0);
    }
  }
  closedir($dh);
}

関連記事

スポンサーリンク

utf8_general_ci と utf8_unicode_ci の違い

ホームページ製作・web系アプリ系の製作案件募集中です。

上に戻る