• 技术文章 >php教程 >php手册

    浅谈php扩展imagick

    2016-06-13 09:34:28原创292
    PHP建图通常都用GD库,因为是内置的不需要在服务器上额外安装插件,所以用起来比较省心,但是如果你的程序主要的功能就是处理图像,那麼就不建议用GD了,因为GD不但低效能而且能力也比较弱,佔用的系统资源也颇多,另外GD的creatfrom也有bug,而imagick却是一个很好的替代品,为此最近把我的一个项目由GD改成了imagick,但是改完之后出现了一些状况在此分享给大家.

    首先说一下我这边出现的状况:

    状况一:需要重写图像操作class

    状况二:imagick多线程时会导致cpu使用率暴增到100%

    在此顺便提一下imagick在centos6.4的安装方法:

    1、安装ImageMagick

    复制代码 代码如下:


    wget http://soft.vpser.net/web/imagemagick/ImageMagick-6.7.1-2.tar.gz
    tar zxvf ImageMagick-6.7.1-2.tar.gz
    cd ImageMagick-6.7.1-2/
    ./configure --prefix=/usr/local/imagemagick --disable-openmp
    make && make install
    ldconfig

    测试ImageMagick是否可以正常运行:

    复制代码 代码如下:


    /usr/local/imagemagick/bin/convert -version

    2、安装PHP扩展:imagick

    复制代码 代码如下:


    wget http://pecl.php.net/get/imagick-3.0.1.tgz
    tar zxvf imagick-3.0.1.tgz
    cd imagick-3.0.1/
    /usr/local/php/bin/phpize
    ./configure --with-php-config=/usr/local/php/bin/php-config --with-imagick=/usr/local/imagemagick
    make && make install
    ldconfig
    vi /usr/local/php/etc/php.ini
    添加:extension = "imagick.so"

    重启lnmp

    复制代码 代码如下:


    /root/lnmp reload

    接下来我们针对上述两个状况分别提出解决办法:

    状况一的解决办法如下:

    复制代码 代码如下:


    /**
    Imagick图像处理类
    用法:
    //引入Imagick物件
    if(!defined('CLASS_IMAGICK')){require(Inc.'class_imagick.php');}
    $Imagick=new class_imagick();
    $Imagick->open('a.gif');
    $Imagick->resize_to(100,100,'scale_fill');
    $Imagick->add_text('1024i.com',10,20);
    $Imagick->add_watermark('1024i.gif',10,50);
    $Imagick->save_to('x.gif');
    unset($Imagick);
    /**/
    define('CLASS_IMAGICK',TRUE);
    class class_imagick{
    private $image=null;
    private $type=null;
    // 构造
    public function __construct(){}
    // 析构
    public function __destruct(){
    if($this->image!==null){$this->image->destroy();}
    }
    // 载入图像
    public function open($path){
    if(!file_exists($path)){
    $this->image=null;
    return ;
    }
    $this->image=new Imagick($path);
    if($this->image){
    $this->type=strtolower($this->image->getImageFormat());
    }
    $this->image->stripImage();
    return $this->image;
    }
    /**
    图像裁切
    /**/
    public function crop($x=0,$y=0,$width=null,$height=null){
    if($width==null) $width=$this->image->getImageWidth()-$x;
    if($height==null) $height=$this->image->getImageHeight()-$y;
    if($width<=0 || $height<=0) return;
    if($this->type=='gif'){
    $image=$this->image;
    $canvas=new Imagick();
    $images=$image->coalesceImages();
    foreach($images as $frame){
    $img=new Imagick();
    $img->readImageBlob($frame);
    $img->cropImage($width,$height,$x,$y);
    $canvas->addImage($img);
    $canvas->setImageDelay($img->getImageDelay());
    $canvas->setImagePage($width,$height,0,0);
    }
    $image->destroy();
    $this->image=$canvas;
    }else{
    $this->image->cropImage($width,$height,$x,$y);
    }
    }
    /**
    更改图像大小
    参数:
    $width:新的宽度
    $height:新的高度
    $fit: 适应大小
    'force': 把图像强制改为$width X $height
    'scale': 按比例在$width X $height内缩放图片,结果不完全等於$width X $height
    'scale_fill':按比例在$width X $height内缩放图片,没有像素的地方填充顏色$fill_color=array(255,255,255)(红,绿,蓝,透明度[0不透明-127全透明])
    其他:智能模式,缩放图片并从正中裁切$width X $height的大小
    注意:
    $fit='force','scale','scale_fill'时输出完整图像
    $fit=图像方位时输出指定位置部份的图像
    字母与图像的对应关系如下:
    north_west north north_east
    west center east
    south_west south south_east
    /**/
    public function resize_to($width=100,$height=100,$fit='center',$fill_color=array(255,255,255,0)){
    switch($fit){
    case 'force':
    if($this->type=='gif'){
    $image=$this->image;
    $canvas=new Imagick();
    $images=$image->coalesceImages();
    foreach($images as $frame){
    $img=new Imagick();
    $img->readImageBlob($frame);
    $img->thumbnailImage($width,$height,false);
    $canvas->addImage($img);
    $canvas->setImageDelay($img->getImageDelay());
    }
    $image->destroy();
    $this->image=$canvas;
    }else{
    $this->image->thumbnailImage($width,$height,false);
    }
    break;
    case 'scale':
    if($this->type=='gif'){
    $image=$this->image;
    $images=$image->coalesceImages();
    $canvas=new Imagick();
    foreach($images as $frame){
    $img=new Imagick();
    $img->readImageBlob($frame);
    $img->thumbnailImage($width,$height,true);
    $canvas->addImage($img);
    $canvas->setImageDelay($img->getImageDelay());
    }
    $image->destroy();
    $this->image=$canvas;
    }else{
    $this->image->thumbnailImage($width,$height,true);
    }
    break;
    case 'scale_fill':
    $size=$this->image->getImagePage();
    $src_width=$size['width'];
    $src_height=$size['height'];
    $x=0;
    $y=0;
    $dst_width=$width;
    $dst_height=$height;
    if($src_width*$height > $src_height*$width){
    $dst_height=intval($width*$src_height/$src_width);
    $y=intval(($height-$dst_height)/2);
    }else{
    $dst_width=intval($height*$src_width/$src_height);
    $x=intval(($width-$dst_width)/2);
    }
    $image=$this->image;
    $canvas=new Imagick();
    $color='rgba('.$fill_color[0].','.$fill_color[1].','.$fill_color[2].','.$fill_color[3].')';
    if($this->type=='gif'){
    $images=$image->coalesceImages();
    foreach($images as $frame){
    $frame->thumbnailImage($width,$height,true);
    $draw=new ImagickDraw();
    $draw->composite($frame->getImageCompose(),$x,$y,$dst_width,$dst_height,$frame);
    $img=new Imagick();
    $img->newImage($width,$height,$color,'gif');
    $img->drawImage($draw);
    $canvas->addImage($img);
    $canvas->setImageDelay($img->getImageDelay());
    $canvas->setImagePage($width,$height,0,0);
    }
    }else{
    $image->thumbnailImage($width,$height,true);
    $draw=new ImagickDraw();
    $draw->composite($image->getImageCompose(),$x,$y,$dst_width,$dst_height,$image);
    $canvas->newImage($width,$height,$color,$this->get_type());
    $canvas->drawImage($draw);
    $canvas->setImagePage($width,$height,0,0);
    }
    $image->destroy();
    $this->image=$canvas;
    break;
    default:
    $size=$this->image->getImagePage();
    $src_width=$size['width'];
    $src_height=$size['height'];
    $crop_x=0;
    $crop_y=0;
    $crop_w=$src_width;
    $crop_h=$src_height;
    if($src_width*$height > $src_height*$width){
    $crop_w=intval($src_height*$width/$height);
    }else{
    $crop_h=intval($src_width*$height/$width);
    }
    switch($fit){
    case 'north_west':
    $crop_x=0;
    $crop_y=0;
    break;
    case 'north':
    $crop_x=intval(($src_width-$crop_w)/2);
    $crop_y=0;
    break;
    case 'north_east':
    $crop_x=$src_width-$crop_w;
    $crop_y=0;
    break;
    case 'west':
    $crop_x=0;
    $crop_y=intval(($src_height-$crop_h)/2);
    break;
    case 'center':
    $crop_x=intval(($src_width-$crop_w)/2);
    $crop_y=intval(($src_height-$crop_h)/2);
    break;
    case 'east':
    $crop_x=$src_width-$crop_w;
    $crop_y=intval(($src_height-$crop_h)/2);
    break;
    case 'south_west':
    $crop_x=0;
    $crop_y=$src_height-$crop_h;
    break;
    case 'south':
    $crop_x=intval(($src_width-$crop_w)/2);
    $crop_y=$src_height-$crop_h;
    break;
    case 'south_east':
    $crop_x=$src_width-$crop_w;
    $crop_y=$src_height-$crop_h;
    break;
    default:
    $crop_x=intval(($src_width-$crop_w)/2);
    $crop_y=intval(($src_height-$crop_h)/2);
    }
    $image=$this->image;
    $canvas=new Imagick();
    if($this->type=='gif'){
    $images=$image->coalesceImages();
    foreach($images as $frame){
    $img=new Imagick();
    $img->readImageBlob($frame);
    $img->cropImage($crop_w,$crop_h,$crop_x,$crop_y);
    $img->thumbnailImage($width,$height,true);
    $canvas->addImage($img);
    $canvas->setImageDelay($img->getImageDelay());
    $canvas->setImagePage($width,$height,0,0);
    }
    }else{
    $image->cropImage($crop_w,$crop_h,$crop_x,$crop_y);
    $image->thumbnailImage($width,$height,true);
    $canvas->addImage($image);
    $canvas->setImagePage($width,$height,0,0);
    }
    $image->destroy();
    $this->image=$canvas;
    }
    }
    /**
    添加图片水印
    参数:
    $path:水印图片(包含完整路径)
    $x,$y:水印座标
    /**/
    public function add_watermark($path,$x=0,$y=0){
    $watermark=new Imagick($path);
    $draw=new ImagickDraw();
    $draw->composite($watermark->getImageCompose(),$x,$y,$watermark->getImageWidth(),$watermark->getimageheight(),$watermark);
    if($this->type=='gif'){
    $image=$this->image;
    $canvas=new Imagick();
    $images=$image->coalesceImages();
    foreach($image as $frame){
    $img=new Imagick();
    $img->readImageBlob($frame);
    $img->drawImage($draw);
    $canvas->addImage($img);
    $canvas->setImageDelay($img->getImageDelay());
    }
    $image->destroy();
    $this->image=$canvas;
    }else{
    $this->image->drawImage($draw);
    }
    }
    /**
    添加文字水印
    参数:
    $text:水印文字
    $x,$y:水印座标
    /**/
    public function add_text($text,$x=0,$y=0,$angle=0,$style=array()){
    $draw=new ImagickDraw();
    if(isset($style['font'])) $draw->setFont($style['font']);
    if(isset($style['font_size'])) $draw->setFontSize($style['font_size']);
    if(isset($style['fill_color'])) $draw->setFillColor($style['fill_color']);
    if(isset($style['under_color'])) $draw->setTextUnderColor($style['under_color']);
    if($this->type=='gif'){
    foreach($this->image as $frame){
    $frame->annotateImage($draw,$x,$y,$angle,$text);
    }
    }else{
    $this->image->annotateImage($draw,$x,$y,$angle,$text);
    }
    }
    /**
    图片存档
    参数:
    $path:存档的位置和新的档案名
    /**/
    public function save_to($path){
    $this->image->stripImage();
    switch($this->type){
    case 'gif':
    $this->image->writeImages($path,true);
    return ;
    case 'jpg':
    case 'jpeg':
    $this->image->setImageCompressionQuality($_ENV['ImgQ']);
    $this->image->writeImage($path);
    return ;
    case 'png':
    $flag = $this->image->getImageAlphaChannel();
    // 如果png背景不透明则压缩
    if(imagick::ALPHACHANNEL_UNDEFINED == $flag or imagick::ALPHACHANNEL_DEACTIVATE == $flag){
    $this->image->setImageType(imagick::IMGTYPE_PALETTE);
    $this->image->writeImage($path);
    }else{
    $this->image->writeImage($path);
    }unset($flag);
    return ;
    default:
    $this->image->writeImage($path);
    return ;
    }
    }
    // 直接输出图像到萤幕
    public function output($header=true){
    if($header) header('Content-type: '.$this->type);
    echo $this->image->getImagesBlob();
    }
    /**
    建立缩小图
    $fit为真时,将保持比例并在$width X $height内產生缩小图
    /**/
    public function thumbnail($width=100,$height=100,$fit=true){$this->image->thumbnailImage($width,$height,$fit);}
    /**
    给图像添加边框
    $width: 左右边框宽度
    $height: 上下边框宽度
    $color: 顏色
    /**/
    public function border($width,$height,$color='rgb(220,220,220)'){
    $color=new ImagickPixel();
    $color->setColor($color);
    $this->image->borderImage($color,$width,$height);
    }
    //取得图像宽度
    public function get_width(){$size=$this->image->getImagePage();return $size['width'];}
    //取得图像高度
    public function get_height(){$size=$this->image->getImagePage();return $size['height'];}
    // 设置图像类型
    public function set_type($type='png'){$this->type=$type;$this->image->setImageFormat($type);}
    // 取得图像类型
    public function get_type(){return $this->type;}
    public function blur($radius,$sigma){$this->image->blurImage($radius,$sigma);} // 模糊
    public function gaussian_blur($radius,$sigma){$this->image->gaussianBlurImage($radius,$sigma);} // 高斯模糊
    public function motion_blur($radius,$sigma,$angle){$this->image->motionBlurImage($radius,$sigma,$angle);} // 运动模糊
    public function radial_blur($radius){$this->image->radialBlurImage($radius);} // 径向模糊
    public function add_noise($type=null){$this->image->addNoiseImage($type==null?imagick::NOISE_IMPULSE:$type);} // 添加噪点
    public function level($black_point,$gamma,$white_point){$this->image->levelImage($black_point,$gamma,$white_point);} // 调整色阶
    public function modulate($brightness,$saturation,$hue){$this->image->modulateImage($brightness,$saturation,$hue);} // 调整亮度,饱和度,色调
    public function charcoal($radius,$sigma){$this->image->charcoalImage($radius,$sigma);} // 素描效果
    public function oil_paint($radius){$this->image->oilPaintImage($radius);} // 油画效果
    public function flop(){$this->image->flopImage();} // 水平翻转
    public function flip(){$this->image->flipImage();} // 垂直翻转
    }

    状况二的解决办法如下:

    首先用/usr/local/imagemagick/bin/convert -version指令查看一下输出内容是否已经开啟了多线程,Features:的值为空说明是单线程,如果Features:的值是openMP说明是多线程.imagick的多线程模式有一个bug,他会导致多核心的cpu使用率瞬间飆升到100所以一定要使用它的单线程模式才行.

    复制代码 代码如下:


    Version: ImageMagick 6.7.1-2 2014-05-29 Q16 http://www.imagemagick.org
    Copyright: Copyright (C) 1999-2011 ImageMagick Studio LLC
    Features:

    上边是我配置正确时显示的结果,如果没有配置正确会显示下边的结果

    复制代码 代码如下:


    Version: ImageMagick 6.7.1-2 2014-05-29 Q16 http://www.imagemagick.org
    Copyright: Copyright (C) 1999-2011 ImageMagick Studio LLC
    Features: openMP

    第一种结果是单线程模式,第二种结果是多线程模式,因为imagick的多线程模式有bug,所以如果您刚开始是用多线程模式安装的imagick那就必须要yum remove imagemagick将其卸载掉重新安装才行.

    经过重写class,重装imagick之后一切正常,而且处理图像的效能比之以前有了大幅提升

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:php imagick
    上一篇:php环境搭建(使用集成环境phpnow) 下一篇:利用谷歌 Translate API制作自己的翻译脚本
    Web大前端开发直播班

    相关文章推荐

    • web上存漏洞及原理分析、防范方法(安全文件上存方法)• 浅析php变量修饰符static的使用• PHP支持多种格式图片上传(支持jpg、png、gif)• 在Windows系统上安装PHP运行环境文字教程• PHP中函数内引用全局变量的方法
    1/1

    PHP中文网