Home  >  Article  >  php教程  >  關於imagick不得不說的一些事

關於imagick不得不說的一些事

WBOY
WBOYOriginal
2016-06-13 09:34:34756browse

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

 

 

 

 

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn