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