对图片进行加水印、裁剪、拉伸、放大缩小、高度或者宽度自适应这几个功能已能够满足非图片处理类的各类网站需求,本文分享的代码实现的也是以上几个基本功能,这几个独立的功能百度一下或者谷歌一下都可以找到现成的代码,这些代码好不好用?仁者见仁,智者见智,有的还是问题代码,所以关键要适合你做的项目。
先贴出源代码出来,下文再细讲每个用法。
001<?php
002
003/**
004 * 基于Imagick的图像处理类
005 * @author wupinglong
006
007 ImageImagick is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Lesser General Public License as published by
009 the Free Software Foundation;
010
011 * @relations http://www.lirengou.com, http://www.sinpe.com, http://www.wodezhan.cn
012 **/
013
014class ImageImagick {
015
016 // 源
017 private $source = array(
018 // 图片路径
019 'file' => null,
020 // 图片原句柄
021 'res' => null,
022 // 文件类型,如:jpg
023 'type' => null,
024 // mime类型
025 'mime' => null,
026 'width' => null,
027 'height' => null
028 );
029
030 // 目标
031 private $target;
032
033 public function __construct($src=null){
034
035 if(!empty($src) && is_readable($src)){
036
037 $res = new Imagick($src);
038
039 $ext = strtolower( $res->getImageFormat() );
040
041 $whxy = $res->getImagePage();
042
043 $this->source = array(
044 'res' => $res,
045 'file' => $src,
046 'mime' => $this->ext2mime($ext),
047 'type' => $ext,
048 'width' => $whxy['width'],
049 'height' => $whxy['height']
050 );
051
052 }
053 else{
054 $this->source = array(
055 'res' => new Imagick(),
056 'type' => 'png',
057 'width' => 1,
058 'height' => 1
059 );
060 }
061
062 $this->target = $this->source;
063
064 return $this;
065 }
066
067 /**
068 * 基于宽高比例的放大、缩小
069 *
070 * @param String $direction 基准边
071 * @param String $base 基准值
072 */
073 public function scale($direction, $base){
074
075 $s = &$this->target;
076
077 $direction = strtolower($direction);
078
079 // 基于宽度
080 if( $direction == 'x' ){
081 $w = is_numeric($base) && $base > 0 ? intval($base) : $s['width'];
082 //$scale = $base / $s['width'];
083 $h = 0;
084 }
085 // 基于高度
086 else{
087 $h = is_numeric($base) && $base > 0 ? intval($base) : $s['height'];
088 //$scale = $base / $s['height'];
089 $w = 0;
090 }
091
092 // 新尺寸
093 //$width = (int)( $s['width'] * $scale );
094 //$height = (int)( $s['height'] * $scale );
095
096 if( 'gif' == $s['type'] ) {
097
098 $res = $s['res']->coalesceImages();
099
100 do {
101 //$res->thumbnailImage($width, $height);
102 $res->scaleImage($w, $h);
103 } while ($res->nextImage());
104
105 $s['res'] = $res->deconstructImages();
106 }
107 else {
108 //$s['res']->thumbnailImage($width, $height);
109 $s['res']->scaleImage($w, $h);
110 }
111
112 $whxy = $s['res']->getImagePage();
113
114 $s['width'] = $whxy['width'];
115 $s['height'] = $whxy['height'];
116
117 return $this;
118 }
119
120 // 拉伸
121 public function stretch($width, $height){
122
123 $s = &$this->target;
124
125 if( 'gif' == $s['type'] ) {
126
127 $res = $s['res']->coalesceImages();
128
129 do {
130 $res->resizeImage( $width, $height, Imagick::FILTER_POINT, 1 );
131 } while ($res->nextImage());
132
133 $s['res'] = $res->deconstructImages();
134
135 }
136 else{
137
138 $s['res']->resizeImage($width, $height, Imagick::FILTER_POINT, 1);
139 }
140
141 $s['width'] = $width;
142 $s['height'] = $height;
143
144 return $this;
145 }
146
147 // 剪裁
148 public function crop($width, $height, $x=0, $y=0){
149
150 $s = &$this->target;
151
152 // 避免超出范围,获取内容为空时的异常
153 if( $x >=$s['width'] || $y >= $s['height'] ){
154 $res = $s['res'];
155 $res->clear();
156 $res->newImage( $width, $height, new ImagickPixel('transparent'), 'png' );
157 $res->setImageOpacity(0);
158
159 $draw = new ImagickDraw();
160
161 $draw->setFillColor( new ImagickPixel( '#ffffff' ) );
162 $draw->setStrokeColor( new ImagickPixel( '#cccccc' ) );
163 $draw->setStrokeWidth(3);
164 $draw->rectangle( 1, 1, $width-2, $height-2 );
165 $draw->setStrokeWidth(1);
166 $draw->line( 3, 3, $width-3, $height-3 );
167
168 $res->drawImage( $draw );
169
170 $draw->clear();
171 $draw->destroy();
172
173 unset($draw);
174
175 }
176 else{
177
178 if( 'gif' == $s['type'] ) {
179
180 $res = $s['res']->coalesceImages();
181
182 do {
183 $res->cropImage( $width, $height, $x, $y );
184 // 去掉画布空白
185 $res->setImagePage(0, 0, 0, 0);
186 } while ($res->nextImage());
187
188 $s['res'] = $res->deconstructImages();
189
190 }
191 else{
192 $s['res']->cropImage( $width, $height, $x, $y );
193 }
194
195 }
196
197 $s['width'] = $width;
198 $s['height'] = $height;
199
200 return $this;
201
202 }
203
204 // 缩略图,基于指定的宽度比例先裁剪,后再放大、缩小
205 public function thumb($width, $height){
206
207 $s = &$this->target;
208
209 if( 'gif' == $s['type'] ) {
210 foreach ( $s['res'] as $frame ) {
211 $p = $frame->getImagePage();
212 $frame->setImagePage( $s['width'], $s['height'], $p['x']/2, $p['y']/2 );
213 $frame->cropthumbnailImage( $width, $height );
214 $frame->setImagePage( 0, 0, 0, 0 );
215 }
216 }
217 else{
218 $s['res']->cropThumbnailImage($width, $height);
219 }
220
221 $s['width'] = $width;
222 $s['height'] = $height;
223
224 return $this;
225 }
226
227 // 适应
228 public function adapt($width, $height){
229
230 // 以宽为基准
231 if( $this->target['width'] / $this->target['height'] >= $width / $height ){
232 $base = $width;
233 $direction = 'x';
234 }
235 // 以高为基准
236 else{
237 $base = $height;
238 $direction = 'y';
239 }
240
241 return $this->scale($direction, $base);
242 }
243
244 // 文本
245 public function text($text, $font, $color='#ffffff', $size=12, $shadow=false, $ox=0, $oy=0, $deep=1 ){
246
247 $t = &$this->target;
248
249 $this->destroy();
250
251 $res = new Imagick();
252
253 $draw = new ImagickDraw();
254
255 $draw->setFont($font);
256
257 $draw->setFontSize($size);
258
259 $draw->setTextAntialias(true);
260
261 $metrics = $res->queryFontMetrics($draw, $text);
262
263 $draw->setFillColor(new ImagickPixel($color));
264
265 $draw->annotation($ox, $metrics['ascender'] + $oy, $text);
266
267 $w = $metrics['textWidth'] + 12;
268 $h = $metrics['textHeight'];
269
270 $res->newImage( $w, $h, new ImagickPixel('transparent'), 'png' );
271
272 $res->setImageOpacity(0);
273
274 $res->drawImage($draw);
275
276 // 阴影
277 if($shadow){
278 $shadow = $res->clone();
279 $shadow->modulateImage(0, 100, 100);
280 $res->compositeImage($shadow, imagick::COMPOSITE_OVERLAY, $deep, $deep);
281 }
282
283 $t['res'] = $res;
284 $t['type'] = 'png';
285 $t['mime'] = 'image/png';
286 $t['width'] = $w;
287 $t['height'] = $h;
288
289 $draw->clear();
290 $draw->destroy();
291
292 unset($draw);
293
294 return $this;
295 }
296
297 // 水印
298 public function water($mask, $pos='right-bottom', $alpha=0.6, $ox=5, $oy=5 ){
299
300 $s = &$this->target;
301
302 $iw = $s['width'];
303 $ih = $s['height'];
304
305 $mt = $mask->getTarget();
306
307 $mw = $mt['width'] + $ox;
308 $mh = $mt['height'] + $oy;
309
310 // 重新计算水印的大小
311 if( $mw > $iw || $mh > $ih ){
312
313 if( ($iw/$ih) > ($mw/$mh) ){
314 // 缩小
315 $scaleh = ( $mh > $ih ? $ih : $mh ) / 3;
316 $scalew = intval( $scaleh * $mw / $mh);
317 }
318 else{
319 // 缩小
320 $scalew = ( $mw > $iw ? $iw : $mw ) / 3;
321 $scaleh = intval( $scalew * $mh / $mw);
322 }
323
324 // 拉伸
325 $mask->stretch( $scalew, $scaleh );
326 }
327
328 $m = $mask->getTarget();
329
330 // 起始坐标
331 $xy = $this->getXY( $pos, $s['width'], $s['height'], $m['width'], $m['height'], $ox, $oy );
332
333 $mim = $m['res'];
334
335 if( 'png'==$m['type'] ){
336 $mim->evaluateImage(Imagick::EVALUATE_MULTIPLY, $alpha, Imagick::CHANNEL_ALPHA);
337 }
338 else{
339 $mim->setImageOpacity($alpha);
340 }
341
342 if( 'gif' == $s['type'] ) {
343
344 $res = $s['res']->coalesceImages();
345
346 foreach ( $res as $frame ) {
347 $frame->compositeImage( $mim, Imagick::COMPOSITE_OVER, $xy['x'], $xy['y'] );
348 }
349
350 $s['res'] = $res->optimizeImageLayers();
351
352 }
353 else{
354 $s['res']->compositeImage( $mim, Imagick::COMPOSITE_OVER, $xy['x'], $xy['y'] );
355 }
356
357 return $this;
358
359 }
360
361 // 输出到浏览器
362 public function display($quality=null){
363
364 $t = $this->target;
365
366 $res = $t['res'];
367
368 if(is_null($quality)){
369 $quality = 100;
370 }
371
372 $res->setImageFormat($t['type']);
373
374 $res->setCompressionQuality($quality);
375
376 header( 'Content-Type: '.$this->ext2mime($t['type']) );
377
378 echo $res->getImagesBLOB();
379
380 $this->destroy();
381
382 exit;
383 }
384
385 // 保存
386 public function save($file=null, $quality=null){
387
388 $t = &$this->target;
389
390 $res = $t['res'];
391
392 if(is_null($quality)){
393 $quality = 100;
394 }
395
396 $res->setImageFormat($t['type']);
397
398 $res->setCompressionQuality($quality);
399
400 // 创建白色的背景
401 if( !in_array($t['type'], array('gif','png')) ){
402 $bg = new Imagick();
403 $bg->newImage( $t['width'], $t['height'], new ImagickPixel('#ffffff'), $t['type'] );
404 $res->compositeImage( $bg, imagick::COMPOSITE_DSTOVER, 0, 0 );
405 $bg->clear();
406 $bg->destroy();
407 }
408
409 if( 'gif' == $t['type'] ){
410 $res->writeImages( $file ? $file : $t['file'], true);
411 }
412 else{
413 $res->writeImage($file ? $file : $t['file']);
414 }
415
416 return $this;
417 }
418
419 //
420 public function getTarget($key=null){
421
422 $d = $this->target;
423
424 if(!empty($key) && array_key_exists( $key, $d ) ){
425 return $d[ $key ];
426 }
427 else{
428 return $d;
429 }
430 }
431
432 //
433 public function getSource($key=null){
434
435 $d = $this->source;
436
437 if(!empty($key) && array_key_exists( $key, $d ) ){
438 return $d[ $key ];
439 }
440 else{
441 return $d;
442 }
443 }
444
445 // 设置目标格式
446 public function setTargetType($format){
447
448 $t = &$this->target;
449
450 $t['file'] = str_replace( $t['type'], $format, $t['file']);
451
452 $t['type'] = $format;
453
454 return $this;
455 }
456
457 // 释放资源,一个连串处理的最后调用
458 public function destroy(){
459
460 $sim = $this->source['res'];
461
462 if( $sim && is_resource($sim) ) {
463 $sim->clear();
464 $sim->destroy();
465 }
466
467 $tim = $this->target['res'];
468
469 if( $tim && is_resource($tim) ) {
470 $tim->clear();
471 $tim->destroy();
472 }
473 }
474
475 public function __destruct() {
476 $this->destroy();
477 }
478
479 private function ext2mime($ext){
480
481 static $mime = array(
482 'png' => 'image/png',
483 'jpe' => 'image/jpeg',
484 'jpeg' => 'image/jpeg',
485 'jpg' => 'image/jpeg',
486 'gif' => 'image/gif',
487 'bmp' => 'image/bmp',
488 'ico' => 'image/vnd.microsoft.icon',
489 'tiff' => 'image/tiff',
490 'tif' => 'image/tiff',
491 'svg' => 'image/svg+xml',
492 'svgz' => 'image/svg+xml',
493 );
494
495 if( !array_key_exists( $ext, $mime ) ){
496 trigger_error( "mime undefined. ($ext)", E_USER_ERROR );
497 }
498
499 return $mime[$ext];
500
501 }
502
503 // 水印位置
504 private function getXY($pos, $iw, $ih, $mw, $mh, $ox=5, $oy=5 ){
505
506 switch($pos){
507
508 case 'right-bottom':
509 // 右下
510 $x = $iw - $mw - $ox;
511 $y = $ih - $mh - $oy;
512 break;
513
514 case 'center':
515 // 左上
516 $x = ( $iw - $mw ) / 2;
517 $y = ( $ih - $mh ) / 2;
518 break;
519
520 case 'left-top':
521 // 左上
522 $x = $ox;
523 $y = $oy;
524 break;
525
526 case 'left-bottom':
527 // 左下
528 $x = $ox;
529 $y = $ih - $mh - $oy;
530 break;
531
532 case 'right-top':
533 // 右上
534 $x = $iw - $mw - $ox;
535 $y = $oy;
536 break;
537
538 default:
539 // 默认将水印放到右下,偏移指定像素
540 $x = $iw - $mw - $ox;
541 $y = $ih - $mh - $oy;
542 break;
543 }
544
545 return array('x'=>$x, 'y'=>$y);
546 }
547
548}
549
550?>
具体用法
每个图片对应一个ImageImagick实例,支持链式操作,能够实现多个处理效果的叠加。项目中使用时,可以作为第三方类库来用,涵盖的几个功能介绍如下:
- scale($direction,$base)
基于原图宽高比例的缩放,direction=x|y,适合于页面显示区域宽或者高一边固定,另一边需要自动延展的场合,比如现在比较流行的瀑布流页面。
可以这样使用:
01<?php
02/**
03 * 示例
04 * 将原图宽度调整为200px并保持原宽高比例后,直接显示在浏览器
05 *
06 */
07
08vendor('ImageImagick')->ImageImagick('e.gif')->scale('x',200)->display(); // 注:vendor('ImageImagick')->ImageImagick('e.gif')为偶在项目中第三方类库的导入方法
09
10// 或
11
12include ....
13
14$iim = new ImageImagick('e.gif');
15
16$iim->scale('x',200)->display(); // 显示
17
18?>
- crop($width, $height, $x=0, $y=0)
基于指定的宽度先做裁剪,如果宽度或者高度有一个不足以按指定的值进行裁剪时,则按指定的宽高比例进行缩小裁剪,然后再将裁剪的内容放大到指定的尺寸,图像不会变形,但像素会变化,一般应用于大图的缩略图生成,代码示例参照上面(以下同)。
- stretch( $width, $height )
整图按指定尺寸进行拉伸、挤压,即图片会充满width*height尺寸的区域,
- adapt($width, $height)
容器自适应,比如上传图片时,指定了一个div作为预览窗,并且固定了div的宽度和高度,这个时候图像需要完整显示在预览窗内且宽高比不变,该方法自动判别图像是用宽度还是高度去适应容器的大小。
- thumb($width, $height)
裁剪,按指定起始坐标和宽高的裁剪,裁剪结果可能小于指定的宽度和高度。适合于交互式的裁剪功能实现,即由用户交互指定了裁剪的坐标和大小,比如头像的裁剪。
- text($text, $font, $color=’#ffffff’, $size=12, $shadow=false, $ox=0, $oy=0, $deep=1 )
- water($mask, $pos=’right-bottom’, $alpha=0.6, $ox=5, $oy=5 )
- display($quality=null)
- save($file=null, $quality=null)