<?php
/* ========================================================================
 - [rkt_imagemagick.php]
 - 内容:ImageMagick操作クラス
 - 作成:高橋 裕志郎
 - ライセンス:
 -      This source file is subject to version 3.0 of the PHP license,
 -      that is available at http://www.php.net/license/3_0.txt
 -      If you did not receive a copy of the PHP license and are unable 
 -      to obtain it through the world-wide-web, please send a note to 
 -      license@php.net so we can mail you a copy immediately.  
 - 問い合わせ先:
 -      yujiro@rakuto.net
 -      http://rakuto.net/
 -      Copyright (C) 2003-2006 `rakuto.net'. All Rights Reserved.
 - 注意事項:
 -      ImageMagickを使用しています。以下などから取り寄せてください。
 -      http://www.imagemagick.org/script/download.php
 - 更新履歴:
 -      [2006/06/04] RKT_imagemagick::setBinary()とRKT_imagemagick::getInfo()を追加
 -      [2006/06/01] 作成
 - ======================================================================== */

if (!defined('IMAGEMAGICK_PATH')){
    
define('IMAGEMAGICK_PATH','/usr/local/bin/');
}
if (!
defined('ERROR_LOG_FILE')){
    
define('ERROR_LOG_FILE','error.log');
}

/**
 * ImageMagick操作クラス
 *
 * @author 高橋 裕志郎 <yujiro@rakuto.net>
 * @package RKT_imgManipulation
 * @access public
 * @version 1.3.06.04
 */
class RKT_imagemagick
{
    
/**
     * 画像ファイル名
     * @var string
     */
    
var $filename '';

    
/**
     * 画像情報
     * @var array
     */
    
var $infos = array();

    
/**
     * 画像のバイナリ情報
     * @var binary
     */
    
var $buffer null;

    
/**
     * 描画の色
     * @var string
     */
    
var $fill_color 'white';

    
/**
     * 線の色
     * @var string
     */
    
var $stroke_color 'black';

    
/**
     * フォントの大きさ
     * @var integer
     */
    
var $pointsize 10;

    
/**
     * 線の太さ
     * @var integer
     */
    
var $stroke_width 1;

    
/**
     * フォントのファイル名
     * @var strong
     */
    
var $font '';

    
/**
     * コンストラクタ
     *
     * @access public
     * @param string $source
     * @return void
     */
    
function RKT_imagemagick($filename=null)
    {
        if (empty(
$filename)){
            return ;
        }

        
$this->filename $filename;
        
$this->readimage($this->filename);
    }

    
/**
     * 画像情報をバッファに格納
     *
     * @access private
     * @return boolean
     */
    
function readimage($filename)
    {
        
$this->filename $filename;
        if (!
file_exists ($this->filename)){
            return 
false;
        }
        
$this->set_info();

        
/* ファイルの中身を取得 */
        
$handle fopen($this->filename'rb');
        if (!
is_resource($handle)) {
            return 
false;
        }
        
$this->buffer fread($handlefilesize($this->filename));
        
fclose($handle);
        
        return 
true;
    }

    
/**
     * コマンドの直接実行
     *
     * @access public
     * @param string $command コマンド名
     * @param string $param パラメータ
     * @return boolean
     */
    
function direct($command$param)
    {
        
$command '"'.IMAGEMAGICK_PATH.$command.'" '.$param.' '.$this->filename;
        
ob_start();
        
passthru($command);
        
$result ob_get_contents();
        
ob_end_clean();

        return 
$result;
    }

    
/**
     * コマンドの実行
     *
     * @access public
     * @param string $command コマンド名
     * @param string $param パラメータ
     * @return boolean
     */
    
function command($command$param)
    {
        
$command '"'.IMAGEMAGICK_PATH.$command.'" '.$param;
        
$inout substr_count($param':-'); 

        
$descriptorspec = array(
            
=> array('pipe''r'),
            
=> array('pipe''w'),
            
=> array('file'ERROR_LOG_FILE'a')
        );
        
$pipes = array();
        
$process proc_open($command$descriptorspec$pipes);
        if (!
is_resource($process)) {
            return 
false;
        }
        if (
$inout == 2){
            
fwrite($pipes[0], $this->buffer);
            
fclose($pipes[0]);
        }

        
ob_start();
        
fpassthru($pipes[1]);
        
$this->buffer ob_get_contents();
        
ob_end_clean();

        
fclose($pipes[1]);
        
proc_close($process);

        return 
true;
    }

    
/**
     * identifyの実行
     *
     * @access public
     * @param string $param パラメータ
     * @return boolean
     */
    
function identify($param)
    {
        
$command '"'.IMAGEMAGICK_PATH.'identify" '.$param;
        
$descriptorspec = array(
            
=> array('pipe''r'),
            
=> array('pipe''w'),
            
=> array('file'ERROR_LOG_FILE'a')
        );
        
$pipes = array();
        
$process proc_open($command$descriptorspec$pipes);
        if (!
is_resource($process)) {
            return 
false;
        }
        
$res fwrite($pipes[0], $this->buffer);
        
fclose($pipes[0]);

        
$result fread($pipes[1], 8192);

        
fclose($pipes[1]);
        
proc_close($process);

        return 
$result;
    }

    
/**
     * 画像情報の取得
     *
     * @access private
     * @return void
     */
    
function set_info()
    {
        
$format = array(
            
'so'=>  '"%m:%f:%w:%h;"',
            
'dll'=> '%m:%f:%w:%h;',
        );
        
$param  '-format ';
        
$param .= $format[PHP_SHLIB_SUFFIX].' ';
        
        if (empty(
$this->infos['format'])){
            
$result $this->direct('identify'$param);
        } else {
            
$param .= $this->infos['format'].':-';
            
$result $this->identify($param);
        }
        
$row explode(';'$result);

        if (empty(
$row[0])){
            
$this->info = array('error'=>1);
            return ;
        }
        
$info explode(':'$row[0]);

        
$this->infos = array(
            
'type'=>   $info[0],
            
'format'=> strtolower($info[0]),
            
'name'=>   $info[1],
            
'width'=>  $info[2],
            
'height'=> $info[3],
        );
    }

    
/*_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
          basic
      _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/*/

    /**
     * 対象画像の出力
     *
     * @access public
     * @return void
     */
    
function output()
    {
        echo 
$this->buffer;
    }

    
/**
     * 対象画像の保存
     *
     * @access public
     * @param string $filename 画像のファイル名
     * @return boolean
     */
    
function save($filename)
    {
        
/* ファイルの中身を取得 */
        
$handle fopen($filename'wb');
        if (!
is_resource($handle)) {
            return 
false;
        }
        
$result fwrite($handle$this->buffer);
        
fclose($handle);
        
        return 
$result;
    }

    
/**
     * 画像情報の取得
     *
     * @access public
     * @return array 画像情報
     */
    
function getInfo()
    {
        
$this->set_info();

        return 
$this->infos;
    }

    
/**
     * 対象画像フォーマットの変換
     *
     * @access public
     * @param string $format 変換する画像フォーマット
     * @return boolean
     */
    
function convert($format)
    {
        
$format = empty($format)?$this->infos['format']:$format;        
        
$command 'convert';
        
$param  $this->infos['format'].':- '.$format.':-';

        
$this->infos['type'] = $format;
        
$this->infos['format'] = $format;
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像フォーマットの変換
     *
     * @access public
     * @param integer $width 画像の幅
     * @param integer $height 画像の高さ
     * @param string $color 背景色
     * @param string $format フォーマット
     * @return boolean
     */
    
function create($width$height$color='white'$format='gif')
    {
        
$command 'convert';

        
$param  '-size ';
        
$param .= $width.'x'.$height.' ';
        
$param .= 'xc:';
        
$param .= $color.' ';
        
$param .= $format.':-';

        
$this->infos = array(
            
'type'=>   $format,
            
'format'=> strtolower($format),
            
'name'=>   'none.'.strtolower($format),
            
'width'=>  $width,
            
'height'=> $height,
        );
        
        return 
$this->command($command$param);
    }

    
/**
     * 画像バイナリデータの設定
     *
     * @access public
     * @param binary $binary 画像バイナリデータ
     * @param string $format フォーマット
     * @return boolean
     */
    
function setBinary($binary$format)
    {
        
$this->infos = array(
            
'type'=>   $format,
            
'format'=> strtolower($format),
            
'name'=>   'none.'.strtolower($format),
            
'width'=>  0,
            
'height'=> 0,
        );

        
$this->buffer $binary;
        
$this->set_info();

        return 
true;
    }

    
/*_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
          move px
      _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/*/

    /**
     * アニメーション画像
     *
     * @access public
     * @param mixed $filename ファイル名
     * @param integer $delay 切替速度
     * @param integer $loop 繰り返し回数(ms)
     * @return boolean
     */
    
function animated($filename$delay=100$loop=0)
    {
        if (
is_array($filename)){
            
$filename implode(' '$filename); 
        }
        
$command 'convert';

        
$param  '-delay ';
        
$param .= $delay.' ';
        
$param .= '-loop ';
        
$param .= $loop.' ';

        
$param .= $filename.' ';
        
$param .= 'gif:-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像を切り取る
     *
     * @access public
     * @param integer $width 画像の幅
     * @param integer $height 画像の高さ
     * @param integer $x x軸の移動ピクセル
     * @param integer $y y軸の移動ピクセル
     * @return boolean
     */
    
function crop($width$height$x=0$y=0)
    {        
        
$command 'convert';

        
$param  '-crop ';
        
$param .= $width.'x'.$height;
        
$param .= '+'.$x.'+'.$y.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';

        
$this->infos['width']  = $width;
        
$this->infos['height'] = $height;
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の中央引き寄せ
     *
     * @access public
     * @param integer $factor 要素
     * @return boolean
     */
    
function implode($factor)
    {        
        
$command 'convert';

        
$param  '-implode ';
        
$param .= $factor.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像のリサイズ
     *
     * @access public
     * @param integer $width 画像の幅
     * @param integer $height 画像の高さ
     * @param boolean $exactly 指定サイズを厳守
     * @return boolean
     */
    
function resize($width$height$exactly=false)
    {
        
$exactly = empty($exactly)?'':'!';
        
        
$command 'convert';

        
$param  '-resize ';
        
$param .= $width.'x'.$height.$exactly.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';

        
$this->infos['width']  = $width;
        
$this->infos['height'] = $height;
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像を巻き込み
     *
     * @access public
     * @param integer $x x軸の移動ピクセル
     * @param integer $y y軸の移動ピクセル
     * @return boolean
     */
    
function roll($x$y)
    {        
        
$command 'convert';

        
$param  '-roll ';
        
$param .= '+'.$x.'+'.$y.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の回転
     *
     * @access public
     * @param integer $angle 回転角度
     * @return boolean
     */
    
function rotate($angle)
    {        
        
$command 'convert';

        
$param  '-rotate ';
        
$param .= $angle.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の傾き
     *
     * @access public
     * @param integer $x x軸の角度
     * @param integer $y y軸の角度
     * @return boolean
     */
    
function shear($x$y)
    {        
        
$command 'convert';

        
$param  '-shear ';
        
$param .= $x.'x'.$y.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の渦巻き表示
     *
     * @access public
     * @param integer $angle 回転角度
     * @return boolean
     */
    
function swirl($angle)
    {        
        
$command 'convert';

        
$param  '-swirl ';
        
$param .= $angle.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の上下反転
     *
     * @access public
     * @return boolean
     */
    
function flip()
    {        
        
$command 'convert';

        
$param  '-flip ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の左右反転
     *
     * @access public
     * @return boolean
     */
    
function flop()
    {
        
$command 'convert';

        
$param  '-flop ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の波加工
     *
     * @access public
     * @param integer $height 波の高さ
     * @param integer $width 波の幅
     * @return boolean
     */
    
function wave($height$width)
    {
        
$command 'convert';

        
$param  '-wave ';
        
$param .= $height.'x'.$width.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の装飾模様
     *
     * @access public
     * @param integer $radius 範囲
     * @param integer $x x軸のトリムピクセル
     * @param integer $y y軸のトリムピクセル
     * @param integer $sigma シグマ
     * @return boolean
     */
    
function vignette($radius$x=0$y=0$sigma=10)
    {
        
$sigma = empty($sigma)?'1':$sigma;

        
$command 'convert';

        
$param  '-vignette ';
        
$param .= $radius.'x'.$sigma.'+'.$x.'+'.$y.'% ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/*_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
          effects
      _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/*/

    /**
     * 対象画像をぼかす
     *
     * @access public
     * @param integer $radius
     * @param integer $sigma
     * @return boolean
     */
    
function blur($radius$sigma=null)
    {
        
$sigma = empty($sigma)?'':'x'.$sigma;
        
$command 'convert';

        
$param  '-blur ';
        
$param .= $radius.$sigma.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像に枠線をつける
     *
     * @access public
     * @param string $color
     * @param integer $width
     * @return boolean
     */
    
function border($color$width=null)
    {
        
$width = empty($width)?'5':$width;
        
$command 'convert';

        
$param  '-border ';
        
$param .= $width.'x'.$width.' ';
        
$param .= '-bordercolor ';
        
$param .= $color.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の木炭加工
     *
     * @access public
     * @param integer $factor 要素
     * @return boolean
     */
    
function charcoal($factor)
    {
        
$command 'convert';

        
$param  '-charcoal ';
        
$param .= $factor.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像のコントラスト調整
     *
     * @access public
     * @param integer $black 黒バランス(%)
     * @param integer $white 白バランス(%)
     * @return boolean
     */
    
function contrast($black$white=null)
    {
        
$white = empty($white)?'':'x'.$white;
        
        
$command 'convert';

        
$param  '-contrast-stretch ';
        
$param .= $black.$white.'% ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の斑点を減少
     *
     * @access public
     * @return boolean
     */
    
function despeckle()
    {
        
$command 'convert';

        
$param  '-despeckle ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像にエッジを効かす
     *
     * @access public
     * @param integer $radius 範囲
     * @return boolean
     */
    
function edge($radius)
    {
        
$command 'convert';

        
$param  '-edge ';
        
$param .= $radius.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像のエンボス加工
     *
     * @access public
     * @param integer $radius 範囲
     * @return boolean
     */
    
function emboss($radius)
    {
        
$command 'convert';

        
$param  '-emboss ';
        
$param .= $radius.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像のエンハンス加工
     *
     * @access public
     * @return boolean
     */
    
function enhance()
    {
        
$command 'convert';

        
$param  '-enhance ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像の均一化
     *
     * @access public
     * @return boolean
     */
    
function equalize()
    {
        
$command 'convert';

        
$param  '-equalize ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像のフレーム
     *
     * @access public
     * @param integer $color 色
     * @param integer $width 枠幅
     * @param integer $outer 外側
     * @param integer $inner 内側
     * @return boolean
     */
    
function frame($color$width=18$outer=4$inner=4)
    {
        
$command 'convert';

        
$param  '-frame ';
        
$param .= $width.'x'.$width;
        
$param .= '+'.$outer.'+'.$inner.' ';
        
$param .= '-mattecolor ';
        
$param .= $color.' ';

        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像のガウス加工
     *
     * @access public
     * @param integer $radius 範囲
     * @param integer $sigma シグマ
     * @return boolean
     */
    
function gaussian($radius$sigma=null)
    {
        
$sigma = empty($sigma)?'':'x'.$sigma;
        
        
$command 'convert';

        
$param  '-gaussian ';
        
$param .= $radius.$sigma.' ';
        
$param .= $this->infos['format'].':- '.$this->infos['format'].':-';
        
        return 
$this->command($command$param);
    }

    
/**
     * 対象画像のメディアン加工
     *
     * @access public
     * @param integer $radius 範囲
     * @return boolean
     */
    
function median($rad