zoukankan      html  css  js  c++  java
  • 關於imagick不得不說的一些事

        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
    

        接下來我們針對上述兩個狀況分別提出解決辦法:

    狀況一的解決辦法如下:

      1 /**
      2     Imagick圖像處理類
      3     用法:
      4         //引入Imagick物件
      5         if(!defined('CLASS_IMAGICK')){require(Inc.'class_imagick.php');}
      6         $Imagick=new class_imagick();
      7         $Imagick->open('a.gif');
      8         $Imagick->resize_to(100,100,'scale_fill');
      9         $Imagick->add_text('1024i.com',10,20);
     10         $Imagick->add_watermark('1024i.gif',10,50);
     11         $Imagick->save_to('x.gif');
     12         unset($Imagick);
     13 /**/
     14 
     15 define('CLASS_IMAGICK',TRUE);
     16 class class_imagick{
     17     private $image=null;
     18     private $type=null;
     19 
     20     // 構造
     21     public function __construct(){}
     22 
     23     // 析構
     24     public function __destruct(){
     25         if($this->image!==null){$this->image->destroy();}
     26     }
     27 
     28     // 載入圖像
     29     public function open($path){
     30         if(!file_exists($path)){
     31             $this->image=null;
     32             return ;
     33         }
     34         $this->image=new Imagick($path);
     35         if($this->image){
     36             $this->type=strtolower($this->image->getImageFormat());
     37         }
     38         $this->image->stripImage();
     39         return $this->image;
     40     }
     41 
     42     /**
     43         圖像裁切
     44     /**/
     45     public function crop($x=0,$y=0,$width=null,$height=null){
     46         if($width==null) $width=$this->image->getImageWidth()-$x;
     47         if($height==null) $height=$this->image->getImageHeight()-$y;
     48         if($width<=0 || $height<=0) return;
     49 
     50         if($this->type=='gif'){
     51             $image=$this->image;
     52             $canvas=new Imagick();
     53 
     54             $images=$image->coalesceImages();
     55             foreach($images as $frame){
     56                 $img=new Imagick();
     57                 $img->readImageBlob($frame);
     58                 $img->cropImage($width,$height,$x,$y);
     59 
     60                 $canvas->addImage($img);
     61                 $canvas->setImageDelay($img->getImageDelay());
     62                 $canvas->setImagePage($width,$height,0,0);
     63             }
     64 
     65             $image->destroy();
     66             $this->image=$canvas;
     67         }else{
     68             $this->image->cropImage($width,$height,$x,$y);
     69         }
     70     }
     71 
     72     /**
     73         更改圖像大小
     74         參數:
     75             $新的寬度
     76             $height:新的高度
     77             $fit: 適應大小
     78                 'force': 把圖像強制改為$width X $height
     79                 'scale': 按比例在$width X $height內縮放圖片,結果不完全等於$width X $height
     80                 'scale_fill':按比例在$width X $height內縮放圖片,沒有像素的地方填充顏色$fill_color=array(255,255,255)(红,绿,蓝,透明度[0不透明-127全透明])
     81                 其他:智能模式,縮放圖片並從正中裁切$width X $height的大小
     82         注意:
     83             $fit='force','scale','scale_fill'時輸出完整圖像
     84             $fit=圖像方位時輸出指定位置部份的圖像
     85         字母與圖像的對應關係如下:
     86             north_west   north   north_east
     87             west         center        east
     88             south_west   south   south_east
     89     /**/
     90     public function resize_to($width=100,$height=100,$fit='center',$fill_color=array(255,255,255,0)){
     91         switch($fit){
     92         case 'force':
     93             if($this->type=='gif'){
     94                 $image=$this->image;
     95                 $canvas=new Imagick();
     96 
     97                 $images=$image->coalesceImages();
     98                 foreach($images as $frame){
     99                     $img=new Imagick();
    100                     $img->readImageBlob($frame);
    101                     $img->thumbnailImage($width,$height,false);
    102 
    103                     $canvas->addImage($img);
    104                     $canvas->setImageDelay($img->getImageDelay());
    105                 }
    106                 $image->destroy();
    107                 $this->image=$canvas;
    108             }else{
    109                 $this->image->thumbnailImage($width,$height,false);
    110             }
    111             break;
    112         case 'scale':
    113             if($this->type=='gif'){
    114                 $image=$this->image;
    115                 $images=$image->coalesceImages();
    116                 $canvas=new Imagick();
    117                 foreach($images as $frame){
    118                     $img=new Imagick();
    119                     $img->readImageBlob($frame);
    120                     $img->thumbnailImage($width,$height,true);
    121 
    122                     $canvas->addImage($img);
    123                     $canvas->setImageDelay($img->getImageDelay());
    124                 }
    125                 $image->destroy();
    126                 $this->image=$canvas;
    127             }else{
    128                 $this->image->thumbnailImage($width,$height,true);
    129             }
    130             break;
    131         case 'scale_fill':
    132             $size=$this->image->getImagePage();
    133             $src_width=$size['width'];
    134             $src_height=$size['height'];
    135 
    136             $x=0;
    137             $y=0;
    138 
    139             $dst_width=$width;
    140             $dst_height=$height;
    141 
    142             if($src_width*$height > $src_height*$width){
    143                 $dst_height=intval($width*$src_height/$src_width);
    144                 $y=intval(($height-$dst_height)/2);
    145             }else{
    146                 $dst_width=intval($height*$src_width/$src_height);
    147                 $x=intval(($width-$dst_width)/2);
    148             }
    149 
    150             $image=$this->image;
    151             $canvas=new Imagick();
    152 
    153             $color='rgba('.$fill_color[0].','.$fill_color[1].','.$fill_color[2].','.$fill_color[3].')';
    154             if($this->type=='gif'){
    155                 $images=$image->coalesceImages();
    156                 foreach($images as $frame){
    157                     $frame->thumbnailImage($width,$height,true);
    158 
    159                     $draw=new ImagickDraw();
    160                     $draw->composite($frame->getImageCompose(),$x,$y,$dst_width,$dst_height,$frame);
    161 
    162                     $img=new Imagick();
    163                     $img->newImage($width,$height,$color,'gif');
    164                     $img->drawImage($draw);
    165 
    166                     $canvas->addImage($img);
    167                     $canvas->setImageDelay($img->getImageDelay());
    168                     $canvas->setImagePage($width,$height,0,0);
    169                 }
    170             }else{
    171                 $image->thumbnailImage($width,$height,true);
    172 
    173                 $draw=new ImagickDraw();
    174                 $draw->composite($image->getImageCompose(),$x,$y,$dst_width,$dst_height,$image);
    175 
    176                 $canvas->newImage($width,$height,$color,$this->get_type());
    177                 $canvas->drawImage($draw);
    178                 $canvas->setImagePage($width,$height,0,0);
    179             }
    180             $image->destroy();
    181             $this->image=$canvas;
    182             break;
    183         default:
    184             $size=$this->image->getImagePage();
    185             $src_width=$size['width'];
    186             $src_height=$size['height'];
    187 
    188             $crop_x=0;
    189             $crop_y=0;
    190 
    191             $crop_w=$src_width;
    192             $crop_h=$src_height;
    193 
    194             if($src_width*$height > $src_height*$width){
    195                 $crop_w=intval($src_height*$width/$height);
    196             }else{
    197                 $crop_h=intval($src_width*$height/$width);
    198             }
    199 
    200             switch($fit){
    201                 case 'north_west':
    202                     $crop_x=0;
    203                     $crop_y=0;
    204                     break;
    205                 case 'north':
    206                     $crop_x=intval(($src_width-$crop_w)/2);
    207                     $crop_y=0;
    208                     break;
    209                 case 'north_east':
    210                     $crop_x=$src_width-$crop_w;
    211                     $crop_y=0;
    212                     break;
    213                 case 'west':
    214                     $crop_x=0;
    215                     $crop_y=intval(($src_height-$crop_h)/2);
    216                     break;
    217                 case 'center':
    218                     $crop_x=intval(($src_width-$crop_w)/2);
    219                     $crop_y=intval(($src_height-$crop_h)/2);
    220                     break;
    221                 case 'east':
    222                     $crop_x=$src_width-$crop_w;
    223                     $crop_y=intval(($src_height-$crop_h)/2);
    224                     break;
    225                 case 'south_west':
    226                     $crop_x=0;
    227                     $crop_y=$src_height-$crop_h;
    228                     break;
    229                 case 'south':
    230                     $crop_x=intval(($src_width-$crop_w)/2);
    231                     $crop_y=$src_height-$crop_h;
    232                     break;
    233                 case 'south_east':
    234                     $crop_x=$src_width-$crop_w;
    235                     $crop_y=$src_height-$crop_h;
    236                     break;
    237                 default:
    238                     $crop_x=intval(($src_width-$crop_w)/2);
    239                     $crop_y=intval(($src_height-$crop_h)/2);
    240             }
    241 
    242             $image=$this->image;
    243             $canvas=new Imagick();
    244 
    245             if($this->type=='gif'){
    246                 $images=$image->coalesceImages();
    247                 foreach($images as $frame){
    248                     $img=new Imagick();
    249                     $img->readImageBlob($frame);
    250                     $img->cropImage($crop_w,$crop_h,$crop_x,$crop_y);
    251                     $img->thumbnailImage($width,$height,true);
    252 
    253                     $canvas->addImage($img);
    254                     $canvas->setImageDelay($img->getImageDelay());
    255                     $canvas->setImagePage($width,$height,0,0);
    256                 }
    257             }else{
    258                 $image->cropImage($crop_w,$crop_h,$crop_x,$crop_y);
    259                 $image->thumbnailImage($width,$height,true);
    260                 $canvas->addImage($image);
    261                 $canvas->setImagePage($width,$height,0,0);
    262             }
    263             $image->destroy();
    264             $this->image=$canvas;
    265         }
    266     }
    267 
    268     /**
    269         添加圖片水印
    270         參數:
    271             $path:水印圖片(包含完整路徑)
    272             $x,$y:水印座標
    273     /**/
    274     public function add_watermark($path,$x=0,$y=0){
    275         $watermark=new Imagick($path);
    276         $draw=new ImagickDraw();
    277         $draw->composite($watermark->getImageCompose(),$x,$y,$watermark->getImageWidth(),$watermark->getimageheight(),$watermark);
    278 
    279         if($this->type=='gif'){
    280             $image=$this->image;
    281             $canvas=new Imagick();
    282             $images=$image->coalesceImages();
    283             foreach($image as $frame){
    284                 $img=new Imagick();
    285                 $img->readImageBlob($frame);
    286                 $img->drawImage($draw);
    287 
    288                 $canvas->addImage($img);
    289                 $canvas->setImageDelay($img->getImageDelay());
    290             }
    291             $image->destroy();
    292             $this->image=$canvas;
    293         }else{
    294             $this->image->drawImage($draw);
    295         }
    296     }
    297 
    298     /**
    299         添加文字水印
    300         參數:
    301             $text:水印文字
    302             $x,$y:水印座標
    303     /**/
    304     public function add_text($text,$x=0,$y=0,$angle=0,$style=array()){
    305         $draw=new ImagickDraw();
    306         if(isset($style['font'])) $draw->setFont($style['font']);
    307         if(isset($style['font_size'])) $draw->setFontSize($style['font_size']);
    308         if(isset($style['fill_color'])) $draw->setFillColor($style['fill_color']);
    309         if(isset($style['under_color'])) $draw->setTextUnderColor($style['under_color']);
    310 
    311         if($this->type=='gif'){
    312             foreach($this->image as $frame){
    313                 $frame->annotateImage($draw,$x,$y,$angle,$text);
    314             }
    315         }else{
    316             $this->image->annotateImage($draw,$x,$y,$angle,$text);
    317         }
    318     }
    319 
    320     /**
    321         圖片存檔
    322         參數:
    323             $path:存檔的位置和新的檔案名
    324     /**/
    325     public function save_to($path){
    326         $this->image->stripImage();
    327         switch($this->type){
    328         case 'gif':
    329             $this->image->writeImages($path,true);
    330             return ;
    331         case 'jpg':
    332         case 'jpeg':
    333             $this->image->setImageCompressionQuality($_ENV['ImgQ']);
    334             $this->image->writeImage($path);
    335             return ;
    336         case 'png':
    337             $flag = $this->image->getImageAlphaChannel();
    338 
    339             // 如果png背景不透明則壓縮
    340             if(imagick::ALPHACHANNEL_UNDEFINED == $flag or imagick::ALPHACHANNEL_DEACTIVATE == $flag){
    341                 $this->image->setImageType(imagick::IMGTYPE_PALETTE);
    342                 $this->image->writeImage($path);
    343             }else{
    344                 $this->image->writeImage($path);
    345             }unset($flag);
    346             return ;
    347         default:
    348             $this->image->writeImage($path);
    349             return ;
    350         }
    351     }
    352 
    353     // 直接輸出圖像到螢幕
    354     public function output($header=true){
    355         if($header) header('Content-type: '.$this->type);
    356         echo $this->image->getImagesBlob();
    357     }
    358 
    359     /**
    360         建立縮小圖
    361         $fit為真時,將保持比例並在$width X $height内產生縮小圖
    362     /**/
    363     public function thumbnail($width=100,$height=100,$fit=true){$this->image->thumbnailImage($width,$height,$fit);}
    364 
    365     /**
    366         給圖像添加邊框
    367         $ 左右邊框寬度
    368         $height: 上下邊框寬度
    369         $color: 顏色
    370     /**/
    371     public function border($width,$height,$color='rgb(220,220,220)'){
    372         $color=new ImagickPixel();
    373         $color->setColor($color);
    374         $this->image->borderImage($color,$width,$height);
    375     }
    376 
    377     //取得圖像寬度
    378     public function get_width(){$size=$this->image->getImagePage();return $size['width'];}
    379 
    380     //取得圖像高度
    381     public function get_height(){$size=$this->image->getImagePage();return $size['height'];}
    382 
    383     // 設置圖像類型
    384     public function set_type($type='png'){$this->type=$type;$this->image->setImageFormat($type);}
    385 
    386     // 取得圖像類型
    387     public function get_type(){return $this->type;}
    388 
    389     public function blur($radius,$sigma){$this->image->blurImage($radius,$sigma);} // 模糊
    390     public function gaussian_blur($radius,$sigma){$this->image->gaussianBlurImage($radius,$sigma);} // 高斯模糊
    391     public function motion_blur($radius,$sigma,$angle){$this->image->motionBlurImage($radius,$sigma,$angle);} // 運動模糊
    392     public function radial_blur($radius){$this->image->radialBlurImage($radius);} // 徑向模糊
    393     public function add_noise($type=null){$this->image->addNoiseImage($type==null?imagick::NOISE_IMPULSE:$type);} // 添加噪點
    394     public function level($black_point,$gamma,$white_point){$this->image->levelImage($black_point,$gamma,$white_point);} // 調整色階
    395     public function modulate($brightness,$saturation,$hue){$this->image->modulateImage($brightness,$saturation,$hue);} // 調整亮度,飽和度,色調
    396     public function charcoal($radius,$sigma){$this->image->charcoalImage($radius,$sigma);} // 素描效果
    397     public function oil_paint($radius){$this->image->oilPaintImage($radius);} // 油畫效果
    398     public function flop(){$this->image->flopImage();} // 水平翻轉
    399     public function flip(){$this->image->flipImage();} // 垂直翻轉
    400 }
    View Code

    狀況二的解決辦法如下:

    首先用/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之後一切正常,而且處理圖像的效能比之以前有了大幅提升

  • 相关阅读:
    LeetCode算法题-Trim a Binary Search Tree(Java实现)
    LeetCode算法题-Non-decreasing Array(Java实现)
    LeetCode算法题-Image Smoother(Java实现)
    Node.js 官方文档中文版
    jade 网上看到一个不错的demo 分享 一下 链接
    jade 的 考古
    标题党 数据抓取与管理
    最近面试 有人问 sqlite 用过么 sqlite 不是 嵌入式的 开发 么 难道最近还 web开发 了?
    嗯 想写个demo 苦于没数据
    客户端 jQuery 跨端口 调用 node 服务端
  • 原文地址:https://www.cnblogs.com/see7di/p/3758879.html
Copyright © 2011-2022 走看看