關於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             $width:新的寬度
 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         $width: 左右邊框寬度
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之後一切正常,而且處理圖像的效能比之以前有了大幅提升

 

 

 

 

posted @ 2014-05-29 13:04  PHP群:223494678  阅读(4430)  评论(4编辑  收藏