PHP中基于Imagick实现图片的水印、剪裁、拉伸、放大缩小、框自适应

对图片进行加水印、裁剪、拉伸、放大缩小、高度或者宽度自适应这几个功能已能够满足非图片处理类的各类网站需求,本文分享的代码实现的也是以上几个基本功能,这几个独立的功能百度一下或者谷歌一下都可以找到现成的代码,这些代码好不好用?仁者见仁,智者见智,有的还是问题代码,所以关键要适合你做的项目。

先贴出源代码出来,下文再细讲每个用法。

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)
点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注