设为首页 | 加入收藏
PHP
心如止水
网络编程
育儿心经
成长经历
心如止水 首页 > 心如止水 > PHP

php图片处理类,GD库、ImageMagick

所属类别:PHP 发布者: 心如止水 来源:喜气妍妍 发布时间:2015-03-04 15:26:47

图片处理是每个网站后台都经常要用的功能,但是php自身的图片处理类功能都很单一,无法满足复杂的需求,且调用有些繁琐(参数很多)。固本人经过多次改版,辛苦的建立了自己的类库。其实很多人写的图片都是出入一个图片源路径和一个目标路径,及一些必要的参数就可以处理好图片。我前期阶段也是如此。后来发现当我有些特殊的要求时就无法满足我的需求,比如说我是要处理图片,可是我不想保存为文件格式,我想输出到浏览器或保存进数据库等。所以我再三思量,决定把图片的处理拆分成三个阶段来完成,第一阶段:读取图片,判断是否支持此类图片的处理等;第二阶段:处理图片(缩放图片、翻转图片等);第三阶段:保存或输出图片。

好了,下面讲下我是如何来设置我的图片处理类的。为满足不同用户的需求,我分别扩展了GD库和ImageMagick。使用来一个抽象类Lib_Image_Abstract作为父类,子类Lib_Image和子类Lib_Imagick分别继承抽象类。父类主要提供一些公共的属性和实现一些公共的方法,以及定义公共的接口;子类实现接口。子类Lib_Image主要是调用GD库来处理图片,而子类Lib_Imagick主要调用ImageMagick来处理图片(不过需要安装ImageMagick,具体的安装流程这里就不多说),因为GD库无法处理gif动画图片,所以本人直接舍弃掉了(如果哪位高人知道gd处理动画图片,也请你告知我一声,共同学习吗)。

具体实现就是我刚开始说的那三步了。代码的解释我就不多说了,我的注释写得够详细了,如何调用请看页尾。因本类是本人花了很多时间写出来的劳动成果,如需转载请注明出处:http://maimengmei.com/blog.php?id=78,谢谢配合!

直接上代码,abstract class Lib_Image_Abstract 如下:

 


/**
 * 图片处理抽象类
 * (抽象类中的方法:如果是抽象方法的话,可以不用实现;如果子类继承了抽象类,那么一定要实现抽象方法)
 * 尽量使抽象方法中的参数及参数值和继承其抽象类的实现方法一致
 * @author bear
 * @copyright xiqiyanyan.com
 * @version 2.0.0
 * @created 2012-12-11 20:40
 */
abstract class Lib_Image_Abstract
{
	/**
	 * 位置:左上(西北)
	 * @var string
	 */
	const PLACE_NORTHWEST = 'northwest';
	
	/**
	 * 位置:上边居中(北)
	 * @var string
	 */
	const PLACE_NORTH = 'north';
	
	/**
	 * 位置:右上(东北)
	 * @var string
	 */
	const PLACE_NORTHEAST = 'northeast';
	
	/**
	 * 位置:左边(西)
	 * @var string
	 */
	const PLACE_WEST = 'west';
	
	/**
	 * 位置:居中(最中间)
	 * @var string
	 */
	const PLACE_CENTER = 'center';
	
	/**
	 * 位置:右边(东)
	 * @var string
	 */
	const PLACE_EAST = 'east';
	
	/**
	 * 位置:左下(西南)
	 * @var string
	 */
	const PLACE_SOUTHWEST = 'southwest';
	
	/**
	 * 位置:下边居中(南)
	 * @var string
	 */
	const PLACE_SOUTH = 'south';
	
	/**
	 * 位置:右下(东南)
	 * @var string
	 */
	const PLACE_SOUTHEAST = 'southeast';
    // 其实Imagick也有打水印的位置,见imagick::GRAVITY_NORTHWEST

	const TYPE_GIF = 'gif';
	const TYPE_JPG = 'jpg';
	const TYPE_JPEG = 'jpeg';
	const TYPE_PNG = 'png';
	const TYPE_WBMP = 'wbmp';
	const TYPE_BMP = 'bmp';
	
    /**
     * 水平翻转
     * @var string
     */
    const ROTATE_H = 'H';
    
    /**
     * 垂直翻转
     * @var string
     */
    const ROTATE_V = 'V';
	
	/**
	 * 错误信息
	 * @var string
	 */
	protected $_error = null;
	
	/**
	 * 图像资源
	 * @var Imagick | source | object (Imagick)
	 */
	protected $_im = null;
	
	/**
	 * 源图片路径
	 * @var string
	 */
	protected $_sourcePath = null;
	
	/**
	 * 目标图片路径
	 * @var string
	 */
	protected $_targetPath = null;
	
	/**
	 * 源图片类型,值如: gif,jpg,jpeg,png (不包括点在内)
	 * @var string
	 */
	protected $_sourceType = null;
	
	/**
	 * 目标文件的文件名
	 * @var string
	 */
	protected $_targetFilename = null;
	
	/**
	 * 源图片的宽
	 * @var integer
	 */
	protected $_sourceWidth;
	
	/**
	 * 源图片的高
	 * @var integer
	 */
	protected $_sourceHeight;
	
    /**
     * jpg图片的质量
     * @var integer
     */
    protected $_quality = 88;

    /**
     * 生成随机文件名
     * @return string
     */
    static public function getFileName($long = 6) { // 抽象类中也允许有静态方法
        $abcString = '';
        $numString = '';
        $ABCString = '';
        for ($i=0; $i<$long; $i++) {
            $abcASCII = mt_rand(97, 122); // mt_rand() 生成随机数
            $abcString .= chr($abcASCII); // chr($ascii): ASCII码 转字符串,如果是字符串转ASCII码用:ord($char); ASCII码对应值: A-Z:65-90; a-z:97-122; 0-9:48-57
            $numASCII = mt_rand(48, 57);
            $numString .= chr($numASCII);
            $ABCASCII = mt_rand(65, 90);
            $ABCString .= chr($ABCASCII);
        } // print_r(microtime(true)); // 1320820176.375 // time() 秒数
        return $abcString . $numString . $ABCString . date('YmdHis');
    }
    
    /**
     * 删除文件
     * @param string $path
     */
    static public function deleteFile($path) {
        if (file_exists($path)) {
            @unlink($path);
        }
    }
    
	/**
	 * @param string 源图片路径(需要处理的图片的绝对路径) origin
	 */
	public function __construct($sourcePath = null) {
		if ($sourcePath !== null) {
			$this->read($sourcePath);
		}
	}
	
	/**
	 * 设置图像资源
	 * @param object $im
	 */
	public function setIm($im) {
		$this->_im = $im;
		// TODO 设置源图片的宽高等信息
	}
	
	/**
	 * 获取图像资源
	 * @return Imagick | resource
	 */
	public function getIm() {
		return $this->_im;
	}
	
	/**
	 * 设置错误信息
	 * @param string $error
	 */
	public function setError($error) {
		$this->_error = $error;
	}
	
	/**
	 * 获取错误信息
	 * @return string
	 */
	public function getError() {
		return $this->_error;
	}
	
	/**
	 * 设置源图片路径
	 * @param string $sourcePath
	 */
	public function setSourcePath($sourcePath) {
		$this->read($sourcePath);
	}
	
	/**
	 * 设置目标图片路径(包括文件名)
	 * @param string $targetPath
	 */
	public function setTargetPath($targetPath) {
		$this->_targetPath = str_replace('\\', '/', $targetPath);
	}
	
	/**
	 * 获取源图片类型
	 * @return string
	 */
    public function getSourceType() {
		return $this->_sourceType;
	}
	
    /**
     * 设置图片质量(只对jpg和png有用)
     * @param integer $quality
     */
    public function setQuality($quality) {
        $this->_quality = $quality;
    }

	/**
	 * 获取缩小比例
	 * @param integer $srcWidth 源图的宽
	 * @param integer $srcHeight 源图的高
	 * @param integer $dstWidth 目标图片的宽
	 * @param integer $dstHeight 目标图片的高
	 * @param string $minification 按大的还是小的缩率;small:取得小的缩率[缩小得比较少](宽或高有一边大于给定值),默认big:取得大的缩率(宽或高一定不会超过给定值)
	 * @return float | false
	 */
    public function getProportionality($srcWidth, $srcHeight, $dstWidth = null, $dstHeight = null, $minification = 'big') {
        $ratio = 1;
        $srcWidth = (int) $srcWidth;
        $srcHeight = (int) $srcHeight; 
        $dstWidth = (int) $dstWidth;
        $dstHeight = (int) $dstHeight;
        if ($srcWidth<1) {
        	$this->_error = '源图片的宽错误';
        	return false;
        }
        if ($srcHeight<1) {
        	$this->_error = '源图片的高错误';
        	return false;
        }
        if (!$dstWidth && !$dstHeight) {
        	return 1;
        }
        if ($srcWidth <= $dstWidth && $srcHeight <= $dstHeight) {
        	return 1;
        }
        if ($dstWidth!=null && $dstHeight==null) {
        	if ($dstWidth<1) {
        		$this->_error = '目标图片的宽必须是大于零的整数';
        		return false;
        	}
        	return $dstWidth/$srcWidth;
        }
        if ($dstHeight!=null && $dstWidth==null) {
        	if ($dstHeight<1) {
        		$this->_error = '目标图片的高必须是大于零的整数';
        		return false;
        	}
        	return $dstHeight/$srcHeight;
        }
        if ($dstWidth<1 || $dstHeight<1) {
        	$this->_error = '目标图片的宽和高必须是大于零的整数!';
        	return false;
        }
        if ($srcWidth*$dstHeight > $srcHeight*$dstWidth) {
            if ($minification == 'small') { // 求得小的缩小比例(ratio)
            	$ratio = $dstHeight/$srcHeight;	
            } else { // 求得大的缩小比例(ratio)
                $ratio = $dstWidth/$srcWidth;
            }
        } else {
        	if ($minification == 'small') { // 求得小的缩小比例(ratio)
        		$ratio = $dstWidth/$srcWidth;
        	} else { // 求得大的缩小比例(ratio)
        		$ratio = $dstHeight/$srcHeight;
        	}	
        }
        return $ratio;
    }

	/**
	 * 生成缩略图
	 * @param integer $width 目标宽
	 * @param integer $height 目标高
	 * @param boolean $bestfit 是否等比例压缩
	 */
	abstract public function thumbnail($width = null, $height = null, $bestfit = true);
	
    /**
     * 裁剪图片
     * @param integer $width 裁剪宽度
     * @param integer $height 裁剪高度
     * @param integer $x 裁剪坐标轴x
     * @param integer $y 裁剪坐标轴y
     * @return boolean
     */
    abstract public function crop($width = 0, $height = 0, $x = 0, $y = 0);
	
    /**
     * 添加文字水印
     * @param string $text 水印文字
     * @param string $place 水印位置
     * @param integer $x 水印位置X轴
     * @param integer $y 水印位置Y轴
     * @param integer $angle 文字旋转角度
     * @param array $style 文字样式
     * @return boolean
     */
    abstract public function watermarkText($text, $place = null, $x = 15, $y = 25, $angle = 0, array $style = array());

    /**
     * 添加图片水印
     * @param string $watermarkPath 水印图片
     * @param string $place 水印位置
     * @param integer $x 水印位置偏移量X
     * @param integer $y 水印位置偏移量Y
     * @param integer $alpha 水印图片的透明度
     * @param integer $angle 水印图片旋转角度
     */
    abstract public function watermarkImage($watermarkPath, $place = 'southeast', $x = 18, $y = 18, $alpha = 52, $angle = 0);

    /**
     * 水平或垂直翻转图片
     * @param string $hv
     * @return boolean
     */
    abstract public function rotateHV($hv = 'H');

    /**
     * 任意角度旋转图片
     * @param integer $angle 旋转角度
     * @param string $color 背景色
     */
    abstract public function rotate($angle, $color = 'transparent');
    
    /**
     * 调整图像大小,等比例缩放图片后进行裁剪,即生成指定大小的图片,多余部分进行裁剪
     * @param integer $width
     * @param integer $height
     * @param string $tooWideCutPosition 太宽了进行裁剪的位置
     * @param string $heightPlace 太高了进行裁剪的位置
     * @return boolean
     */
    abstract public function resize($width, $height, $tooWideCutPosition = 'center', $tooHighCutPosition = 'center');
    
    /**
     * 读取一张图片
     * @param string $targetPath
     */
    abstract public function read($targetPath);
    
    /**
     * 输出到浏览器
     */
    abstract public function show();
	
	/**
	 * 保存(写入)图片
	 * @param string $targetPath 目标图片路径
	 * @param boolean $flag (isCover) 是否覆盖已存在的图
	 * @return boolean
	*/
	abstract public function write($targetPath = null, $flag = true);

	/**
	 * 判断是否存在图像资源
	 * @return boolean
	 */
	protected function _isExistIm() {
	    if (is_resource($this->_im) || $this->_im instanceof Imagick) {
	        return true;
	    } else {
	        if (!$this->_error) {
	            $this->_error = '无法获取图像资源';
	        }
	        return false;
	    }
	}
	
	/**
	 * 创建目录(文件夹)路径下的所有目录 , created all folder
	 * 这里的方法和 Common_Tool::createdDirectory($directoryPath) 是一样的
	 * @param string $directoryPath 要创建的文件目录(文件夹)路径,只能是绝对路径,或相对路径,
	 * 不能是zend的重写路径(如 ‘/upload/img/’)或http://这样的路径
	 * @return boolean
	*/
    protected function createdDirectory($directoryPath) { // created all folder
    	$directoryPath = trim($directoryPath);
		if (!$directoryPath) {
			$this->_error = '创建目录路径为空!';
			return false;
		}
		$directoryPath = str_replace('\\', '/', $directoryPath);
		if ($directoryPath[strlen($directoryPath)-1] == '/') {
			$directoryPath = substr($directoryPath, 0, -1);
		}
		
		/* $pattern = '/([a-zA-Z]+:\/)?/';
		preg_match($pattern, $directoryPath, $prefixFolder);
		$createdFolder = $prefixFolder[0];
		$directoryPath = str_replace($createdFolder, '', $directoryPath); */ // 貌似这里为了兼容windows才写的,后面改版没有考虑进去 
		
        // 只因为有时file_exists明明有的目录,但是还是返回false,后改为从后面截取判断(都是安全模式惹的祸)
        // 后来经证实,在php安全模式下,有很多函数受到限制,所以需要设置php环境成非安全模式,设置 safe_mode (php可以用ini_get('safe_mode')查看)
        if (is_dir($directoryPath)) {
        	return true;
        }
        $arrayFolder = explode('/', $directoryPath);
        $sum = count($arrayFolder);
        $createdPath = array();
        for ($i=($sum-1); $i>0; $i--) {
        	array_unshift($createdPath, $arrayFolder[$i]);
        	$directoryPath = str_replace('/' . $arrayFolder[$i], '', $directoryPath);
            if (is_dir($directoryPath)) {
                break;
        	}
        }
        foreach ($createdPath as $path) {
        	if (is_writeable($directoryPath)) {
        		$directoryPath .= '/' . $path;
        		mkdir($directoryPath);
//         		mkdir($directoryPath, 0777, true); // 安全模式下有问题
//         		chmod($directoryPath, 0777);
        	} else {
        		$this->_error = "无法新建目标文件夹(目录);请确认目标文件夹路径是否正确或目标文件夹 $directoryPath 是否有写的权限!";
        		return false;
        	}
        }
        return true; // 不知道以后这个地方还会有问题不
		
		/* foreach ($arrayFolder as $folder) {
			$folder = trim($folder);
			$parentFolder = $createdFolder;
			$createdFolder .= $folder . '/';
			if ($createdFolder == '/') {
				continue;
			}
			$createdFolder = '/home/';
			
			if (!file_exists($createdFolder)) {
				if (!is_writeable($parentFolder)) {
					$this->setError("无法新建目标文件夹(目录);请确认目标文件夹路径是否正确或目标文件夹 $parentFolder 是否有写的权限!");
					return false;
				}
				mkdir($createdFolder);
			}
		} */

	}
    
}

 

class Lib_Image如下:

 


/**
 * @desc 与图片有关的一些操作,如生成缩略图,不变形缩小图片,打水印,调整图片透明度,切割图片,合成图片
 * 这里主要用 GD 库来操作,目前只支持 .jpg, .png, .gif 格式的图片(不支持gif动画)
 * @author Bear
 * @version 2.0.0 2012-12-25 16:36
 * @copyright xiqiyanyan.com
 * @created 2011-11-1 14:15
 */
class Lib_Image extends Lib_Image_Abstract
{
	/**
	 * 源图片的部分信息,如:宽、高、类型 ; 
	 * Array ( [0] => 1000 [1] => 1539 [2] => 3 [3] => width="1000" height="1539" [bits] => 8 [mime] => image/png )
	 * 索引 2 的值是:1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM
	 * “bits”的值是碰到的最高的位深度
	 * @var array
	 */
	private $_imageInfo;     

    /**
     * 允许的图片类型
     * @var array
     */
    private $_allowExt = array('.gif', '.jpg', '.jpeg', '.png'); // gd不支持bmp; 貌似别人有写过一个支持bmp的函数
	
    /**
     * 裁剪图片(除gif动画外,都能实现裁剪)
     * @see Lib_Image_Abstract::crop()
     * @param integer $width 目标宽,不能为负数(如果裁剪的宽和高都不传,将取原图片的宽和高)
     * @param integer $height 目标高,不能为负数(如果裁剪(目标)的宽或高只传一个,另一个将取原图片的)
     * @param integer $x 裁剪位置x轴,可以为负数;如为负数则在坐标轴原点的左边
     * @param integer $y 裁剪位置y轴,可以为负数;其图片左上角为坐标轴原点(0,0)
     * @return boolean
     */
    public function crop($width = 0, $height = 0, $x = 0, $y = 0) {
        if (!$this->_isExistIm()) {
    		return false;
        }
        $width = (int) $width;
        $height = (int) $height;
        $x = (int) $x;
        $y = (int) $y;
        if (!$width) {
            $width = $this->_sourceWidth;
        }
        if (!$height) {
            $height = $this->_sourceHeight;
        }
        if ($width < 1) {
            $this->_error = '裁剪的宽度不能小于1';
            $this->_im = null;
            return false;
        }
        if ($height < 1) {
            $this->_im = null;
            $this->_error = '裁剪的高度不能小于1';
            return false;
        }
        $defactoWidthAndHeight = $this->getDefactoCropWidthAndHeight($this->_sourceWidth, $this->_sourceHeight, $width, $height, $x, $y); 
        $newImage = imagecreatetruecolor ( $defactoWidthAndHeight['width'], $defactoWidthAndHeight['height'] );
        // resource imagecreatetruecolor( int $x_size宽, int $y_size高)  新建一个真彩色黑色图像
        $boolean = imagecopyresampled ( $newImage, $this->_im, 0, 0, 0, 0, $defactoWidthAndHeight['width'], $defactoWidthAndHeight['height'], $defactoWidthAndHeight['width'], $defactoWidthAndHeight['height'] );
        // bool imagecopyresampled ( 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 )
        // 重采样拷贝部分图像并调整大小,将一幅图像中的一块正方形区域拷贝到另一个图像中,平滑地插入像素值,因此,尤其是,减小了图像的大小而仍然保持了极大的清晰度。成功时返回 TRUE, 或者在失败时返回 FALSE.
        //$boolean = imagecopy ( $newImage, $this->_im, 0, 0, $x, $y, $width, $height );
        // imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
        
        if ($boolean) {
            $this->_im = $newImage;
            return true;
        } else {
            $this->_error = '裁剪图片出错';
            $this->_im = null;
            return false;
        }
    }
    
    /**
     * 生成固定大小的缩略图,即可以把图像等比例缩小后进行裁剪; 
     * Previews(缩略图)
     * @see Lib_Image_Abstract::resize()
     * @param interger $width 生成图片(目标图片)的宽度
     * @param integer $height 生成图片(目标图片)的高度
     * @param string $tooWideCutPosition 如果宽度超出,按什么来裁剪图片,取值见常量,如:center(默认):裁剪中间部分; west:居左裁剪; east:居右裁剪
     * @param string $tooHighCutPosition 如果高度超出,按什么来截取图片,取值见常量,如:center(默认):截取中间部分; north:居上裁剪; south:居下裁剪
     * @return boolean
     */
    public function resize($width, $height, $tooWideCutPosition = 'center', $tooHighCutPosition = 'center') {
        if (!$this->_isExistIm()) {
            return false;
        }
        $width = (int) $width;
        $height = (int) $height;
        if ($width < 0 || $height < 0) {
            $this->_error = '目标宽或高不能小于0';
            $this->_im = null;
            return false;
        }
        if (!$width && !$height) {
            return true;
        }
        if (!$width || !$height) { // 只传入了宽或高其中的一个
            return $this->thumbnail($width, $height);
        }
        
        $ratio = $this->getProportionality($this->_sourceWidth, $this->_sourceHeight, $width, $height, 'small');
        $cutW = intval($width/$ratio);
        $cutH = intval($height/$ratio);
        // 获取要裁剪的开始位置 $widthFlag 按什么位置裁剪宽
        $x = 0;
        $y = 0;
        switch ($tooWideCutPosition) {
            case self::PLACE_WEST : break;
            case self::PLACE_EAST : $x = (int) ($this->_sourceWidth-$cutW); break;
            default : $x = (int) ($this->_sourceWidth-$cutW)/2; break;
        }
        switch ($tooHighCutPosition) {
            case self::PLACE_NORTH : break;
            case self::PLACE_SOUTH : $y = (int) ($this->_sourceHeight-$cutH); break;
            default : $y = (int) ($this->_sourceHeight-$cutH)/2; break;
        }

        // 重新拷贝图像
        if (function_exists('imagecopyresampled')) {
            $tmpImage = imagecreatetruecolor($width, $height);// resource imagecreatetruecolor( int $x_size宽, int $y_size高) 新建一个真彩色黑色图像
            $boolean = imagecopyresampled($tmpImage, $this->_im, 0, 0, $x, $y, $width, $height, $cutW, $cutH);
            // bool imagecopyresampled ( 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 )
            // 重采样拷贝部分图像并调整大小,将一幅图像中的一块正方形区域拷贝到另一个图像中,平滑地插入像素值,因此,尤其是,减小了图像的大小而仍然保持了极大的清晰度。成功时返回 TRUE, 或者在失败时返回 FALSE.
        } else {
            $tmpImage = imagecreate($width, $height);// resource imagecreate ( int $x_size , int $y_size ) 新建一个基于调色板的空白图像
            $boolean = imagecopyresized($tmpImage, $this->_im, 0, 0, $x, $y, $width, $height, $cutW, $cutH); // 黑白
            // 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 )
            // 拷贝部分图像并调整大小,将一幅图像中的一块正方形区域拷贝到另一个图像中 
        }
        if ($boolean) {
            $this->_im = $tmpImage;
            return true;
        } else {
            $this->_error = '重新采样拷贝图像时出错';
            $this->_im = null;
            return false;
        }
    }

    /**
     * 载入一张图片
     * verification source image is exist and get source image infomation
     * @param string $sourcePath 源图片路径
     * @return boolean
     */
    public function read($sourcePath) {
    	if (!is_file($sourcePath)) {
    		$this->_error = '源图片文件不存在';
    		return false;
    	}
        $this->_imageInfo = getimagesize($sourcePath);
    	// array getimagesize ( string $filename [, array &$imageinfo ] )  取得图像位深度、类型、宽高; 本函数不需要 GD 图像库。
    	// getimagesize() 函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。
    	// 如果不能访问 filename 指定的图像或者其不是有效的图像,getimagesize() 将返回 FALSE 并产生一条 E_WARNING 级的错误。
        if (!$this->_imageInfo) {
        	$this->_error = '源图片不是有效的图像';
        	return false;
        }
        $type = strtolower(image_type_to_extension($this->_imageInfo[2]));
        // image_type_to_extension 获取图片的后缀名,包括点在内(注意这里的参数)
        if (!in_array($type, $this->_allowExt)) {
        	$this->_error = '不支持的图片文件格式,只支持' . join('、', $this->_allowExt) . '格式的图片';
        	return false;
        }
    	$this->_sourceType = substr($type, 1);
        $this->_sourcePath = $sourcePath;
        $createFunction = 'imagecreatefrom' . $this->_sourceType;
        $this->_im = $createFunction($this->_sourcePath); // 通过源文件类型创建图像资源
        $this->_sourceWidth = (int) $this->_imageInfo [0];  // 源图像的宽度
        $this->_sourceHeight = (int) $this->_imageInfo [1]; // 源图像的高度
        // $width = imagesx($this->_im); // int imagesx ( resource $image )
        // 获取图像的宽度 # 获取源图像的宽度 (现在才知道, # 也可以做为php的注释)
        // $height = imagesy($this->_im); //int imagesy ( resource $image )
        // 获取图像的高度
        return true;
        /* switch ($this->_imageInfo[2]) { // IMAGETYPE_JPEG
            case 1 : return $this->_im = imagecreatefromgif($this->_sourcePath); break;
            case 2 : return $this->_im = imagecreatefromjpeg($this->_sourcePath); break;
    		// resource imagecreatefromjpeg( string $filename)  从 JPEG 文件或 URL 新建一图像, 返回一图像标识符
    	    case 3 : return $this->_im = imagecreatefrompng($this->_sourcePath); break;
    	    default : $this->setError('源图片错误;不支持的文件类型,只支持GIF、JPG、PNG的图片'); return false; break;
        } */
    }

    /**
     * 等比例生成缩略图(bind thumbnail image ; 不支持gif动画,能生成jpg、gif、png格式的缩略图,如果gif动画不需要动画的话,也可以生成)
     * 如果源图片的宽和高都小于给定缩略图的宽和高就不进行缩率
     * 这里保持了源图像的比例,如果需要截取图片并生成缩略图请调用 resize方法
     * 最好生成的是 jpg 图片,这样图片会小很多
     * 呵呵,这个函数还可以用来当上传图片使用
     * @see Lib_Image_Abstract::thumbnail
     * @param integer $width 缩略图的宽
     * @param integer $height 缩略图的高 (如果想只按宽或高进行缩放时,宽或高可以只传一个,另一个设为0或null)
     * @param string $type 指定生成图片的类型,默认jpg,如果保持源图片类型传入null
     * @param integer $quality 生成缩略图的质量,取值范围是 0(最差)-100(最好);仅对jpg有效
     * @param boolean $flag 是否删除源图片,默认false:不删除, true:删除
     * @return false | string 如果成功返回完整的文件名,如果失败返回false,会有错误提示信息
     */
    public function thumbnail($width = null, $height = null, $bestfit = true) {
        // $_FILES['inputFileName']['type'] => 'image/jpeg'、'image/pjpeg'、'image/png'、'image/x-png'、'image/gif'、、、、
    	$width = (int) $width;
    	$height = (int) $height;
    	if (!$this->_isExistIm()) {
    		return false;
        }
        if ($width == null && $height == null) {
    		return true;
    	}
        if ($this->_sourceWidth <= $width && $this->_sourceHeight <= $height) {
        	return true;
        }
		$ratio = $this->getProportionality($this->_sourceWidth, $this->_sourceHeight, $width, $height);
		if (!$ratio) {
			return false;
		}
        $newWidth = floor($this->_sourceWidth * $ratio);
        $newHeight = floor($this->_sourceHeight * $ratio);
        if (function_exists ( 'imagecopyresampled' ) ) {
            $newImage = imagecreatetruecolor ( $newWidth, $newHeight );
            // resource imagecreatetruecolor( int $x_size宽, int $y_size高)
            // 新建一个真彩色黑色图像
            $boolean = imagecopyresampled ( $newImage, $this->_im, 0, 0, 0, 0, $newWidth, $newHeight, $this->_sourceWidth, $this->_sourceHeight );
            // bool imagecopyresampled ( 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 )
            // 重采样拷贝部分图像并调整大小,将一幅图像中的一块正方形区域拷贝到另一个图像中,平滑地插入像素值,因此,尤其是,减小了图像的大小而仍然保持了极大的清晰度。成功时返回 TRUE, 或者在失败时返回 FALSE.
        } else {
            $newImage = imagecreate ( $newWidth, $newHeight );
            // resource imagecreate ( int $x_size , int $y_size )
            // 新建一个基于调色板的空白图像(创建画布)
            // $newImage = imagecreatetruecolor($newWidth, $newHeight); // 貌似这个更好
            $boolean = imagecopyresized ( $newImage, $this->_im, 0, 0, 0, 0, $newWidth, $newHeight, $this->_sourceWidth, $this->_sourceHeight );
            // 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 )
            // 拷贝部分图像并调整大小,将一幅图像中的一块正方形区域拷贝到另一个图像中
        }
        if ($boolean) {
        	$this->_im = $newImage;
        	return true;
        } else {
        	$this->_error = '处理图片出错';
        	return false;
        }
		// @imagedestroy($newImage); // imagedestroy(resource $image) 销毁一图像
		// 操,特别注意了,这个地方还不能销毁这图像,貌似这里赋值时是按引用传递的
    }

    /**
	 * 给图片打上文字水印
	 * png8貌似不能换颜色
	 * @param string $text 要打水印的文字(包括中文),如果有中文的话,需要中文字体
	 * @param string $place 打水印的位置:取值见常量
	 * @param integer $x 水印位置,如果传入了$place,这个参数也有效,指X轴偏移量
     * @param integer $y 水印位置,如果传入了$place,这个参数也有效,指Y轴偏移量
     * @param integer $angle 文字旋转角度;正数顺时针,负数逆时针; 0 度为从左向右读的文本。例如 90 度表示从上往下读的文本。180(-180)度为从右到左的倒立文本
     * @param array $style 水印文字样式
     * $style['fontFile'] 水印文字字体 ; 如:APPLICATION_PATH . '/../public/Fonts/msyhbd.ttf'(如果水印文字有中文,必须要中文字体才能支持,不然会有乱码)
     * $style['fontSize'] 水印文字的大小,默认15
     * $style['fillColor'] 水印文字的颜色,默认黑色 #000000; 文字颜色(0-255);取值如:$style['fillColor'] = array('red'=>255, 'green'=>0, 'blue'=>0); 
     * 这些参数是 0 到 255 的整数或者十六进制的 0x00 到 0xFF; 同样该参数也可以传入字符串,如:#F00 ; 不支持颜色单词 
     * $style['fillOpacity'] 水印文字的透明度,取值0(完全不透明)-127(完全透明);默认:68 半透明
     * $style['underColor'] 水印文字背景色,默认无 (这里暂不支持)
     * @return boolean
	 */
    public function watermarkText($text, $place = null, $x = 15, $y = 25, $angle = 0, array $style = array()) {
        if (!$text || !is_string($text)) {
            $this->_error = '水印文字不能为空且一定是字符串';
            return false;
        }
        if (!$this->_isExistIm()) {
            return false;
        }
        
        if (!isset($style['fontFile']) || !$style['fontFile']) {
            $style['fontFile'] = ROOT_PATH . '/fonts/msyhbd.ttf';
        }
        if (!is_file($style['fontFile'])) {
            $this->_error = '字体文件不存在';
            $this->_im = null;
            return false;
        }
        if (!isset($style['fontSize']) || !$style['fontSize']) {
            $style['fontSize'] = 15;
        }
        $angle = -$angle;
        $temp = imagettfbbox($style['fontSize'], $angle, $style['fontFile'], $text); // 取得使用 TrueType 字体的文本的范围
        $textW = $temp[2] - $temp[6]; // 取得字符串的宽
        $textH = $temp[3] - $temp[7]; // 取得字符串的高
        
        switch ($place) {
            case self::PLACE_CENTER    : $x = ($this->_sourceWidth-$textW)/2; $y = ($this->_sourceHeight-$textH)/2; break;
            case self::PLACE_NORTHEAST : $x = $this->_sourceWidth-($textW+$x); break;
            case self::PLACE_NORTHWEST : break;
            case self::PLACE_SOUTHEAST : $x = $this->_sourceWidth-($textW+$x); $y = $this->_sourceHeight-($textH+$y); break;
            case self::PLACE_SOUTHWEST : $y = $this->_sourceHeight-($textH+$y); break;
            default : break;
        }
        
        if (isset($style['fillColor'])) {
            if (is_string($style['fillColor'])) {
                $style['fillColor'] = strtoupper($style['fillColor']);
                if (substr($style['fillColor'], 0, 1) != '#') {
                    $this->_error = '文字颜色参数错误,应该如:#FFFFFF';
                    $this->_im = null;
                    return false;
                }
                if (isset($style['fillColor'][6])) {
                    $style['fillColor'] = array('red'   => hexdec(substr($style['fillColor'], 1, 2)), // 十六进制转换为十进制
                                             'green' => hexdec(substr($style['fillColor'], 3, 2)), 
                                             'blue'  => hexdec(substr($style['fillColor'], 5, 2)));
                } else {
                    $style['fillColor'] = array('red'   => hexdec($style['fillColor'][1].$style['fillColor'][1]), // 十六进制转换为十进制
                            'green' => hexdec($style['fillColor'][2].$style['fillColor'][2]),
                            'blue'  => hexdec($style['fillColor'][3].$style['fillColor'][3]));
                }
            } else if (is_array($style['fillColor'])) {
                // 数组不处理
            } else {
                $style['fillColor'] = array('red'=>0, 'green'=>0, 'blue'=>0);
            }
        } else {
            $style['fillColor'] = array('red'=>0, 'green'=>0, 'blue'=>0);
        }
        if (!isset($style['fillOpacity'])) {
            $style['fillOpacity'] = 68;
        }

//         $image = imagecreatetruecolor($textW, $textH);
        $color = imagecolorallocatealpha($this->_im, $style['fillColor']['red'], $style['fillColor']['green'], $style['fillColor']['blue'], $style['fillOpacity']);
        
        //$color = imagecolorallocate($this->_im, $style['fillColor']['red'], $style['fillColor']['green'], $style['fillColor']['blue']);
        //var_dump($color);exit;
        // int imagecolorallocate ( resource $image , int $red , int $green , int $blue ) 为一幅图像分配颜色。 首次调用将创建背景颜色
        //string iconv(string $in_charset, string $out_charset, string $str); // 字符串的字符集转换;如gb2312->utf-8 :$string = iconv('GB2312', 'utf-8', $string);

        // imagefttext($im, $fontSize, 0, $startXY['x'], $startXY['y'], $color, $fontFile, $string); 
        // 使用 FreeType 2 字体将文本写入图像 ;array imagefttext ( resource $image , float $size , float $angle , int $x , int $y , int $col , string $font_file , string $text [, array $extrainfo ] )
        imagettftext($this->_im, $style['fontSize'], $angle, $x, $y, $color, $style['fontFile'], $text); // 用 TrueType 字体向图像写入文本 ;
        // array imagettftext ( resource $image , float $size , float $angle , int $x , int $y , int $color , string $fontfile , string $text )
        // image 图像资源。
        // size 字体大小。根据 GD 版本不同,应该以像素大小指定(GD1)或点大小(GD2)。
        // angle 角度制表示的角度,0 度为从左向右读的文本。更高数值表示逆时针旋转。例如 90 度表示从下向上读的文本。
        // x 由 x,y 所表示的坐标定义了第一个字符的基本点(大概是字符的左下角)。这和 imagestring() 不同,其 x,y 定义了第一个字符的左上角。例如 "top left" 为 0, 0。
        // y Y 坐标。它设定了字体基线的位置,不是字符的最底端。
        // color 颜色索引。使用负的颜色索引值具有关闭防锯齿的效果。见 imagecolorallocate()。
        // fontfile 是想要使用的 TrueType 字体的路径。 根据 PHP 所使用的 GD 库的不同,当 fontfile 没有以 / 开头时则 .ttf 将被加到文件名之后并且会在库定义字体路径中尝试搜索该文件名。 当使用的 GD 库版本低于 2.0.18 时,一个空格字符 而不是分号将被用来作为不同字体文件的“路径分隔符”。不小心使用了此特性将会导致一条警告信息:Warning: Could not find/open font。对受影响的版本来说唯一解决方案就是将字体移动到不包含空格的路径中去。
        // text 文本字符串。 可以包含十进制数字化字符表示(形式为:€)来访问字体中超过位置 127 的字符。UTF-8 编码的字符串可以直接传递。 如果字符串中使用的某个字符不被字体支持,一个空心矩形将替换该字符。
        // 此函数 imagettftext() 返回一个含有 8 个单元的数组表示了文本外框的四个角,顺序为左下角,右下角,右上角,左上角。这些点是相对于文本的而和角度无关,因此“左上角”指的是以水平方向看文字时其左上角。本函数同时需要 GD 库和 » FreeType 库。
        return true;
//     		if ($isCover) { // 覆盖源图片
//     			$this->_targetPath = $this->_sourcePath;
//     			$flag = false;
//     			$imageFileName = pathinfo($this->_targetPath, PATHINFO_BASENAME);
//     			$type = pathinfo($this->_targetPath, PATHINFO_EXTENSION);
//     		} else {

//     			$this->_targetPath = $this->_targetPath . $imageFileName;
//     		}
//     		$this->_fileName = null;


//     		return $imageFileName;
    		/* $imageFileName = $this->getFileName() . $this->_sourceExtension; // 获取文件名和后缀名
    		if (!$this->printImageByExt($this->_im, $this->_targetPath . $imageFileName)) {
    			$this->setError('保存图片文件出错。无法保存图片,不支持的图片格式或图片文件不可写');
    			return false;
    		} */
    }
    
    /**
     * 给源图片打上图片水印
     * (貌似有些打出来达不到想要的效果)
     * 水印图片如果是 png 的话,貌似全透明的效果出不来
     * 如果源图是png8貌似打出来效果不好
     * @see Lib_Image_Abstract::watermarkImage()
     * @param string $watermarkPath 水印图片的绝对路径
     * @param string $place 打水印的位置(position);取值见常量。默认southeast:右下角;center:中间;southwest:左下角;northeast:右上角; northwest:左上角
     * @param integer $x 打水印的开始位置,X轴;如果传入了$place,此值将做为偏移量
     * @param integer $y 打水印的开始位置,Y轴;如果传入了$place,此值将做为偏移量
     * @param integer $alpha 水印图片的透明度,取值0(全透明)-100(不透明);仅对 jpg 格式的水印图片有效(暂不支持)
     * @param integer $angle TODO 水印图片的旋转角度
     * @return boolean
     */
    public function watermarkImage($watermarkPath, $place = 'southeast', $x = 18, $y = 18, $alpha = 52, $angle = 0) {
        if (!is_file($watermarkPath)) {
            $this->_error = '水印图片不存在!';
            $this->_im = null;
            return false;
        }
        if (!$this->_isExistIm()) {
            return false;
        }
        $watermarkExt = strtolower(strrchr($watermarkPath, '.'));
        if (!in_array($watermarkExt, $this->_allowExt)) { // 仅通过后缀名进行判断和创建图像资源; TODO 真实的文件类型
            $this->_error = '水印图片文件类型不符,只支持 ' . implode('、', $this->_allowExt) . ' 格式的图片';
            $this->_im = null;
            return false;
        }
        $watermarkType = substr($watermarkExt, 1);
        if ($watermarkType == 'jpg') {
            $watermarkType = 'jpeg';
        }
        $imageFunction = 'imagecreatefrom' . $watermarkType;
        $watermarkImg = $imageFunction($watermarkPath);
        $watermarkW = imagesx($watermarkImg);
        $watermarkH = imagesy($watermarkImg);
        if ($this->_sourceWidth < $watermarkW || $this->_sourceHeight < $watermarkH) { // 多于判断,有时候没有必要考虑
            $this->setError('源图片的宽或高小于水印图片的宽或高,无法生成水印图!');
            $this->_im = null;
            return false;
        }
        switch ($place) {
            case self::PLACE_NORTHWEST : break;
            case self::PLACE_NORTHEAST : $x = $this->_sourceWidth-($watermarkW+$x); break;
            case self::PLACE_CENTER    : $x = ($this->_sourceWidth-$watermarkW)/2; $y = ($this->_sourceHeight-$watermarkH)/2; break;
            case self::PLACE_SOUTHWEST : $y = $this->_sourceHeight-($watermarkH+$y); break;
            case self::PLACE_SOUTHEAST : $x = $this->_sourceWidth-($watermarkW+$x); $y = $this->_sourceHeight-($watermarkH+$y); break;
            default : break;
        }
        imagealphablending($this->_im, true); // 设定图像的混色模式;  貌似这里没有什么用,用不用都一样
        $boolean = imagecopymergegray($this->_im, $watermarkImg, $x, $y, 0, 0, $watermarkW, $watermarkH, $alpha); // ubuntu 64 位下测试不行; ubuntu 32 位下测试可以 
        // 用灰度拷贝并合并图像的一部分;拷贝水印到目标文件
        //$boolean = imagecopy($this->_im, $watermarkImg, $x, $y, 0, 0, $watermarkW, $watermarkH); // ubuntu 64 位下测试还可以
        //$boolean = imagecopymerge($this->_im, $watermarkImg, $x, $y, 0, 0, $watermarkW, $watermarkH, 100); // ubuntu 64 位下测试不行
        //$boolean = imagecopyresized($this->_im, $watermarkImg, $x, $y, 0, 0, $watermarkW, $watermarkH, $watermarkW, $watermarkH); // ubuntu 64 位下测试还可以
        //$boolean = imagecopyresampled($this->_im, $watermarkImg, $x, $y, 0, 0, $watermarkW, $watermarkH, $watermarkW, $watermarkH); // ubuntu 64 位下测试还可以
        // int imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); 拷贝图像的一部分
        //imagecopyresized($this->_im, $watermarkImg, $start['x'], $start['y'], 0, 0, $watermarkW, $watermarkH, $watermarkW, $watermarkH); // 这个写法就和上面的一模一样
        //int imagecopymerge ( resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y, int src_w, int src_h, int pct ) 拷贝并合并图像的一部分
        // 将 src_im 图像中坐标从 src_x,src_y 开始,宽度为 src_w,高度为 src_h 的一部分拷贝到 dst_im 图像中坐标为 dst_x 和 dst_y 的位置上。两图像将根据 pct 来决定合并程度,其值范围从 0 到 100。
        // 当 pct = 0 时,实际上什么也没做 当为 100 时本函数和 imagecopy() 完全一样。  
        // imagecopymergegray 和 imagecopymerge() 完全一样只除了合并时通过在拷贝操作前将目标像素转换为灰度级来保留了原色度。
        if ($boolean) {
            return true;
        } else {
            $this->_error = '拷贝并合并图像时出错';
            $this->_im = null;
            return false;
        }
    }

    /**
     * 水平(左右翻转)或垂直(上下翻转)翻转图片
     * @see Lib_Image_Abstract::rotateHV()
     * @param string $hv 是水平还是垂直翻转,默认H:水平;V:垂直;
     * @return boolean
     */
    public function rotateHV($hv = 'H') {
        if (!$this->_isExistIm()) {
            return false;
        }
        $imgTmp = imagecreatetruecolor($this->_sourceWidth, $this->_sourceHeight);
        if ($hv == self::ROTATE_H) { // 水平翻转
            $startX = $this->_sourceWidth-1;
            $startY = 0;
            $srcX = -$this->_sourceWidth;
            $srcY = $this->_sourceHeight;
        } elseif ($hv == self::ROTATE_V) { // 垂直翻转
            $startX = 0;
            $startY = $this->_sourceHeight-1;
            $srcX = $this->_sourceWidth;
            $srcY = -$this->_sourceHeight;
        } else {
            $this->setError('参数错误');
            return false;
        }
        $boolean =  imagecopyresampled($imgTmp, $this->_im, 0, 0, $startX, $startY, $this->_sourceWidth, $this->_sourceHeight, $srcX, $srcY);
        if ($boolean) {
            $this->_im = $imgTmp;
            return true;
        } else {
            $this->_error = '翻转图片失败';
            return false;
        }
    }

    /**
     * 写入图片
     * @param string $targetPath 目标路径(只能是绝对路径)
     * @param boolean $flag 是否覆盖(isCover)已存在的图片;默认true:覆盖;false:不覆盖
     * @see Lib_Image_Abstract::write()
     * @return boolean
     */
    public function write($targetPath = null, $flag = true) {
    	if ($targetPath != null) {
            $this->_targetPath = str_replace('\\', '/', $targetPath);
    	}
    	if ($this->_targetPath == null) {
    		$this->_error = '生成图片的目标路径不能为空';
    		return false;
    	}
    	if (!$this->_isExistIm()) {
    		return false;
    	}
    	
    	// 下面检测路径是否有写的权限,和创建没有的文件夹
        $directory = pathinfo($this->_targetPath, PATHINFO_DIRNAME); // pathinfo 默认返回所有文件路径信息; 这里返回文件夹信息(返回目录部分)
    	$boolean = $this->createdDirectory($directory);
    	if (!$boolean) {
    		return false;
    	}
    	return $this->writeImageByPath($this->_targetPath, $flag);
    }

    /**
     * 任意角度旋转图片
     * @see Lib_Image_Abstract::rotate()
     * @param integer $angle 旋转角度,负数逆时针,正数顺时针
     * @param array | string $color 背景颜色(可以实现半透明,但是保存图片必须为png),默认transparent:全透明 。
     * 取值如:array('red'=>0, 'green'=>0, 'blue'=>255) 或 array('red'=>0xFF, 'green'=>0xFF, 'blue'=>0xFF); 或 #FFFFFF 或 #0f0 
     * @return boolean
     */
    public function rotate($angle, $color = 'transparent') {
        if (!$this->_isExistIm()) {
            return false;
        }
        if ($color == 'transparent') {
            //$color = imagecolorallocate($this->_im, 255, 255, 255);
            //$color = imagecolortransparent($this->_im, $color); // 将某个颜色定义为透明色 ; 这里貌似不行
            $color = imagecolorallocatealpha($this->_im, 255, 255, 255, 127); // 2147483647 2130706432 2133993502
            // 为一幅图像分配颜色+alpha; 失败返回false。
        } else {
            $error = '颜色参数错误';
            if (is_array($color)) { // 不处理
                if (!isset($color['red']) || !isset($color['green']) || !isset($color['blue'])) {
                    $this->_error = $error;
                    $this->_im = null;
                    return false;
                }
            } elseif (is_string($color)) {
                $color = strtoupper($color);
                if (substr($color, 0, 1) != '#') {
                    $this->_error = '文字颜色参数错误,应该如:#FFFFFF';
                    $this->_im = null;
                    return false;
                }
                if (isset($color[6])) {
                    $color = array('red'   => hexdec(substr($color, 1, 2)), // 十六进制转换为十进制
                            'green' => hexdec(substr($color, 3, 2)),
                            'blue'  => hexdec(substr($color, 5, 2)));
                } else {
                    $color = array('red'   => hexdec($color[1].$color[1]), // 十六进制转换为十进制
                            'green' => hexdec($color[2].$color[2]),
                            'blue'  => hexdec($color[3].$color[3]));
                }
                // TODO rgb(255,255,255) rgba(0,0,0,127)
            } else {
                $this->_error = $error;
                $this->_im = null;
                return false;
            }
            // TODO 独立函数,将颜色值转为数组rgba
            if (!isset($color['alpha'])) {
                $color['alpha'] = 0;
            }
            $color = imagecolorallocatealpha($this->_im, $color['red'], $color['green'], $color['blue'], $color['alpha']); 
        }
        $this->_im = imagerotate($this->_im, -$angle, $color, 1);
        if ($this->_im) {
            return true;
        } else {
            $this->_im = null;
            $this->_error = '旋转图片失败';
            return false;
        }
    }

    /**
     * 输出图像到浏览器
     * @see Lib_Image_Abstract::show()
     */
    public function show() {
        switch ($this->_sourceType) {
            case self::TYPE_GIF  : $imgType = 'image/gif'; $ext = 'gif'; break;
            case self::TYPE_JPEG :
            case self::TYPE_JPG  : $imgType = 'image/jpeg'; $ext = 'jpeg'; break;
            default : $imgType = 'image/png'; $ext = 'png'; break;
        }
        header('Content-Type:' . $imgType);
        $function = 'image' . $ext;
        $function($this->_im);
    }

    /**
     * 释放资源
     */
    public function __destruct() {
        if (is_resource($this->_im)) {
            imagedestroy($this->_im); // imagedestroy(resource $image) 销毁一图像
        }
    }

    /**
     * 获取裁剪后图片的实际宽度和高度
     * @param integer $sourceWidth 原图片的宽度
     * @param integer $sourceHeight 原图片的高度
     * @param integer $cropWidth 要裁剪的宽度
     * @param integer $cropHeight 要裁剪的高度
     * @param integer $x 裁剪的X坐标轴,可以为负数
     * @param integer $y 裁剪的Y坐标轴,可以为负数
     * @return array
     */
    private function getDefactoCropWidthAndHeight($sourceWidth, $sourceHeight, $cropWidth, $cropHeight, $x, $y) {
        $defactoWidthAndHeight = array('width'=>$cropWidth, 'height'=>$cropHeight);
        if (($cropWidth+$x) > $sourceWidth) {//$this->_sourceWidth - $x < $width
            $defactoWidthAndHeight['width'] = $sourceWidth-$x;
        } elseif (($cropWidth+$x) < $cropWidth) {
            $defactoWidthAndHeight['width'] = $cropWidth+$x;
        }
        if (($cropHeight+$y) > $sourceHeight) {
            $defactoWidthAndHeight['height'] = $sourceHeight-$y;
        } elseif (($cropHeight+$y) < $cropHeight) {
            $defactoWidthAndHeight['height'] = $cropHeight+$y;
        }
        return $defactoWidthAndHeight;
    }

    /**
     * 根据图片类型,保存相应的图片
     * @param string $targetPath 图片保存路径,包括完整的文件名
     * @param boolean $flag 是否覆盖已存在的图片;默认true:覆盖;false:不覆盖
     * @return boolean
     */
    private function writeImageByPath($targetPath, $flag) {
        if (is_file($targetPath)) {
            if ($flag) {
                if (!is_writeable($targetPath)) {
                    $this->_error = '图片文件 ' . $targetPath . ' 已存在且不可写!无法保存图片文件!';
                    return false;
                }
            } else {
                $this->_error = '目标文件已存在';
                return false;
            }
        }
        $dir = pathinfo($targetPath, PATHINFO_DIRNAME); // pathinfo 默认返回所有文件路径信息; 这里返回文件夹信息(返回目录部分)
        if (!is_writable($dir)) {
            $this->_error = '目录 ' . $dir . ' 不可写!无法保存图片!';
            return false;
        }
        $ext = strtolower(pathinfo($targetPath, PATHINFO_EXTENSION)); // 图片类型
        if (!in_array('.' . $ext, $this->_allowExt)) {
            $this->_error = '不支持的图片文件格式,无法保存图片;只支持 ' . join('、', $this->_allowExt) . ' 格式的图片';
            return false;
        }
        switch ($ext) {
            case self::TYPE_GIF   : return imagegif($this->_im, $targetPath); break;
            /* case 'png' : $quality = floor($quality/10);
             if ($quality < 0 || $quality > 9) {
            $quality = 8;
            }
            $quality = 10 - $quality;
            return imagepng($im, $targetPath, $quality); break; */
            // 特别注意了:这里到质量只能是0-9,如果填错了将可能无法生成图片;  (其实这里的质量对png影响不大,所以没有什么意义)
            // 特别注意了:imagepng($image[, $filename, $quality, $filters]) 倒数第二个参数是表示图片是压缩比例,取值必须是0~9( compression level must be 0 through 9 );
            // 0  代表不压缩 文件和源文件一样大,1代表压缩最小, 9代表压缩最大,貌似没有多大的区别。默认6左右
            case self::TYPE_PNG   : imagesavealpha($this->_im, true); // 如果源gif或png有透明的部分需要保留
            // imagesavealpha($image, $saveflag); // 设置标记在保存png图像时保存完整的alpha通道;使用本函数,必须将 alphablending 清位(imagealphablending($im, false))
            return imagepng($this->_im, $targetPath); break;
            case self::TYPE_JPG   :
            case self::TYPE_JPEG  : return imagejpeg($this->_im, $targetPath, $this->_quality); break; // jpeg 默认 $quality = 75
            // bool imagejpeg ( resource $image [, string $filename [, int $quality ]] )  以 JPEG 格式将图像输出到浏览器或文件
            default : $this->_error = '不支持的图片格式,无法保存图片'; return false; break;
        }
    }

}

 

class Lib_Imagick如下:

 

/**
 * @desc 对Linux的ImageMagick进行扩展,对图片进行处理 (需要Linux安装ImageMagick)
 * http://www.1024i.com  学习网站
 * @author Bear
 * @copyright xiqiyanyan.com
 * @version 2.0.0 2012-07-16 14:16
 * @created 2012-06-30 09:49
 */
class Lib_Imagick extends Lib_Image_Abstract
{
	/**
	 * 允许的图片类型
	 * @var array
	 */
    private $_allowExt = array('.gif', '.jpg', '.jpeg', '.png', '.bmp');
    
    /**
     * 分解gif图片 (GIF动画为了压缩,会以第一帧为模板,其余各帧按照适当的偏移量依次累加,并只保留不同的像素,结果是导致各帧尺寸不尽相同)
     * @param string $targetFolder 分解后保存的文件夹(目录) (后面可以带/,也可以不带)
     * @param string $prefix 生成gif图片的前缀名
     */
    public function gifDecay($targetFolder, $prefix = '') {
        if (!$this->_im) {
            return false;
        }
        $targetFolder = $this->formatPath($targetFolder);
        $i = 0;
        foreach ($this->_im as $image) {
            $i++;
            $targetPath = $targetFolder . $prefix . $i . '.gif';
            $image->writeImage($targetPath);
        }
    }
    
    /**
     * 等比例生成gif缩略图
     * gif缩略图暂时不提供变形压缩和裁剪
     * 如果源图片尺寸比目标图片尺寸还要小,将等比例拉伸
     * 可按一边等比例缩放
     * @param integer $width 缩略图的宽
     * @param integer $height 缩略图的高
     * @param boolean $constrain 是否等比例缩放
     * @return boolean
     */
    public function gifThumbnail($width, $height, $constrain = true) {
        if (!$this->_isExistIm()) {
            return false;
        }
        $this->_im = $this->_im->coalesceImages(); // coalesceimages 确保各帧尺寸一致,详见手册 Imagick::coalesceImages
        if (!$width || !$height) {
            $constrain = false;
        }
        foreach ($this->_im as $frame) { /* Resize all frames */
            $frame->thumbnailImage($width, $height, $constrain); // 这里设为false时,才能另一边传0不报错,才能实现按一边等比例缩放
        }
        $this->_im = $this->_im->optimizeImageLayers(); // optimizeImageLayers 它删除重复像素内容,也可以参考下手册
        // 注意:不管是coalesceimages,还是optimizeImageLayers,都是返回新的Imagick对象!
        return true;
        // 如果要求更完美一点,可以使用quantizeImages方法进一步压缩(不知道怎么用)
    
    
        // exec("convert $dir -coalesce $dir"); // 对gif进行整合 (不知道这句话什么意思)
        // exec("convert -size $width"."x"."$height $dir -esize $max_width"."x"."$max_height $dir"); (这句话也没有来得及测试)
        //     	$str = "convert $this->_sourcePath -coalesce -thumbnail {$width}X{$height} -layers optimize $targetPath";
        //     	exec($str); // 这个命令行是等比例缩略
    
    
        //$im = new Imagick($sourcePath); // Create a new imagick object and read in GIF
        /* foreach ($this->_im as $frame) { // Resize all frames
        $frame->thumbnailImage($width, $height, true);
        $frame->setImagePage($width, $height, 0, 0); //Set the virtual canvas to correct size
        }
        return $this->writes($targetPath); */
        // 后面这个能生成gif动画,但是不是等比例的,貌似不对,还有透明东东
        // Notice writeImages instead of writeImage
    }
    
    /**
     * 载入一张图片
     * @param string $sourcePath 源图片路径
     * @return boolean
     */
    public function read($sourcePath) {
    	if (!is_file($sourcePath)) {
    		$this->_error = '源文件不存在';
    		return false;
    	}
    	try {
            $this->_im = new Imagick($sourcePath); // 其实这里也可以当验证图片类型
            /* Create a new imagick object and read in */
            $this->_sourceType = strtolower($this->_im->getimageformat()); 
            // 如果要设置图片类型用setImageFormat.  注意了:getformat 和 getImageFormat 是不一样的
            // 真的很奇怪, 如果后缀名是jpeg的话,这个地方无法获取到图片类型; 
            // 后来证实是没有安装libpng、libjpeg,其实是支持jpeg的
            // $ext = $this->_im->getImageType(); // 这个也可以获取图片的类型;取值:5:gif;6:bmp
            // 源图片类型,图片本质是gif,如果仅修改后缀成jpg,不会对这个有影响
            if (!in_array('.' . $this->_sourceType, $this->_allowExt)) {
            	$this->_error = '不支持的图片文件格式,只支持 ' . join('、', $this->_allowExt) . ' 格式的图片';
            	$this->_im = null;
            	return false;
            }
            if ($this->_sourceType == self::TYPE_GIF) {
                $this->_im = $this->_im->coalesceImages();
            }
            $widthAndHeight = $this->_im->getImageGeometry(); // 获取图片的宽和高(如果是gif图片,取得的高和宽将是最后一帧的宽和高)
            // Array ( [width] => 588 [height] => 436 )   $this->_im->getimagewidth();获取图片的宽
            // $this->_im->getImagePage(); 获取图片的部分信息,返回如:array{["width"]=>int(500), ["height"]=>int(282), ["x"]=>int(0), ["y"]=>int(0)}
            $this->_sourceWidth = (int) $widthAndHeight['width'];
            $this->_sourceHeight = (int) $widthAndHeight['height'];
            $this->_sourcePath = $sourcePath;
    	} catch (Exception $e) {
            $this->_error = '读取图片文件出错,不支持的图片文件格式';
            $this->_im = null;
            return false;
    	}
    }
    
    /**
     * 生成缩略图(压缩图片)(支持gif动画);如果 $bestfit 为true,宽、高都不会超过给定到值,如果为false,就是固定给定的值
     * 如果只传入来宽或高的一个(另一个传null或0),就会按照宽或高等比例缩放
     * 如果源图片尺寸比目标图片尺寸还要小,将进行拉伸
     * 如果宽和高都不传,将保持源图片的宽和高
     * @param integer $width 目标宽
     * @param integer $height 目标高
     * @param boolean $bestfit 是否变形压缩,默认true:不变形,false:变形
     * @return boolean
     * @see Lib_Image_Abstract::thumbnail
     */
    public function thumbnail($width = null, $height = null, $bestfit = true) {
    	if (!$this->_isExistIm()) {
    		return false;
    	}
    	if ($width == null && $height == null) {
    		return true;
    	}
    	if ($this->_sourceType == self::TYPE_GIF) {
    		return $this->gifThumbnail($width, $height, $bestfit);
    	}
    	if (!$width || !$height) {
    		$bestfit = false;
    	}
    	return $this->_im->thumbnailimage($width, $height, $bestfit);
    }

    /**
     * 裁剪图片(gif动画也能裁剪)
     * @param integer $width 目标宽,不能为负数(如果裁剪的宽和高都不传,将取原图片的宽和高)
     * @param integer $height 目标高,不能为负数(如果裁剪(目标)的宽或高只传一个,另一个将取原图片的)
     * @param integer $x 裁剪位置x轴,可以为负数;如为负数则在坐标轴原点的左边
     * @param integer $y 裁剪位置y轴,可以为负数;其图片左上角为坐标轴原点(0,0)
     * @return boolean
     */
    public function crop($width = 0, $height = 0, $x = 0, $y = 0) {
        /* if ($this->_sourceWidth <= $x || $this->_sourceHeight <= $y) {
        	$this->_error = '裁剪坐标大于源图片的宽或高,无法进行裁剪!';
        	$this->_im = null;
            return false;
        } */
    	if (!$this->_isExistIm()) {
    		return false;
    	}
        $width = (int) $width;
        $height = (int) $height;
        $x = (int) $x;
        $y = (int) $y;
        if (!$width) {
            $width = $this->_sourceWidth;
        }
        if (!$height) {
            $height = $this->_sourceHeight;
        }
        if ($width < 1) {
        	$this->_error = '裁剪的宽度不能小于1';
        	$this->_im = null;
            return false;
        }
        if ($height < 1) {
        	$this->_im = null;
            $this->_error = '裁剪的高度不能小于1';
            return false;
        }
        if ($this->_sourceType == self::TYPE_GIF) {
            $this->_im = $this->_im->coalesceImages(); // 确保每帧的宽度和高度一致
            foreach ($this->_im as $frame) {
                $frame->cropImage($width, $height, $x, $y);
                $frame->setImagePage($frame->getImageWidth(), $frame->getImageHeight(), 0, 0); /* Set the virtual canvas to correct size */
            }
            return true;
    
            /* $unitl = $image->getNumberImages (); // 貌似提速gif处理 不知道什么意思
            for($i = 0; $i < $unitl; $i ++) {
                $image->setImageIndex ( $i );
                $image->compositeImage ( $numimage, Imagick::COMPOSITE_OVER, 0, 0 );
                //降低色彩量化的质量
                $image->quantizeImage(256, imagick::COLORSPACE_RGB, 4, false, false);
            } */
        } else {
            $boolean = $this->_im->cropImage($width, $height, $x, $y);
            if ($boolean) {
                return $this->_im->setimagepage($this->_im->getimagewidth(), $this->_im->getimageheight(), 0, 0);
                // 重置图片的显示信息,删除多余的透明层
            } else {
                $this->_error = '裁剪图片出错';
                $this->_im = null;
                return false;
            }
        }
    }

    /**
     * 添加文字水印(不支持gif动画,操处理gif图片有点慢)
     * 此函数依赖getDrawForText函数
     * @param string $text 水印文字
     * @param string $srcPath 需要添加水印图片的绝对路径
     * @param string $dstPath 打好水印后保存文件路径,如果想覆盖原图片,设成和源图片路径一样就OK
     * @param string $place 水印位置,详见常量  TODO 未完成
     * @param integer $x 水印位置(也是偏移量)
     * @param integer $y 水印位置(也是偏移量)
     * @param integer $angle 水印旋转角度,正数顺时针,负数逆时针
     * @param array $style 水印文字样式
     * $style['fontFile'] 水印文字字体 ; 如:APPLICATION_PATH . '/../public/Fonts/msyhbd.ttf'
     * (如果水印文字有中文,必须要中文字体才能支持,不然会有乱码)
     * $style['fontSize'] 水印文字的大小,默认15
     * $style['fillColor'] 水印文字的颜色,默认黑色 #000000
     * $style['fillOpacity'] 水印文字的透明度,取值范围0(全透明)-1(完全不透明);默认:0.58 半透明 
     * $style['underColor'] 水印文字背景色,默认无
     * @return boolean
     */
    public function watermarkText($text, $place = null, $x = 15, $y = 25, $angle = 0, array $style = array()) {
        if (!$this->_isExistIm()) {
            return false;
        }
        $font = isset ( $style ['fontFile'] ) ? $style ['fontFile'] : null;
        $size = isset ( $style ['fontSize'] ) ? $style ['fontSize'] : 15;
        $color = isset ( $style ['fillColor'] ) ? $style ['fillColor'] : 'black';
        // $pixel = new ImagickPixel('gray');
        // $draw->setfillcolor($pixel);
        $opacity = isset ( $style ['fillOpacity'] ) ? $style ['fillOpacity'] : 0.58;
        $underColor = isset ( $style ['underColor'] ) ? $style ['underColor'] : null;
        $draw = $this->getDrawForText ( $font, $size, $color, $opacity, $underColor );
        if (!$draw) {
            $this->_im = null;
            return false;
        }
        if ($place !== null) {
            $watermarkWH = $this->_im->queryfontmetrics ( $draw, $text );
            switch ($place) {
                case self::PLACE_NORTHWEST : break;
                case self::PLACE_NORTHEAST :
                    $x = intval( $this->_sourceWidth - ($watermarkWH ['textWidth'] + $x) ); break;
                case self::PLACE_CENTER    :
                    $x = ( int ) ($this->_sourceWidth - $watermarkWH ['textWidth']) / 2;
                    $y = ( int ) ($this->_sourceHeight - $watermarkWH ['textHeight']) / 2; break;
                case self::PLACE_SOUTHWEST :
                    $y = intval( $this->_sourceHeight - ($watermarkWH ['textHeight']+$y) ); break;
                default :
                    $x = intval( $this->_sourceWidth - ($watermarkWH ['textWidth'] + $x) );
                    $y = intval( $this->_sourceHeight - ($watermarkWH ['textHeight'] + $y) ); break;
            }
        }
        if ($this->_sourceType == self::TYPE_GIF) { // 处理gif
            $this->_im = $this->_im->coalesceimages();
            $boolean = true;
            foreach ($this->_im as $frame) {
                $flag = $frame->annotateimage($draw, $x, $y, $angle, $text);
                if (!$flag) {
                    $boolean = false;
                    $this->_im = null;
                    $this->_error = '处理图片出错';
                    break;
                }
            }
            return $boolean;
        } else {
            return $this->_im->annotateimage($draw, $x, $y, $angle, $text);
            // TODO 不知道为什么,在ubuntu 32位系统上没有解决中文字乱码的问题.真想不明白背景色也没有用
        }

        // 还有下面的方法:
        // $draw->setGravity(Imagick::GRAVITY_SOUTHEAST); //设置水印位置
        // (特别注意了,原生态的打水印的位置很好用哦)
        // $draw->annotation(0, 0, 'xiqiyanyan.com');
        // $canvas->drawImage($draw);
    }   
    
    /**
     * 添加图片水印 
     * 有个别水印图片打不漂亮;貌似对jpg图片打出来还不错
     * @see Lib_Image_Abstract::watermarkImage()
     * @param string $watermarkPath 水印图片(最好是透明背景的png图片)
     * @param string $place 水印位置;具体对应参数如下(可参见常量)
     *         northwest            northeast 
     *                     center
     *         southwest            southeast
     * @param integer $x 水印位置 ; x(水平坐标轴)轴偏移量
     * @param integer $y 水印位置 ; y(垂直坐标轴)轴偏移量
     * @param integer $alpha 水印透明度。取值0(全透明)-100(完全不透明) ;默认52:半透明
     * @param integer $angle 水印图片旋转角度  TODO
     * @return boolean
     */
    public function watermarkImage($watermarkPath, $place = 'southeast', $x = 18, $y = 18, $alpha = 52, $angle = 0) {
        if (!is_file($watermarkPath)) {
            $this->_error = '水印文件不存在';
            $this->_im = null;
            return false;
        }
        if (!$this->_isExistIm()) {
            return false;
        }
        try {
            $watermark = new Imagick();
            $watermark->readImage($watermarkPath);
            $alpha = $alpha/100; 
            $watermark->setImageOpacity($alpha); // 设置透明度,不知道为什么这里如果设了透明度,有些png水印打出来的图片就不漂亮了
            // 在ubuntu 64 位上还是一样
            $watermarkW = $watermark->getimagewidth();
            $watermarkH = $watermark->getimageheight();
            switch ($place) {
                case self::PLACE_NORTHWEST : break;
                case self::PLACE_NORTHEAST : $x = $this->_sourceWidth-($watermarkW+$x); break;
                case self::PLACE_CENTER    : $x = intval(($this->_sourceWidth-$watermarkW)/2); 
                                               $y = intval(($this->_sourceHeight-$watermarkH)/2); break;
                case self::PLACE_SOUTHWEST : $y = $this->_sourceHeight-($watermarkH+$y); break;
                case self::PLACE_SOUTHEAST : $x = $this->_sourceWidth-($watermarkW+$x);
                                               $y = $this->_sourceHeight-($watermarkH+$y);break;
                default : $x = $this->_sourceWidth-($watermarkW+$x); $y = $this->_sourceHeight-($watermarkH+$y); break;
            }
            $compose = $watermark->getImageCompose();
            // 方法一
            //return $this->_im->compositeimage($watermark, $compose, $x, $y);
            // 方法二
            $draw = new ImagickDraw();
            $draw->composite($compose, $x, $y, $watermarkW, $watermarkH, $watermark);
            if ($this->_sourceType == self::TYPE_GIF) {
                $this->_im = $this->_im->coalesceImages();
                $flag = true;
                foreach ($this->_im as $frame) {
                    $boolean = $frame->drawImage($draw);
                    if (!$boolean) {
                        $flag = false;
                        $this->_im = null;
                        $this->_error = '添加水印出错!';
                        break;
                    }
                }
                return $flag;
            }
            return $this->_im->drawImage($draw);            
        } catch (Exception $e) {
            $this->_error = '处理水印图片出错';
            $this->_im = null;
            return false;
        }
    }

    /**
     * 写入图片(gif动画也可以写入)
     * @param string $targetPath 目标路径(只能是绝对路径)
     * @param boolean $flag  是否覆盖已存在的图片;默认true:覆盖;false:不覆盖
     * @return boolean
     */
    public function write($targetPath = null, $flag = true) { // 貌似实现抽象方法时,参数个数只能多,不能少(可能也是php的bug,不会报错),且前面的参数的默认值需一致
        if ($targetPath != null) {
            $this->_targetPath = str_replace('\\', '/', $targetPath);
        }
        if ($this->_targetPath == null) {
        	$this->_error = '生成图片的目标路径不能为空';
        	return false;
        }
        if (!$this->_isExistIm()) {
        	return false;
        }
        // 下面检测路径是否有写的权限,和创建没有的文件夹
        $directory = pathinfo($this->_targetPath, PATHINFO_DIRNAME); // pathinfo 默认返回所有文件路径信息; 这里返回文件夹信息(返回目录部分)
        $boolean = $this->createdDirectory($directory);
        if (!$boolean) {
        	return false;
        }
        // 下面判断是否覆盖已有的文件,已存在是否有写权限
        if (is_file($this->_targetPath)) {
        	if ($flag) {
        		if (!is_writeable($this->_targetPath)) {
        			$this->_error = '图片文件 ' . $this->_targetPath . ' 已存在且不可写!无法保存图片文件!';
        			return false;
        		}
        	} else {
        		$this->_error = '目标文件已存在';
        		return false;
        	}
        }
        // 判断已存在的目录是否可写
        $dir = pathinfo($this->_targetPath, PATHINFO_DIRNAME); // pathinfo 默认返回所有文件路径信息; 这里返回文件夹信息(返回目录部分)
        if (!is_writable($dir)) {
        	$this->_error = '目录 ' . $dir . ' 不可写!无法保存图片!';
        	return false;
        }
        // 是否是支持的文件类型
        $ext = strtolower(pathinfo($this->_targetPath, PATHINFO_EXTENSION)); // 图片类型
        if (!in_array('.' . $ext, $this->_allowExt)) {
        	$this->_error = '不支持的图片文件格式,无法保存图片;只支持 ' . join('、', $this->_allowExt) . ' 格式的图片';
        	return false;
        }
        // 写入图片
        if ($this->_sourceType == self::TYPE_GIF) { // gif 类型
        	// 如果目标路径图片的类型和源图片不一致,需要进行重命名处理
        	$flag = false;
        	$ext = strrchr($this->_targetPath, '.');
        	if (strtolower($ext) != '.' . self::TYPE_GIF) {
        		$flag = true;
        		$oldFileName = $this->_targetPath;
        		$this->_targetPath = str_replace($ext, '.' . self::TYPE_GIF, $this->_targetPath);
        	}
            $boolean = $this->_im->writeImages($this->_targetPath, true);
            if ($boolean) {
            	if ($flag) { // 重命名
            		if (file_exists($this->_targetPath)) { // 这句多余的判断
                        if (rename($this->_targetPath, $oldFileName)) {
                        	$this->_targetPath = $oldFileName;
                        	return true;
                        } else {
                        	$this->_error = '无法重命名文件';
                        	return false;
                        }
            		}
            	}
            	return true;
            } else { 
            	$this->_error = '写入文件出错';
            	return false;
            }
        } else { // 其他类型
            if ($this->_sourceType != self::TYPE_BMP) {
                $this->_im->setImageCompressionQuality($this->_quality); // 设置图片质量
                // 图片质量 (只对jpg和png有用,取值0-100,jpg 值越大质量越好文件越大,png 反之,不过png影响不大,貌似png有问题,这里最好不要传,默认88就好)
            }
            return $this->_im->writeImage($this->_targetPath); // Write the image to disk
        }
    }
    
    /**
     * 输出图像到浏览器
     * @see Lib_Image_Abstract::show()
     */
    public function show() {
        switch ($this->_sourceType) {
            case self::TYPE_GIF  : $imgType = 'image/gif'; break;
            case self::TYPE_JPEG : 
            case self::TYPE_JPG  : $imgType = 'image/jpeg'; break;
            case self::TYPE_BMP  : $imgType = 'image/bmp'; break;
            default : $imgType = 'image/png'; break;
        }
        header('Content-Type:' . $imgType);
        if ($this->_sourceType == self::TYPE_GIF) {
            echo $this->_im->getimagesblob();
        } else {
            echo $this->_im->getimageblob();
        }
    }
    
    /**
     * 水平翻转(左右翻转)或垂直翻转(上下翻转)
     * 支持gif图片
     * @see Lib_Image_Abstract::rotateHV()
     * @param string $hv 默认H:水平翻转;V:垂直翻转
     * @return boolean
     */
    public function rotateHV($hv = 'H') {
        if (!$this->_isExistIm()) {
            return false;
        }
        if ($this->_sourceType == self::TYPE_GIF) {
            $this->_im = $this->_im->coalesceImages(); // 确保每帧的宽度和高度一致
            $boolean = true;
            foreach ($this->_im as $frame) {
                $flag = $this->_rotate($frame, $hv);
                if (!$flag) {
                    $boolean = false;
                    break;
                }
                //$frame->setImagePage($frame->getImageWidth(), $frame->getImageHeight(), 0, 0);
            }
            if ($boolean) {
                return true;
            } else {
                $this->_im = null;
                return false;
            }
            return true;
        }
        return $this->_rotate($this->_im, $hv);
    }
    
    /**
     * 水平翻转(左右翻转)或垂直翻转(上下翻转)
     * @param Imagick $im
     * @param string $hv
     * @return boolean
     */
    private function _rotate(&$im, $hv) {
        if (self::ROTATE_H == $hv) {// 水平翻转
            $boolean = $im->flopImage();
        } elseif(self::ROTATE_V == $hv) {// 垂直翻转
            $boolean = $im->flipImage();
        } else {
            $this->_error = '参数错误';
            $this->_im = null;
            return false;
        }
        if ($boolean) {
            return true;
        } else {
            $this->_error = '翻转失败';
            $this->_im = null;
            return false;
        }
    }  
    
    /**
     * 任意角度旋转图片
     * @see Lib_Image_Abstract::rotate()
     * @param integer $angle 旋转角度,正数顺时针,负数逆时针
     * @param string $color 如果旋转后有空的地方用什么颜色填充,默认全透明(要想透明,文件类型必须为png,不然就成黑色了)
     * 可以为颜色单词,如:white或pink;可以为字符串,如:#FFF或#FFF000
     * @return boolean
     */
    public function rotate($angle, $color = 'transparent') {
        if (!$this->_isExistIm()) {
            return false;
        }
        return $this->_im->rotateImage(new ImagickPixel($color), $angle); // 其实 new ImagickPixel() 建的是黑色背景到图片,并不是透明色
    }
    
    /**
     * 等比例缩放图片后进行裁剪,即生成指定大小的图片,多余部分进行裁剪
     * @see Lib_Image_Abstract::resize()
     * @param integer $width 目标图片的宽(如果目标宽和高只传一个【另一个传null或0】将按等比例缩放)
     * @param integer $height 目标图片的高(如果目标宽和高只传一个【另一个传null或0】将按等比例缩放)
     * @param string $tooWideCutPosition 如果缩率图的宽大于目标宽,进行裁剪的位置,取值见常量。默认center:居中裁剪;west:居左裁剪;east:居右裁剪
     * @param string $tooHighCutPosition 如果高超出设定值,需要从哪个位置开始裁剪,取值见常量PLACE_NORTH等。默认center:居中;north:上面;south:下面;
     * @return boolean
     */
    public function resize($width, $height, $tooWideCutPosition = 'center', $tooHighCutPosition = 'center') {
        if (!$this->_isExistIm()) {
            return false;
        }
        $width = (int) $width;
        $height = (int) $height;
        if ($width < 0 || $height < 0) {
            $this->_error = '目标宽或高不能小于0';
            $this->_im = null;
            return false;
        }
        if (!$width && !$height) {
            return true;
        }
        if (!$width || !$height) { // 只传入了宽或高
            return $this->thumbnail($width, $height);
        }
        
        // 方法一:先缩略,后裁剪
        /* $ratio = $this->getProportionality($this->_sourceWidth, $this->_sourceHeight, $width, $height, 'small');
        if (!$ratio) {
            return false;
        }
        $newWidth = floor($this->_sourceWidth*$ratio);
        $newHeight = floor($this->_sourceHeight*$ratio);
        $boolean = $this->thumbnail($newWidth, $newHeight);
        if (!$boolean) {
            return false;
        }//return true;
        $x = 0;
        $y = 0;
        if ($width < $newWidth) { // 宽多了
            switch ($tooWideCutPosition) {
                case self::PLACE_EAST: $x = (int) ($newWidth-$width); break;
                case self::PLACE_WEST: break;
                default : $x = (int) ($newWidth-$width)/2; break;
            }
        }
        if ($height < $newHeight) { // 高多了
            switch ($tooHighCutPosition) {
                case self::PLACE_NORTH : break;
                case self::PLACE_SOUTH : $y = (int) ($newHeight-$height); break;
                default : $y = (int) ($newHeight-$height)/2; break;
            }
        }//var_dump($x);var_dump($y);exit;
        return $this->crop($width, $height, $x, $y); */
        
        // 方法二:先裁剪,后缩略
        $cutX = 0;
        $cutY = 0;
        $cutW = $this->_sourceWidth;
        $cutH = $this->_sourceHeight;
        if ($this->_sourceWidth*$height > $this->_sourceHeight*$width) { // 需裁宽
            $cutW = intval($this->_sourceHeight*$width/$height);
        } else { // 需裁高
            $cutH = intval($this->_sourceWidth*$height/$width);
        }
        switch ($tooWideCutPosition) {
            case self::PLACE_WEST : break;
            case self::PLACE_EAST : $cutX = (int) ($this->_sourceWidth-$cutW); break;
            default: $cutX = (int) ($this->_sourceWidth-$cutW)/2; break;
        }
        switch ($tooHighCutPosition) {
            case self::PLACE_NORTH: break;
            case self::PLACE_SOUTH: $cutY = intval($this->_sourceHeight-$cutH); break;
            default : $cutY = intval(($this->_sourceHeight-$cutH)/2); break;
        }
        $boolean = $this->crop($cutW, $cutH, $cutX, $cutY);
        if ($boolean) {
            
        } else {
            return false;
        }
        return $this->thumbnail($width, $height);
        //convert /home/xiqiyanyan/www/phpBase/img/ddd.jpg -gravity east -crop 300X300+0+0 +repage /home/xiqiyanyan/www/phpBase/img/west.png
        //$convert = "convert $sourcePath -crop {$cropW}X{$cropH}+{$cropX}+{$cropY} +repage $targetPath";
        //$str = "convert $targetPath -coalesce -thumbnail {$width}X{$height} -layers optimize $targetPath";
    }
    
    /**
     * 获取文字的描绘对象
     * @param string $font 字体名称或字体路径
     * @param integer $size 字体大小
     * @param string | ImagickPixel $color 字颜色
     * @param float $opacity 文字的透明度,取值范围0(全透明)-1(不透明)
     * @param string | ImagickPixel $underColor 字的背景颜色
     * @return ImagickDraw | false
     */
    public function getDrawForText($font = null, $size = 8, $color = 'transparent', $opacity = 0.58, $underColor = null) {
        $draw = new ImagickDraw ();
        // $draw->setGravity(Imagick::GRAVITY_CENTER);
        // 特别注意这里了,如果这里设置了文字水印的位置的话,那么在其写入别到文件时就会起作用,且其他设置的坐标都没有用
        if ($font !== null) {
            if (is_file($font)) {
                $draw->setfont ( $font );
            } else {
                $this->_error = '字体文件不存在';
                return false;
            }
        }
        $draw->setfontsize ( $size );
        $draw->setFillColor ( $color );
        $draw->setfillopacity ( $opacity ); // 貌似和这个是一样的: $draw->setFillAlpha(0.5);
        if ($underColor !== null) {
            $draw->settextundercolor ( $underColor );
        }
        // $draw->settextalignment(2); //文字对齐方式,2为居中
        return $draw;
    }
    
    /**
     * 等比例缩略图,留空的地方用其他颜色填充(这个函数貌似运行很慢,要1秒钟)   ( 特别注意了, 这里因为需求不大所以就没有改,这个还不能用)
     * TODO GIF动画考虑
     * @param string $source 源图片
     * @param string $target 目标图片
     * @param integer $width 缩略图的长 Define width and height of the thumbnail
     * @param integer $height 缩略图的宽
     * @param mixed $color 颜色 (默认白色)。 这个参数可以传入如下形式的参数:
     *         string 'pink'
     *         string '#FFF'
     *         object new ImagickPixel('red');
     * @return boolean
     */
    public function thumbnailAndStuffColour($width, $height, $color = 'white') {
        $this->thumbnail($width, $height, true); // 等比例缩放
        $im = new Imagick (); // Instanciate and read the image in
        $im->newimage ( $width, $height, $color, 'png' ); // 按照缩略图大小创建一个有颜色的图片 .  pink : 粉红, red:红色,gray:灰色
        //$im->newimage ( $width, $height, $color, 'jpg' ); // 这里的$color可以等于rgba('255(红)','255(绿)','255(蓝)','透明度(0完全透明-127不透明)')
        // 实践证明,无法新建一个半透明背景的图片,只能为0时,全透明,为正数时,不透明
        $geometry = $this->_im->getImageGeometry (); // 取得缩略图的实际大小
        $x = ($width - $geometry ['width']) / 2; // 计算合并坐标
        $y = ($height - $geometry ['height']) / 2;
        $im->compositeImage ( $this->_im, Imagick::COMPOSITE_OVER, $x, $y ); // 合并两图片。 貌似和composite方法一样
        $this->_im = $im;
        return true;
    }
    
    /**
     * 添加一个边框
     * @param integer $leftRight 左右边框宽度
     * @param integer $topBottom 上下边框宽度
     * @param string $color 边框颜色;取值可以为: rgb(255,255,0) 或 '#FF00FF' 或 'white/red' 或 cmyk(100,100,100,10)
     * @return boolean
     */
    public function border($leftRight, $topBottom, $color = 'rgba(220,220,220,127)') { // 透明度貌似在这里没有用
        //$pixel = new ImagickPixel();
        //$pixel->setcolor($color);
        //$color = new ImagickPixel($color);
        return $this->_im->borderimage($color, $leftRight, $topBottom);
        //$this->_im->raiseimage(8, 8, 8, 8, 0);//加半透明边框 ; 
        //哈哈,这个真可以加一个半透明的边框,这个是在里面加了个类似突起的线框, 最后一个参数(boolean)是凸线还是凹线
    }
    
    /**
     * 批量生成某个文件夹下某一种类型图片的缩略图
     * TODO GIF动画
     * @param string $sourcePath
     *            源文件夹路径
     * @param string $targetPath
     *            目标文件夹路径 (注意如果保存在同一个目录下,运行两遍就有可能翻倍哦)
     * @param integer $width
     *            缩略图宽 (注意宽或高 一个都不能为零)
     * @param integer $height
     *            缩略图高
     * @param string $type
     *            图片类型,如:jpg,png等 (注意:linux对大小写敏感)
     * @param boolean $isScale
     *            是否等比例缩放,true(默认):是; false:否
     */
    public function batchThumbnail($sourcePath, $targetPath, $width, $height, $type = 'png', $isScale = true) {
        $sourcePath = $this->formatPath ( $sourcePath );
        $targetPath = $this->formatPath ( $targetPath );
        $sourcePath = $sourcePath . '*.' . $type;
        $images = new Imagick ( glob ( $sourcePath ) ); 
        // array glob(string $pattern[, int $flags]) // 寻找与模式匹配的文件路径
        $i = 0;
        foreach ( $images as $image ) {
            $image->thumbnailImage ( $width, $height, $isScale );
            $savePath = $targetPath . ++ $i . '.' . $type;
            $image->writeImage ( $savePath );
        }
    }
    
    /**
     * 对比度调节 (这个用得也不多,所以没有调,还不能用)
     * TODO
     * @param string $srcPath
     *            需要调整对比度的源图片
     * @param string $dstPath
     *            调整后保存的路径(处理后的目标图片存储位置)
     * @param boolean $sharpen
     *            所否增强对比度,默认true:增加对比度,false:减少对比度;
     *            貌似这里传0-9的数字没有什么用,这里的对比度所通过多次调用才能达到你想要到效果
     * @param boolean $apply
     *            作用区域; 默认false:全局作用,true:局部作用;全局作用时,后面到参数(宽、高、x、y)都没有用
     * @param integer $width
     *            局部作用宽
     * @param integer $height
     *            局部作用高
     * @param integer $x
     *            局部作用到坐标轴x
     * @param integer $y
     *            局部作用到坐标轴y
     * @return boolean
     */
    public function contrast($srcPath, $dstPath, $sharpen = true, $apply = false, $width = 0, $height = 0, $x = 0, $y = 0) {
        $this->readImage ( $srcPath );
        if ($apply) {
            $region = $this->getimageregion ( $width, $height, $x, $y ); // 获取图片的局部块
            $region->contrastimage ( $sharpen );
            $this->compositeImage ( $region, $region->getImageCompose (), $x, $y );
            $region->destroy ();
        } else {
            $this->contrastimage ( $sharpen );
        }
        return $this->writeImage ( $dstPath );
    }
    
    /**
     * 合并两张图片(把图二合并到图一来) (ImageMagick 有个奇怪的问题,第一次运行会有点慢)
     * TODO GIF动画
     * @param string $onePath
     *            需要合并的图片一
     * @param string $twoPath
     *            需要合并的图片二
     * @param string $dstPath
     *            合并后的保存地址
     * @param integer $x
     *            合并坐标轴x
     * @param integer $y
     *            合并坐标轴y
     * @return boolean
     */
    public function join($onePath, $twoPath, $dstPath, $x = 0, $y = 0) {
        $im1 = new Imagick ();
        $im1->readimage ( $onePath );
        $im2 = new Imagick ( $twoPath );
        $im2->setimageformat ( 'png' );
        $composite = $im2->getImageCompose ();
        $im1->compositeimage ( $im2, $composite, $x, $y );
        $im2->destroy ();
        return $im1->writeImage ( $dstPath );
    }

    /**
     * jpg质量压缩 (此函数在安全模式下不能运行)
     * 对其他类型到图片压缩率没有什么作用
     * @param string $src 源图片
     * @param string $dst 目标图片
     * @param integer $quality 质量(压缩比率) (后证实压缩率对gif毫无影响; 对png有一点影响,不过默认就好)
     */
    public function zip($src, $dst, $quality = 88) {
        exec("convert -quality {$quality} {$src} {$dst}");
    }
    
    /**
     * 将字符串生成图片
     * 此函数依赖 getDrawForText 函数
     * TODO 继续优化
     * @param string $text 需要生成图片的文字 (如果文字中有中文,那么就要用中文字体,不然有乱码)
     * @param mixed $color 文字颜色;可以如:'#FFF'; 'red'; 'rgb(0,0,255)';透明度在这里也是没有用的
     * @param integer $size 文字大小
     * @param string $font 字体;格式如: /home/bear/msyh.ttf
     * @param float $opacity 文字透明度,取值0-1;默认1:不透明; 0:全透明
     * @param integer $angle 文字角度
     * @param string $underColor 文字背景颜色,默认null:无   TODO ubuntu 32位上没有成功
     * @param string $background 画布颜色, transparent 透明
     * @return boolean
     */
    public function text($text, $color = 'black', $size = 8, $font = null, $opacity = 1, $underColor = null, $background = 'transparent') {
        $draw = $this->getDrawForText($font, $size, $color, $opacity, $underColor);
        $this->_im = new Imagick();
        //$im->setImageFormat('png');
        $properties = $this->_im->queryFontMetrics($draw, $text);
        $this->_im->newimage(intval($properties['textWidth']+15), intval($properties['textHeight']+15), new ImagickPixel($background));
        // 不能建一个半透明的图层,只能全透明和不透明
        $x = 7;
        $y = 32;
        return $this->_im->annotateImage($draw, $x, $y, 0, $text); // $angle 第三个参数是文字旋转角度, TODO
    }
    
    	 	
    

    
    
    	 	// 下面5个方法, 后面只有resize02修改过,可以用,其他的不能用
    	 	/**
    	 	* 缩小图片尺寸(缩略图)
    	 	* @param string $sourcePath 待处理的图片
    	 	* @param string $targetPath 保存处理后图片的路径
    	 	* @param integer $width 处理后图片尺寸的宽度(单位px)
    	 	* @param integer $height 处理后图片尺寸的高度(单位px)
    	 	* @param boolean $isCrop 是否裁剪图片;默认false:不裁剪图片;true:裁剪图片
    	 	* @return boolean
    	 	*/
    	 	//     public function resize01($sourcePath, $targetPath, $width, $height, $isCrop = false) {
    	 	//     	//$this->readImageBlob($sourcePath); // 从一个二进制到字符串中读取图像
    	 	//     	$this->readImage($sourcePath);
    	 	//     	$w = $this->getImageWidth();
    	 	//     	$h = $this->getImageHeight();
    	 	//     	if ($w > $width || $h > $height) {
    	 	//     		if ($isCrop) {
    	 	//     			$this->cropThumbnailImage($width, $height);
    	 	//     		} else {
    	 	//     			$this->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1, true);
    	 	//     		}
    	 	//     	}
    	 	//     	//$image = $this->getImageBlob();
    	 	//         return $this->writeImage($targetPath);
    	 	//     }
    
    	 	/**
    	 	* 缩小图片尺寸(缩略图) (特别注意了:后经测试,这个是最值得用的,速度和压缩都平衡) (jpg比png压缩率大很多)
    	 	* @param string $sourcePath 待处理的图片
    	 	* @param integer $width 处理后图片尺寸的宽度(单位px)
    	 	* @param integer $height 处理后图片尺寸的高度(单位px)
    	 	* @param string $targetPath 保存处理后图片的路径
    	 	* @param boolean $isCrop 是否裁剪图片;默认false:不裁剪图片;true:裁剪图片(会生成你给定的宽和高,居中裁剪)
    	 	* @param integer $quality 压缩质量 (很奇怪的是如果保存为png时,$quality为90时快些,但文件大很多)
    	 	* @return boolean
    	 	*/
    	 	//     public function resize02($sourcePath, $width, $height, $targetPath = null, $isCrop = false, $quality = 88) {
    	 	//     	$this->_im = new Imagick();
    	 	//     	$this->_im->readImage($sourcePath);
    	 	//     	$w = $this->_im->getImageWidth();
    	 	//     	$h = $this->_im->getImageHeight();
    	 	//     	$widthRate = $w/$width;
    	 	//     	$heightRate = $h/$height;
    	 	//     	$inputWidth = $width;
    	 	//     	$inputHeight = $height;
    	 	//     	if ($widthRate > 1 || $heightRate > 1) {
    	 	//     		if ($isCrop) {
    	 	//     			if ($widthRate > $heightRate) {
    	 	//     				$width = $w/$heightRate;
    	 	//     			} else {
    	 	//     				$height = $h/$widthRate;
    	 	//     			}
    	 	//     		} else {
    	 	//     			if ($widthRate > $heightRate) {
    	 	//     				$height = $h/$widthRate;
    	 	//     			} else {
    	 	//     				$width = $w/$heightRate;
    	 	//     			}
    	 	//     		}
    	 	//     		$this->_im->resizeImage($width, $height, Imagick::FILTER_CATROM, 1, false);
    	 	//     		if ($isCrop) {
    	 	 //     			if ($width > $inputWidth) {
    	 	 //     				$this->_im->cropImage($inputWidth, $height, ($width-$inputWidth)/2, 0);
    	 	 //     			} else if ($height > $inputHeight) {
    	 	 //     				$this->_im->cropImage($width, $inputHeight, 0, ($height-$inputHeight)/2);
    	 	//     			}
    	 	//     		}
    	 	//     	}
    	 	//     	$this->_im->setImageFormat('jpeg');
    	 	//     	$this->_im->setImageCompression(Imagick::COMPRESSION_JPEG);
    	 	//         $this->_im->setImageCompressionQuality($quality);
    	 	//         $this->_im->stripImage(); // 去除Exif信息
    	 	//         return $this->writeImage($targetPath);
    	 	//     }
    
    	 	/**
    	 	* 缩小图片尺寸(缩略图)
    	 	* @param string $sourcePath 待处理的图片
    	 	* @param string $targetPath 保存处理后图片的路径
    	 	* @param integer $width 处理后图片尺寸的宽度(单位px)
    	 	* @param integer $height 处理后图片尺寸的高度(单位px)
    	 	 * @param boolean $isCrop 是否裁剪图片;默认false:不裁剪图片;true:裁剪图片
    	 	 * @return boolean
    	 	 */
    	 	 //     public function resize03($sourcePath, $targetPath, $width, $height, $isCrop = false){
    	 	 //     	$this->readImage($sourcePath);
    	 	 //     	$this->setImageCompression(imagick::COMPRESSION_JPEG);
    	 	//     	$this->setImageCompressionQuality(80);
    	 	//     	if ($isCrop) {
    	 	//     		$this->cropThumbnailImage($width, $height);
    	 	//     	} else {
    	 	//     		$this->resizeImage($width, $height, Imagick::FILTER_CATROM, 1, true);
    	 	//     	}
    	 	//     	$this->stripImage();
    	 	//     	return $this->writeImage($targetPath);
    	 	//     }
    
    	 	/**
    	 	* 缩小图片尺寸(缩略图)
    	 	* @param string $sourcePath 待处理的图片
    	 	* @param string $targetPath 保存处理后图片的路径
    	 	* @param integer $width 处理后图片尺寸的宽度(单位px)
    	 	* @param integer $height 处理后图片尺寸的高度(单位px)
    	 	* @param boolean $isCrop 是否裁剪图片;默认false:不裁剪图片;true:裁剪图片
    	 	* @return boolean
    	 	*/
    	 	//     public function resize04($sourcePath, $targetPath, $width, $height, $isCrop = false){
    	 	//     	$this->readImage($sourcePath);
    	 	//     	if ($isCrop) {
    	 	 //     		$this->cropThumbnailImage($width, $height);
    	 	 //     	} else {
    	 	 //     		$this->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1, true);
    	 	 //     	}
    	 	 //     	$this->setImageFormat('jpeg');
    	 	 //     	$this->setImageCompression(Imagick::COMPRESSION_JPEG);
    	 	//     	$a = $this->getImageCompressionQuality()*0.75;
    	 	//     	if ($a == 0) {
    	 	//     	    $a = 75;
    	 	//     	}
    	 	//     	$this->setImageCompressionQuality($a);
    	 	//     	$geo = $this->getImageGeometry(); // 取得图像的宽和高
    	 	//     	$this->thumbnailImage($geo['width'], $geo['height']);
    	 	//     	$this->stripImage();
    	 	//     	return $this->writeImage($targetPath);
    	 	//     }
    
    	 	/**
    	 	* 缩小图片尺寸(缩略图)
    	 	* @param string $sourcePath 待处理的图片
    	 	* @param string $targetPath 保存处理后图片的路径
    	 	* @param integer $width 处理后图片尺寸的宽度(单位px)
    	 	* @param integer $height 处理后图片尺寸的高度(单位px)
    	 	* @param boolean $isCrop 是否裁剪图片;默认false:不裁剪图片;true:裁剪图片
    	 	* @return boolean
    	 	*/
    	 	//     public function resize($sourcePath, $targetPath, $width, $height, $isCrop = false) {
    	 	//     	$this->readImage($sourcePath);
    	 	//     	$w = $this->getImageWidth();
    	 	//     	$h = $this->getImageHeight();
    	 	//     	if ($w > $width || $h > $height) {
    	 	//     		if ($isCrop) {
    	 	//     			$this->cropThumbnailImage($width, $height);
    	 	//     		} else {
    	 	//     			$this->resizeImage($width, $height, Imagick::FILTER_CATROM, 1, true);
    	 	//     		}
    	 	//     	}
    	 	//     	$this->setImageFormat('JPEG');
    	 	//     	$this->setImageCompression(Imagick::COMPRESSION_JPEG);
    	 	//     	$a = $this->getImageCompressionQuality() * 0.75;
    	 	//     	if ($a ==0) {
//     		$a = 75;
    	 	//     	}
    	 	//     	$this->setImageCompressionQuality($a);
    	 	//     	$this->stripImage();
    //     	return $this->writeImage($targetPath);
    //     }
        // 下面是对本此5个方法(图片压缩)的总结:
        // 1、压缩率尽可能的小,这个要和业务部门商量,找到一个平衡点。(请注意最后方法设置品质方法使用获取到当前图片的压缩率然后再取75%,如果当前图片压缩率为60%,如果使用$imagick->setImageCompressionQuality(80)方法将使图片压缩率提高至80%,这会使图片变大!!!)
        // 2、一定要移除图片的exif信息!!!!  这部分内容详情请查看 http://baike.baidu.com/view/22006.htm
        // 3、压缩尺寸使用Imagick::FILTER_CATROM方法对速度有一定的提升,图片本身的品质没有大的变化。
        // 4、$imagick->setImageFormat(‘JPEG’)也很给力。
       
    /**
     * 释放资源
     */
    public function __destruct() {
        if ($this->_im instanceof Imagick) {
            $this->_im->destroy();
        }
    }
    
    /**
     * 格式化路径,把所有的 \ 转化成 / , 并在最后加上 /
     * @param string $path
     * @return string
     */
    private function formatPath($path) {
        $path = str_replace ( '\\', '/', $path );
        if (substr ( $path, - 1 ) != '/') {
            $path = $path . '/';
        }
        return $path;
    }
        
	
}

调用方式:

                $sourcePath = ROOT_PATH . '/img/gif.gif.jpg';
		$targetPath = ROOT_PATH . '/img/new.png';
		$width = 130;
		$height = 280;
		$imagick = new Lib_Imagick();
		//$imagick->setSourcePath($sourcePath);
		$imagick->read($sourcePath);
		$imagick->gifThumbnail($width, $height, false);
		$boolean = $imagick->write($targetPath);
		if (!$boolean) {
		    var_dump($imagick->getError());
		}

转载请注明出处:http://maimengmei.com/blog.php?id=78,谢谢配合!请尊重别人的劳动成果,本文来自卖萌妹

标签: ImageMagick ; gd ;

93% 6% 欢迎顶踩!
        15 票                 1
顶 踩
看过本文的所有网友评论:
我也来评论几句:
验证码: 请输入右边图片上的字母或数字(不区分大小写);看不清,请直接点击图片即可换一张