作者 王智

4

  1 +/vendor/
  2 +/thinkphp/
  3 +/composer.lock
  4 +/.idea/
  1 +language: php
  2 +
  3 +php:
  4 + - 5.4
  5 + - 5.5
  6 + - 5.6
  7 + - 7.0
  8 + - hhvm
  9 +
  10 +matrix:
  11 + allow_failures:
  12 + - php: 7.0
  13 + - php: hhvm
  14 +
  15 +before_script:
  16 + - composer self-update
  17 + - composer install --prefer-source --no-interaction --dev
  18 +
  19 +script: phpunit --coverage-clover=coverage.xml --configuration=phpunit.xml
  20 +
  21 +after_success:
  22 + - bash <(curl -s https://codecov.io/bash)
  1 + Apache License
  2 + Version 2.0, January 2004
  3 + http://www.apache.org/licenses/
  4 +
  5 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
  6 +
  7 + 1. Definitions.
  8 +
  9 + "License" shall mean the terms and conditions for use, reproduction,
  10 + and distribution as defined by Sections 1 through 9 of this document.
  11 +
  12 + "Licensor" shall mean the copyright owner or entity authorized by
  13 + the copyright owner that is granting the License.
  14 +
  15 + "Legal Entity" shall mean the union of the acting entity and all
  16 + other entities that control, are controlled by, or are under common
  17 + control with that entity. For the purposes of this definition,
  18 + "control" means (i) the power, direct or indirect, to cause the
  19 + direction or management of such entity, whether by contract or
  20 + otherwise, or (ii) ownership of fifty percent (50%) or more of the
  21 + outstanding shares, or (iii) beneficial ownership of such entity.
  22 +
  23 + "You" (or "Your") shall mean an individual or Legal Entity
  24 + exercising permissions granted by this License.
  25 +
  26 + "Source" form shall mean the preferred form for making modifications,
  27 + including but not limited to software source code, documentation
  28 + source, and configuration files.
  29 +
  30 + "Object" form shall mean any form resulting from mechanical
  31 + transformation or translation of a Source form, including but
  32 + not limited to compiled object code, generated documentation,
  33 + and conversions to other media types.
  34 +
  35 + "Work" shall mean the work of authorship, whether in Source or
  36 + Object form, made available under the License, as indicated by a
  37 + copyright notice that is included in or attached to the work
  38 + (an example is provided in the Appendix below).
  39 +
  40 + "Derivative Works" shall mean any work, whether in Source or Object
  41 + form, that is based on (or derived from) the Work and for which the
  42 + editorial revisions, annotations, elaborations, or other modifications
  43 + represent, as a whole, an original work of authorship. For the purposes
  44 + of this License, Derivative Works shall not include works that remain
  45 + separable from, or merely link (or bind by name) to the interfaces of,
  46 + the Work and Derivative Works thereof.
  47 +
  48 + "Contribution" shall mean any work of authorship, including
  49 + the original version of the Work and any modifications or additions
  50 + to that Work or Derivative Works thereof, that is intentionally
  51 + submitted to Licensor for inclusion in the Work by the copyright owner
  52 + or by an individual or Legal Entity authorized to submit on behalf of
  53 + the copyright owner. For the purposes of this definition, "submitted"
  54 + means any form of electronic, verbal, or written communication sent
  55 + to the Licensor or its representatives, including but not limited to
  56 + communication on electronic mailing lists, source code control systems,
  57 + and issue tracking systems that are managed by, or on behalf of, the
  58 + Licensor for the purpose of discussing and improving the Work, but
  59 + excluding communication that is conspicuously marked or otherwise
  60 + designated in writing by the copyright owner as "Not a Contribution."
  61 +
  62 + "Contributor" shall mean Licensor and any individual or Legal Entity
  63 + on behalf of whom a Contribution has been received by Licensor and
  64 + subsequently incorporated within the Work.
  65 +
  66 + 2. Grant of Copyright License. Subject to the terms and conditions of
  67 + this License, each Contributor hereby grants to You a perpetual,
  68 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  69 + copyright license to reproduce, prepare Derivative Works of,
  70 + publicly display, publicly perform, sublicense, and distribute the
  71 + Work and such Derivative Works in Source or Object form.
  72 +
  73 + 3. Grant of Patent License. Subject to the terms and conditions of
  74 + this License, each Contributor hereby grants to You a perpetual,
  75 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  76 + (except as stated in this section) patent license to make, have made,
  77 + use, offer to sell, sell, import, and otherwise transfer the Work,
  78 + where such license applies only to those patent claims licensable
  79 + by such Contributor that are necessarily infringed by their
  80 + Contribution(s) alone or by combination of their Contribution(s)
  81 + with the Work to which such Contribution(s) was submitted. If You
  82 + institute patent litigation against any entity (including a
  83 + cross-claim or counterclaim in a lawsuit) alleging that the Work
  84 + or a Contribution incorporated within the Work constitutes direct
  85 + or contributory patent infringement, then any patent licenses
  86 + granted to You under this License for that Work shall terminate
  87 + as of the date such litigation is filed.
  88 +
  89 + 4. Redistribution. You may reproduce and distribute copies of the
  90 + Work or Derivative Works thereof in any medium, with or without
  91 + modifications, and in Source or Object form, provided that You
  92 + meet the following conditions:
  93 +
  94 + (a) You must give any other recipients of the Work or
  95 + Derivative Works a copy of this License; and
  96 +
  97 + (b) You must cause any modified files to carry prominent notices
  98 + stating that You changed the files; and
  99 +
  100 + (c) You must retain, in the Source form of any Derivative Works
  101 + that You distribute, all copyright, patent, trademark, and
  102 + attribution notices from the Source form of the Work,
  103 + excluding those notices that do not pertain to any part of
  104 + the Derivative Works; and
  105 +
  106 + (d) If the Work includes a "NOTICE" text file as part of its
  107 + distribution, then any Derivative Works that You distribute must
  108 + include a readable copy of the attribution notices contained
  109 + within such NOTICE file, excluding those notices that do not
  110 + pertain to any part of the Derivative Works, in at least one
  111 + of the following places: within a NOTICE text file distributed
  112 + as part of the Derivative Works; within the Source form or
  113 + documentation, if provided along with the Derivative Works; or,
  114 + within a display generated by the Derivative Works, if and
  115 + wherever such third-party notices normally appear. The contents
  116 + of the NOTICE file are for informational purposes only and
  117 + do not modify the License. You may add Your own attribution
  118 + notices within Derivative Works that You distribute, alongside
  119 + or as an addendum to the NOTICE text from the Work, provided
  120 + that such additional attribution notices cannot be construed
  121 + as modifying the License.
  122 +
  123 + You may add Your own copyright statement to Your modifications and
  124 + may provide additional or different license terms and conditions
  125 + for use, reproduction, or distribution of Your modifications, or
  126 + for any such Derivative Works as a whole, provided Your use,
  127 + reproduction, and distribution of the Work otherwise complies with
  128 + the conditions stated in this License.
  129 +
  130 + 5. Submission of Contributions. Unless You explicitly state otherwise,
  131 + any Contribution intentionally submitted for inclusion in the Work
  132 + by You to the Licensor shall be under the terms and conditions of
  133 + this License, without any additional terms or conditions.
  134 + Notwithstanding the above, nothing herein shall supersede or modify
  135 + the terms of any separate license agreement you may have executed
  136 + with Licensor regarding such Contributions.
  137 +
  138 + 6. Trademarks. This License does not grant permission to use the trade
  139 + names, trademarks, service marks, or product names of the Licensor,
  140 + except as required for reasonable and customary use in describing the
  141 + origin of the Work and reproducing the content of the NOTICE file.
  142 +
  143 + 7. Disclaimer of Warranty. Unless required by applicable law or
  144 + agreed to in writing, Licensor provides the Work (and each
  145 + Contributor provides its Contributions) on an "AS IS" BASIS,
  146 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  147 + implied, including, without limitation, any warranties or conditions
  148 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
  149 + PARTICULAR PURPOSE. You are solely responsible for determining the
  150 + appropriateness of using or redistributing the Work and assume any
  151 + risks associated with Your exercise of permissions under this License.
  152 +
  153 + 8. Limitation of Liability. In no event and under no legal theory,
  154 + whether in tort (including negligence), contract, or otherwise,
  155 + unless required by applicable law (such as deliberate and grossly
  156 + negligent acts) or agreed to in writing, shall any Contributor be
  157 + liable to You for damages, including any direct, indirect, special,
  158 + incidental, or consequential damages of any character arising as a
  159 + result of this License or out of the use or inability to use the
  160 + Work (including but not limited to damages for loss of goodwill,
  161 + work stoppage, computer failure or malfunction, or any and all
  162 + other commercial damages or losses), even if such Contributor
  163 + has been advised of the possibility of such damages.
  164 +
  165 + 9. Accepting Warranty or Additional Liability. While redistributing
  166 + the Work or Derivative Works thereof, You may choose to offer,
  167 + and charge a fee for, acceptance of support, warranty, indemnity,
  168 + or other liability obligations and/or rights consistent with this
  169 + License. However, in accepting such obligations, You may act only
  170 + on Your own behalf and on Your sole responsibility, not on behalf
  171 + of any other Contributor, and only if You agree to indemnify,
  172 + defend, and hold each Contributor harmless for any liability
  173 + incurred by, or claims asserted against, such Contributor by reason
  174 + of your accepting any such warranty or additional liability.
  175 +
  176 + END OF TERMS AND CONDITIONS
  177 +
  178 + APPENDIX: How to apply the Apache License to your work.
  179 +
  180 + To apply the Apache License to your work, attach the following
  181 + boilerplate notice, with the fields enclosed by brackets "{}"
  182 + replaced with your own identifying information. (Don't include
  183 + the brackets!) The text should be enclosed in the appropriate
  184 + comment syntax for the file format. We also recommend that a
  185 + file or class name and description of purpose be included on the
  186 + same "printed page" as the copyright notice for easier
  187 + identification within third-party archives.
  188 +
  189 + Copyright {yyyy} {name of copyright owner}
  190 +
  191 + Licensed under the Apache License, Version 2.0 (the "License");
  192 + you may not use this file except in compliance with the License.
  193 + You may obtain a copy of the License at
  194 +
  195 + http://www.apache.org/licenses/LICENSE-2.0
  196 +
  197 + Unless required by applicable law or agreed to in writing, software
  198 + distributed under the License is distributed on an "AS IS" BASIS,
  199 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  200 + See the License for the specific language governing permissions and
  201 + limitations under the License.
  1 +# The ThinkPHP5 Image Package
  2 +
  3 +[![Build Status](https://img.shields.io/travis/top-think/think-image.svg)](https://travis-ci.org/top-think/think-image)
  4 +[![Coverage Status](https://img.shields.io/codecov/c/github/top-think/think-image.svg)](https://codecov.io/github/top-think/think-image)
  5 +[![Downloads](https://img.shields.io/github/downloads/top-think/think-image/total.svg)](https://github.com/top-think/think-image/releases)
  6 +[![Releases](https://img.shields.io/github/release/top-think/think-image.svg)](https://github.com/top-think/think-image/releases/latest)
  7 +[![Releases Downloads](https://img.shields.io/github/downloads/top-think/think-image/latest/total.svg)](https://github.com/top-think/think-image/releases/latest)
  8 +[![Packagist Status](https://img.shields.io/packagist/v/top-think/think-image.svg)](https://packagist.org/packages/topthink/think-image)
  9 +[![Packagist Downloads](https://img.shields.io/packagist/dt/top-think/think-image.svg)](https://packagist.org/packages/topthink/think-image)
  10 +
  11 +## 安装
  12 +
  13 +> composer require topthink/think-image
  14 +
  15 +## 使用
  16 +
  17 +~~~
  18 +$image = \think\Image::open('./image.jpg');
  19 +或者
  20 +$image = \think\Image::open(request()->file('image'));
  21 +
  22 +
  23 +$image->crop(...)
  24 + ->thumb(...)
  25 + ->water(...)
  26 + ->text(....)
  27 + ->save(..);
  28 +
  29 +~~~
  1 +{
  2 + "name": "topthink/think-image",
  3 + "description": "The ThinkPHP5 Image Package",
  4 + "license": "Apache-2.0",
  5 + "authors": [
  6 + {
  7 + "name": "yunwuxin",
  8 + "email": "448901948@qq.com"
  9 + }
  10 + ],
  11 + "require": {
  12 + "ext-gd": "*"
  13 + },
  14 + "require-dev": {
  15 + "topthink/framework": "^5.0",
  16 + "phpunit/phpunit": "4.8.*"
  17 + },
  18 + "config": {
  19 + "preferred-install": "dist"
  20 + },
  21 + "autoload": {
  22 + "psr-4": {
  23 + "think\\": "src"
  24 + }
  25 + }
  26 +}
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<phpunit backupGlobals="false"
  3 + backupStaticAttributes="false"
  4 + bootstrap="tests/autoload.php"
  5 + colors="true"
  6 + convertErrorsToExceptions="true"
  7 + convertNoticesToExceptions="true"
  8 + convertWarningsToExceptions="true"
  9 + processIsolation="false"
  10 + stopOnFailure="false"
  11 + syntaxCheck="false">
  12 + <testsuites>
  13 + <testsuite name="Package Test Suite">
  14 + <directory suffix=".php">./tests/</directory>
  15 + </testsuite>
  16 + </testsuites>
  17 + <listeners>
  18 + <listener class="JohnKary\PHPUnit\Listener\SpeedTrapListener" />
  19 + </listeners>
  20 +</phpunit>
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +
  12 +namespace think;
  13 +
  14 +use think\image\Exception as ImageException;
  15 +use think\image\gif\Gif;
  16 +
  17 +class Image
  18 +{
  19 +
  20 + /* 缩略图相关常量定义 */
  21 + const THUMB_SCALING = 1; //常量,标识缩略图等比例缩放类型
  22 + const THUMB_FILLED = 2; //常量,标识缩略图缩放后填充类型
  23 + const THUMB_CENTER = 3; //常量,标识缩略图居中裁剪类型
  24 + const THUMB_NORTHWEST = 4; //常量,标识缩略图左上角裁剪类型
  25 + const THUMB_SOUTHEAST = 5; //常量,标识缩略图右下角裁剪类型
  26 + const THUMB_FIXED = 6; //常量,标识缩略图固定尺寸缩放类型
  27 + /* 水印相关常量定义 */
  28 + const WATER_NORTHWEST = 1; //常量,标识左上角水印
  29 + const WATER_NORTH = 2; //常量,标识上居中水印
  30 + const WATER_NORTHEAST = 3; //常量,标识右上角水印
  31 + const WATER_WEST = 4; //常量,标识左居中水印
  32 + const WATER_CENTER = 5; //常量,标识居中水印
  33 + const WATER_EAST = 6; //常量,标识右居中水印
  34 + const WATER_SOUTHWEST = 7; //常量,标识左下角水印
  35 + const WATER_SOUTH = 8; //常量,标识下居中水印
  36 + const WATER_SOUTHEAST = 9; //常量,标识右下角水印
  37 + /* 翻转相关常量定义 */
  38 + const FLIP_X = 1; //X轴翻转
  39 + const FLIP_Y = 2; //Y轴翻转
  40 +
  41 + /**
  42 + * 图像资源对象
  43 + *
  44 + * @var resource
  45 + */
  46 + protected $im;
  47 +
  48 + /** @var Gif */
  49 + protected $gif;
  50 +
  51 + /**
  52 + * 图像信息,包括 width, height, type, mime, size
  53 + *
  54 + * @var array
  55 + */
  56 + protected $info;
  57 +
  58 + protected function __construct(\SplFileInfo $file)
  59 + {
  60 + //获取图像信息
  61 + $info = @getimagesize($file->getPathname());
  62 +
  63 + //检测图像合法性
  64 + if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) {
  65 + throw new ImageException('Illegal image file');
  66 + }
  67 +
  68 + //设置图像信息
  69 + $this->info = [
  70 + 'width' => $info[0],
  71 + 'height' => $info[1],
  72 + 'type' => image_type_to_extension($info[2], false),
  73 + 'mime' => $info['mime'],
  74 + ];
  75 +
  76 + //打开图像
  77 + if ('gif' == $this->info['type']) {
  78 + $this->gif = new Gif($file->getPathname());
  79 + $this->im = @imagecreatefromstring($this->gif->image());
  80 + } else {
  81 + $fun = "imagecreatefrom{$this->info['type']}";
  82 + $this->im = @$fun($file->getPathname());
  83 + }
  84 +
  85 + if (empty($this->im)) {
  86 + throw new ImageException('Failed to create image resources!');
  87 + }
  88 +
  89 + }
  90 +
  91 + /**
  92 + * 打开一个图片文件
  93 + * @param \SplFileInfo|string $file
  94 + * @return Image
  95 + */
  96 + public static function open($file)
  97 + {
  98 + if (is_string($file)) {
  99 + $file = new \SplFileInfo($file);
  100 + }
  101 + if (!$file->isFile()) {
  102 + throw new ImageException('image file not exist');
  103 + }
  104 + return new self($file);
  105 + }
  106 +
  107 + /**
  108 + * 保存图像
  109 + * @param string $pathname 图像保存路径名称
  110 + * @param null|string $type 图像类型
  111 + * @param int $quality 图像质量
  112 + * @param bool $interlace 是否对JPEG类型图像设置隔行扫描
  113 + * @return $this
  114 + */
  115 + public function save($pathname, $type = null, $quality = 80, $interlace = true)
  116 + {
  117 + //自动获取图像类型
  118 + if (is_null($type)) {
  119 + $type = $this->info['type'];
  120 + } else {
  121 + $type = strtolower($type);
  122 + }
  123 + //保存图像
  124 + if ('jpeg' == $type || 'jpg' == $type) {
  125 + //JPEG图像设置隔行扫描
  126 + imageinterlace($this->im, $interlace);
  127 + imagejpeg($this->im, $pathname, $quality);
  128 + } elseif ('gif' == $type && !empty($this->gif)) {
  129 + $this->gif->save($pathname);
  130 + } elseif ('png' == $type) {
  131 + //设定保存完整的 alpha 通道信息
  132 + imagesavealpha($this->im, true);
  133 + //ImagePNG生成图像的质量范围从0到9的
  134 + imagepng($this->im, $pathname, min((int) ($quality / 10), 9));
  135 + } else {
  136 + $fun = 'image' . $type;
  137 + $fun($this->im, $pathname);
  138 + }
  139 +
  140 + return $this;
  141 + }
  142 +
  143 + /**
  144 + * 返回图像宽度
  145 + * @return int 图像宽度
  146 + */
  147 + public function width()
  148 + {
  149 + return $this->info['width'];
  150 + }
  151 +
  152 + /**
  153 + * 返回图像高度
  154 + * @return int 图像高度
  155 + */
  156 + public function height()
  157 + {
  158 + return $this->info['height'];
  159 + }
  160 +
  161 + /**
  162 + * 返回图像类型
  163 + * @return string 图像类型
  164 + */
  165 + public function type()
  166 + {
  167 + return $this->info['type'];
  168 + }
  169 +
  170 + /**
  171 + * 返回图像MIME类型
  172 + * @return string 图像MIME类型
  173 + */
  174 + public function mime()
  175 + {
  176 + return $this->info['mime'];
  177 + }
  178 +
  179 + /**
  180 + * 返回图像尺寸数组 0 - 图像宽度,1 - 图像高度
  181 + * @return array 图像尺寸
  182 + */
  183 + public function size()
  184 + {
  185 + return [$this->info['width'], $this->info['height']];
  186 + }
  187 +
  188 + /**
  189 + * 旋转图像
  190 + * @param int $degrees 顺时针旋转的度数
  191 + * @return $this
  192 + */
  193 + public function rotate($degrees = 90)
  194 + {
  195 + do {
  196 + $img = imagerotate($this->im, -$degrees, imagecolorallocatealpha($this->im, 0, 0, 0, 127));
  197 + imagedestroy($this->im);
  198 + $this->im = $img;
  199 + } while (!empty($this->gif) && $this->gifNext());
  200 +
  201 + $this->info['width'] = imagesx($this->im);
  202 + $this->info['height'] = imagesy($this->im);
  203 +
  204 + return $this;
  205 + }
  206 +
  207 + /**
  208 + * 翻转图像
  209 + * @param integer $direction 翻转轴,X或者Y
  210 + * @return $this
  211 + */
  212 + public function flip($direction = self::FLIP_X)
  213 + {
  214 + //原图宽度和高度
  215 + $w = $this->info['width'];
  216 + $h = $this->info['height'];
  217 +
  218 + do {
  219 +
  220 + $img = imagecreatetruecolor($w, $h);
  221 +
  222 + switch ($direction) {
  223 + case self::FLIP_X:
  224 + for ($y = 0; $y < $h; $y++) {
  225 + imagecopy($img, $this->im, 0, $h - $y - 1, 0, $y, $w, 1);
  226 + }
  227 + break;
  228 + case self::FLIP_Y:
  229 + for ($x = 0; $x < $w; $x++) {
  230 + imagecopy($img, $this->im, $w - $x - 1, 0, $x, 0, 1, $h);
  231 + }
  232 + break;
  233 + default:
  234 + throw new ImageException('不支持的翻转类型');
  235 + }
  236 +
  237 + imagedestroy($this->im);
  238 + $this->im = $img;
  239 +
  240 + } while (!empty($this->gif) && $this->gifNext());
  241 +
  242 + return $this;
  243 + }
  244 +
  245 + /**
  246 + * 裁剪图像
  247 + *
  248 + * @param integer $w 裁剪区域宽度
  249 + * @param integer $h 裁剪区域高度
  250 + * @param integer $x 裁剪区域x坐标
  251 + * @param integer $y 裁剪区域y坐标
  252 + * @param integer $width 图像保存宽度
  253 + * @param integer $height 图像保存高度
  254 + *
  255 + * @return $this
  256 + */
  257 + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null)
  258 + {
  259 + //设置保存尺寸
  260 + empty($width) && $width = $w;
  261 + empty($height) && $height = $h;
  262 + do {
  263 + //创建新图像
  264 + $img = imagecreatetruecolor($width, $height);
  265 + // 调整默认颜色
  266 + $color = imagecolorallocate($img, 255, 255, 255);
  267 + imagefill($img, 0, 0, $color);
  268 + //裁剪
  269 + imagecopyresampled($img, $this->im, 0, 0, $x, $y, $width, $height, $w, $h);
  270 + imagedestroy($this->im); //销毁原图
  271 + //设置新图像
  272 + $this->im = $img;
  273 + } while (!empty($this->gif) && $this->gifNext());
  274 + $this->info['width'] = (int) $width;
  275 + $this->info['height'] = (int) $height;
  276 + return $this;
  277 + }
  278 +
  279 + /**
  280 + * 生成缩略图
  281 + *
  282 + * @param integer $width 缩略图最大宽度
  283 + * @param integer $height 缩略图最大高度
  284 + * @param int $type 缩略图裁剪类型
  285 + *
  286 + * @return $this
  287 + */
  288 + public function thumb($width, $height, $type = self::THUMB_SCALING)
  289 + {
  290 + //原图宽度和高度
  291 + $w = $this->info['width'];
  292 + $h = $this->info['height'];
  293 + /* 计算缩略图生成的必要参数 */
  294 + switch ($type) {
  295 + /* 等比例缩放 */
  296 + case self::THUMB_SCALING:
  297 + //原图尺寸小于缩略图尺寸则不进行缩略
  298 + if ($w < $width && $h < $height) {
  299 + return $this;
  300 + }
  301 + //计算缩放比例
  302 + $scale = min($width / $w, $height / $h);
  303 + //设置缩略图的坐标及宽度和高度
  304 + $x = $y = 0;
  305 + $width = $w * $scale;
  306 + $height = $h * $scale;
  307 + break;
  308 + /* 居中裁剪 */
  309 + case self::THUMB_CENTER:
  310 + //计算缩放比例
  311 + $scale = max($width / $w, $height / $h);
  312 + //设置缩略图的坐标及宽度和高度
  313 + $w = $width / $scale;
  314 + $h = $height / $scale;
  315 + $x = ($this->info['width'] - $w) / 2;
  316 + $y = ($this->info['height'] - $h) / 2;
  317 + break;
  318 + /* 左上角裁剪 */
  319 + case self::THUMB_NORTHWEST:
  320 + //计算缩放比例
  321 + $scale = max($width / $w, $height / $h);
  322 + //设置缩略图的坐标及宽度和高度
  323 + $x = $y = 0;
  324 + $w = $width / $scale;
  325 + $h = $height / $scale;
  326 + break;
  327 + /* 右下角裁剪 */
  328 + case self::THUMB_SOUTHEAST:
  329 + //计算缩放比例
  330 + $scale = max($width / $w, $height / $h);
  331 + //设置缩略图的坐标及宽度和高度
  332 + $w = $width / $scale;
  333 + $h = $height / $scale;
  334 + $x = $this->info['width'] - $w;
  335 + $y = $this->info['height'] - $h;
  336 + break;
  337 + /* 填充 */
  338 + case self::THUMB_FILLED:
  339 + //计算缩放比例
  340 + if ($w < $width && $h < $height) {
  341 + $scale = 1;
  342 + } else {
  343 + $scale = min($width / $w, $height / $h);
  344 + }
  345 + //设置缩略图的坐标及宽度和高度
  346 + $neww = $w * $scale;
  347 + $newh = $h * $scale;
  348 + $x = $this->info['width'] - $w;
  349 + $y = $this->info['height'] - $h;
  350 + $posx = ($width - $w * $scale) / 2;
  351 + $posy = ($height - $h * $scale) / 2;
  352 + do {
  353 + //创建新图像
  354 + $img = imagecreatetruecolor($width, $height);
  355 + // 调整默认颜色
  356 + $color = imagecolorallocate($img, 255, 255, 255);
  357 + imagefill($img, 0, 0, $color);
  358 + //裁剪
  359 + imagecopyresampled($img, $this->im, $posx, $posy, $x, $y, $neww, $newh, $w, $h);
  360 + imagedestroy($this->im); //销毁原图
  361 + $this->im = $img;
  362 + } while (!empty($this->gif) && $this->gifNext());
  363 + $this->info['width'] = (int) $width;
  364 + $this->info['height'] = (int) $height;
  365 + return $this;
  366 + /* 固定 */
  367 + case self::THUMB_FIXED:
  368 + $x = $y = 0;
  369 + break;
  370 + default:
  371 + throw new ImageException('不支持的缩略图裁剪类型');
  372 + }
  373 + /* 裁剪图像 */
  374 + return $this->crop($w, $h, $x, $y, $width, $height);
  375 + }
  376 +
  377 + /**
  378 + * 添加水印
  379 + *
  380 + * @param string $source 水印图片路径
  381 + * @param int $locate 水印位置
  382 + * @param int $alpha 透明度
  383 + * @return $this
  384 + */
  385 + public function water($source, $locate = self::WATER_SOUTHEAST, $alpha = 100)
  386 + {
  387 + if (!is_file($source)) {
  388 + throw new ImageException('水印图像不存在');
  389 + }
  390 + //获取水印图像信息
  391 + $info = getimagesize($source);
  392 + if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) {
  393 + throw new ImageException('非法水印文件');
  394 + }
  395 + //创建水印图像资源
  396 + $fun = 'imagecreatefrom' . image_type_to_extension($info[2], false);
  397 + $water = $fun($source);
  398 + //设定水印图像的混色模式
  399 + imagealphablending($water, true);
  400 + /* 设定水印位置 */
  401 + switch ($locate) {
  402 + /* 右下角水印 */
  403 + case self::WATER_SOUTHEAST:
  404 + $x = $this->info['width'] - $info[0];
  405 + $y = $this->info['height'] - $info[1];
  406 + break;
  407 + /* 左下角水印 */
  408 + case self::WATER_SOUTHWEST:
  409 + $x = 0;
  410 + $y = $this->info['height'] - $info[1];
  411 + break;
  412 + /* 左上角水印 */
  413 + case self::WATER_NORTHWEST:
  414 + $x = $y = 0;
  415 + break;
  416 + /* 右上角水印 */
  417 + case self::WATER_NORTHEAST:
  418 + $x = $this->info['width'] - $info[0];
  419 + $y = 0;
  420 + break;
  421 + /* 居中水印 */
  422 + case self::WATER_CENTER:
  423 + $x = ($this->info['width'] - $info[0]) / 2;
  424 + $y = ($this->info['height'] - $info[1]) / 2;
  425 + break;
  426 + /* 下居中水印 */
  427 + case self::WATER_SOUTH:
  428 + $x = ($this->info['width'] - $info[0]) / 2;
  429 + $y = $this->info['height'] - $info[1];
  430 + break;
  431 + /* 右居中水印 */
  432 + case self::WATER_EAST:
  433 + $x = $this->info['width'] - $info[0];
  434 + $y = ($this->info['height'] - $info[1]) / 2;
  435 + break;
  436 + /* 上居中水印 */
  437 + case self::WATER_NORTH:
  438 + $x = ($this->info['width'] - $info[0]) / 2;
  439 + $y = 0;
  440 + break;
  441 + /* 左居中水印 */
  442 + case self::WATER_WEST:
  443 + $x = 0;
  444 + $y = ($this->info['height'] - $info[1]) / 2;
  445 + break;
  446 + default:
  447 + /* 自定义水印坐标 */
  448 + if (is_array($locate)) {
  449 + list($x, $y) = $locate;
  450 + } else {
  451 + throw new ImageException('不支持的水印位置类型');
  452 + }
  453 + }
  454 + do {
  455 + //添加水印
  456 + $src = imagecreatetruecolor($info[0], $info[1]);
  457 + // 调整默认颜色
  458 + $color = imagecolorallocate($src, 255, 255, 255);
  459 + imagefill($src, 0, 0, $color);
  460 + imagecopy($src, $this->im, 0, 0, $x, $y, $info[0], $info[1]);
  461 + imagecopy($src, $water, 0, 0, 0, 0, $info[0], $info[1]);
  462 + imagecopymerge($this->im, $src, $x, $y, 0, 0, $info[0], $info[1], $alpha);
  463 + //销毁零时图片资源
  464 + imagedestroy($src);
  465 + } while (!empty($this->gif) && $this->gifNext());
  466 + //销毁水印资源
  467 + imagedestroy($water);
  468 + return $this;
  469 + }
  470 +
  471 + /**
  472 + * 图像添加文字
  473 + *
  474 + * @param string $text 添加的文字
  475 + * @param string $font 字体路径
  476 + * @param integer $size 字号
  477 + * @param string $color 文字颜色
  478 + * @param int $locate 文字写入位置
  479 + * @param integer $offset 文字相对当前位置的偏移量
  480 + * @param integer $angle 文字倾斜角度
  481 + *
  482 + * @return $this
  483 + * @throws ImageException
  484 + */
  485 + public function text($text, $font, $size, $color = '#00000000',
  486 + $locate = self::WATER_SOUTHEAST, $offset = 0, $angle = 0) {
  487 +
  488 + if (!is_file($font)) {
  489 + throw new ImageException("不存在的字体文件:{$font}");
  490 + }
  491 + //获取文字信息
  492 + $info = imagettfbbox($size, $angle, $font, $text);
  493 + $minx = min($info[0], $info[2], $info[4], $info[6]);
  494 + $maxx = max($info[0], $info[2], $info[4], $info[6]);
  495 + $miny = min($info[1], $info[3], $info[5], $info[7]);
  496 + $maxy = max($info[1], $info[3], $info[5], $info[7]);
  497 + /* 计算文字初始坐标和尺寸 */
  498 + $x = $minx;
  499 + $y = abs($miny);
  500 + $w = $maxx - $minx;
  501 + $h = $maxy - $miny;
  502 + /* 设定文字位置 */
  503 + switch ($locate) {
  504 + /* 右下角文字 */
  505 + case self::WATER_SOUTHEAST:
  506 + $x += $this->info['width'] - $w;
  507 + $y += $this->info['height'] - $h;
  508 + break;
  509 + /* 左下角文字 */
  510 + case self::WATER_SOUTHWEST:
  511 + $y += $this->info['height'] - $h;
  512 + break;
  513 + /* 左上角文字 */
  514 + case self::WATER_NORTHWEST:
  515 + // 起始坐标即为左上角坐标,无需调整
  516 + break;
  517 + /* 右上角文字 */
  518 + case self::WATER_NORTHEAST:
  519 + $x += $this->info['width'] - $w;
  520 + break;
  521 + /* 居中文字 */
  522 + case self::WATER_CENTER:
  523 + $x += ($this->info['width'] - $w) / 2;
  524 + $y += ($this->info['height'] - $h) / 2;
  525 + break;
  526 + /* 下居中文字 */
  527 + case self::WATER_SOUTH:
  528 + $x += ($this->info['width'] - $w) / 2;
  529 + $y += $this->info['height'] - $h;
  530 + break;
  531 + /* 右居中文字 */
  532 + case self::WATER_EAST:
  533 + $x += $this->info['width'] - $w;
  534 + $y += ($this->info['height'] - $h) / 2;
  535 + break;
  536 + /* 上居中文字 */
  537 + case self::WATER_NORTH:
  538 + $x += ($this->info['width'] - $w) / 2;
  539 + break;
  540 + /* 左居中文字 */
  541 + case self::WATER_WEST:
  542 + $y += ($this->info['height'] - $h) / 2;
  543 + break;
  544 + default:
  545 + /* 自定义文字坐标 */
  546 + if (is_array($locate)) {
  547 + list($posx, $posy) = $locate;
  548 + $x += $posx;
  549 + $y += $posy;
  550 + } else {
  551 + throw new ImageException('不支持的文字位置类型');
  552 + }
  553 + }
  554 + /* 设置偏移量 */
  555 + if (is_array($offset)) {
  556 + $offset = array_map('intval', $offset);
  557 + list($ox, $oy) = $offset;
  558 + } else {
  559 + $offset = intval($offset);
  560 + $ox = $oy = $offset;
  561 + }
  562 + /* 设置颜色 */
  563 + if (is_string($color) && 0 === strpos($color, '#')) {
  564 + $color = str_split(substr($color, 1), 2);
  565 + $color = array_map('hexdec', $color);
  566 + if (empty($color[3]) || $color[3] > 127) {
  567 + $color[3] = 0;
  568 + }
  569 + } elseif (!is_array($color)) {
  570 + throw new ImageException('错误的颜色值');
  571 + }
  572 + do {
  573 + /* 写入文字 */
  574 + $col = imagecolorallocatealpha($this->im, $color[0], $color[1], $color[2], $color[3]);
  575 + imagettftext($this->im, $size, $angle, $x + $ox, $y + $oy, $col, $font, $text);
  576 + } while (!empty($this->gif) && $this->gifNext());
  577 + return $this;
  578 + }
  579 +
  580 + /**
  581 + * 切换到GIF的下一帧并保存当前帧
  582 + */
  583 + protected function gifNext()
  584 + {
  585 + ob_start();
  586 + ob_implicit_flush(0);
  587 + imagegif($this->im);
  588 + $img = ob_get_clean();
  589 + $this->gif->image($img);
  590 + $next = $this->gif->nextImage();
  591 + if ($next) {
  592 + imagedestroy($this->im);
  593 + $this->im = imagecreatefromstring($next);
  594 + return $next;
  595 + } else {
  596 + imagedestroy($this->im);
  597 + $this->im = imagecreatefromstring($this->gif->image());
  598 + return false;
  599 + }
  600 + }
  601 +
  602 + /**
  603 + * 析构方法,用于销毁图像资源
  604 + */
  605 + public function __destruct()
  606 + {
  607 + empty($this->im) || imagedestroy($this->im);
  608 + }
  609 +
  610 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +
  12 +namespace think\image;
  13 +
  14 +
  15 +class Exception extends \RuntimeException
  16 +{
  17 +
  18 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +
  12 +namespace think\image\gif;
  13 +
  14 +
  15 +class Decoder
  16 +{
  17 + public $GIF_buffer = [];
  18 + public $GIF_arrays = [];
  19 + public $GIF_delays = [];
  20 + public $GIF_stream = "";
  21 + public $GIF_string = "";
  22 + public $GIF_bfseek = 0;
  23 + public $GIF_screen = [];
  24 + public $GIF_global = [];
  25 + public $GIF_sorted;
  26 + public $GIF_colorS;
  27 + public $GIF_colorC;
  28 + public $GIF_colorF;
  29 +
  30 + /*
  31 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  32 + ::
  33 + :: GIFDecoder ( $GIF_pointer )
  34 + ::
  35 + */
  36 + public function __construct($GIF_pointer)
  37 + {
  38 + $this->GIF_stream = $GIF_pointer;
  39 + $this->getByte(6); // GIF89a
  40 + $this->getByte(7); // Logical Screen Descriptor
  41 + $this->GIF_screen = $this->GIF_buffer;
  42 + $this->GIF_colorF = $this->GIF_buffer[4] & 0x80 ? 1 : 0;
  43 + $this->GIF_sorted = $this->GIF_buffer[4] & 0x08 ? 1 : 0;
  44 + $this->GIF_colorC = $this->GIF_buffer[4] & 0x07;
  45 + $this->GIF_colorS = 2 << $this->GIF_colorC;
  46 + if (1 == $this->GIF_colorF) {
  47 + $this->getByte(3 * $this->GIF_colorS);
  48 + $this->GIF_global = $this->GIF_buffer;
  49 + }
  50 +
  51 + for ($cycle = 1; $cycle;) {
  52 + if ($this->getByte(1)) {
  53 + switch ($this->GIF_buffer[0]) {
  54 + case 0x21:
  55 + $this->readExtensions();
  56 + break;
  57 + case 0x2C:
  58 + $this->readDescriptor();
  59 + break;
  60 + case 0x3B:
  61 + $cycle = 0;
  62 + break;
  63 + }
  64 + } else {
  65 + $cycle = 0;
  66 + }
  67 + }
  68 + }
  69 +
  70 + /*
  71 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  72 + ::
  73 + :: GIFReadExtension ( )
  74 + ::
  75 + */
  76 + public function readExtensions()
  77 + {
  78 + $this->getByte(1);
  79 + for (; ;) {
  80 + $this->getByte(1);
  81 + if (($u = $this->GIF_buffer[0]) == 0x00) {
  82 + break;
  83 + }
  84 + $this->getByte($u);
  85 + /*
  86 + * 07.05.2007.
  87 + * Implemented a new line for a new function
  88 + * to determine the originaly delays between
  89 + * frames.
  90 + *
  91 + */
  92 + if (4 == $u) {
  93 + $this->GIF_delays[] = ($this->GIF_buffer[1] | $this->GIF_buffer[2] << 8);
  94 + }
  95 + }
  96 + }
  97 +
  98 + /*
  99 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  100 + ::
  101 + :: GIFReadExtension ( )
  102 + ::
  103 + */
  104 + public function readDescriptor()
  105 + {
  106 + $this->getByte(9);
  107 + $GIF_screen = $this->GIF_buffer;
  108 + $GIF_colorF = $this->GIF_buffer[8] & 0x80 ? 1 : 0;
  109 + if ($GIF_colorF) {
  110 + $GIF_code = $this->GIF_buffer[8] & 0x07;
  111 + $GIF_sort = $this->GIF_buffer[8] & 0x20 ? 1 : 0;
  112 + } else {
  113 + $GIF_code = $this->GIF_colorC;
  114 + $GIF_sort = $this->GIF_sorted;
  115 + }
  116 + $GIF_size = 2 << $GIF_code;
  117 + $this->GIF_screen[4] &= 0x70;
  118 + $this->GIF_screen[4] |= 0x80;
  119 + $this->GIF_screen[4] |= $GIF_code;
  120 + if ($GIF_sort) {
  121 + $this->GIF_screen[4] |= 0x08;
  122 + }
  123 + $this->GIF_string = "GIF87a";
  124 + $this->putByte($this->GIF_screen);
  125 + if (1 == $GIF_colorF) {
  126 + $this->getByte(3 * $GIF_size);
  127 + $this->putByte($this->GIF_buffer);
  128 + } else {
  129 + $this->putByte($this->GIF_global);
  130 + }
  131 + $this->GIF_string .= chr(0x2C);
  132 + $GIF_screen[8] &= 0x40;
  133 + $this->putByte($GIF_screen);
  134 + $this->getByte(1);
  135 + $this->putByte($this->GIF_buffer);
  136 + for (; ;) {
  137 + $this->getByte(1);
  138 + $this->putByte($this->GIF_buffer);
  139 + if (($u = $this->GIF_buffer[0]) == 0x00) {
  140 + break;
  141 + }
  142 + $this->getByte($u);
  143 + $this->putByte($this->GIF_buffer);
  144 + }
  145 + $this->GIF_string .= chr(0x3B);
  146 + /*
  147 + Add frames into $GIF_stream array...
  148 + */
  149 + $this->GIF_arrays[] = $this->GIF_string;
  150 + }
  151 +
  152 + /*
  153 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  154 + ::
  155 + :: GIFGetByte ( $len )
  156 + ::
  157 + */
  158 + public function getByte($len)
  159 + {
  160 + $this->GIF_buffer = [];
  161 + for ($i = 0; $i < $len; $i++) {
  162 + if ($this->GIF_bfseek > strlen($this->GIF_stream)) {
  163 + return 0;
  164 + }
  165 + $this->GIF_buffer[] = ord($this->GIF_stream{$this->GIF_bfseek++});
  166 + }
  167 + return 1;
  168 + }
  169 +
  170 + /*
  171 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  172 + ::
  173 + :: GIFPutByte ( $bytes )
  174 + ::
  175 + */
  176 + public function putByte($bytes)
  177 + {
  178 + for ($i = 0; $i < count($bytes); $i++) {
  179 + $this->GIF_string .= chr($bytes[$i]);
  180 + }
  181 + }
  182 +
  183 + /*
  184 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  185 + ::
  186 + :: PUBLIC FUNCTIONS
  187 + ::
  188 + ::
  189 + :: GIFGetFrames ( )
  190 + ::
  191 + */
  192 + public function getFrames()
  193 + {
  194 + return ($this->GIF_arrays);
  195 + }
  196 +
  197 + /*
  198 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  199 + ::
  200 + :: GIFGetDelays ( )
  201 + ::
  202 + */
  203 + public function getDelays()
  204 + {
  205 + return ($this->GIF_delays);
  206 + }
  207 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +namespace think\image\gif;
  12 +
  13 +class Encoder
  14 +{
  15 + public $GIF = "GIF89a"; /* GIF header 6 bytes */
  16 + public $VER = "GIFEncoder V2.05"; /* Encoder version */
  17 + public $BUF = [];
  18 + public $LOP = 0;
  19 + public $DIS = 2;
  20 + public $COL = -1;
  21 + public $IMG = -1;
  22 + public $ERR = [
  23 + 'ERR00' => "Does not supported function for only one image!",
  24 + 'ERR01' => "Source is not a GIF image!",
  25 + 'ERR02' => "Unintelligible flag ",
  26 + 'ERR03' => "Does not make animation from animated GIF source",
  27 + ];
  28 +
  29 + /*
  30 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  31 + ::
  32 + :: GIFEncoder...
  33 + ::
  34 + */
  35 + public function __construct(
  36 + $GIF_src, $GIF_dly, $GIF_lop, $GIF_dis,
  37 + $GIF_red, $GIF_grn, $GIF_blu, $GIF_mod
  38 + )
  39 + {
  40 + if (!is_array($GIF_src)) {
  41 + printf("%s: %s", $this->VER, $this->ERR['ERR00']);
  42 + exit(0);
  43 + }
  44 + $this->LOP = ($GIF_lop > -1) ? $GIF_lop : 0;
  45 + $this->DIS = ($GIF_dis > -1) ? (($GIF_dis < 3) ? $GIF_dis : 3) : 2;
  46 + $this->COL = ($GIF_red > -1 && $GIF_grn > -1 && $GIF_blu > -1) ?
  47 + ($GIF_red | ($GIF_grn << 8) | ($GIF_blu << 16)) : -1;
  48 + for ($i = 0; $i < count($GIF_src); $i++) {
  49 + if (strtolower($GIF_mod) == "url") {
  50 + $this->BUF[] = fread(fopen($GIF_src[$i], "rb"), filesize($GIF_src[$i]));
  51 + } else if (strtolower($GIF_mod) == "bin") {
  52 + $this->BUF[] = $GIF_src[$i];
  53 + } else {
  54 + printf("%s: %s ( %s )!", $this->VER, $this->ERR['ERR02'], $GIF_mod);
  55 + exit(0);
  56 + }
  57 + if (substr($this->BUF[$i], 0, 6) != "GIF87a" && substr($this->BUF[$i], 0, 6) != "GIF89a") {
  58 + printf("%s: %d %s", $this->VER, $i, $this->ERR['ERR01']);
  59 + exit(0);
  60 + }
  61 + for ($j = (13 + 3 * (2 << (ord($this->BUF[$i]{10}) & 0x07))), $k = true; $k; $j++) {
  62 + switch ($this->BUF[$i]{$j}) {
  63 + case "!":
  64 + if ((substr($this->BUF[$i], ($j + 3), 8)) == "NETSCAPE") {
  65 + printf("%s: %s ( %s source )!", $this->VER, $this->ERR['ERR03'], ($i + 1));
  66 + exit(0);
  67 + }
  68 + break;
  69 + case ";":
  70 + $k = false;
  71 + break;
  72 + }
  73 + }
  74 + }
  75 + $this->addHeader();
  76 + for ($i = 0; $i < count($this->BUF); $i++) {
  77 + $this->addFrames($i, $GIF_dly[$i]);
  78 + }
  79 + $this->addFooter();
  80 + }
  81 +
  82 + /*
  83 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  84 + ::
  85 + :: GIFAddHeader...
  86 + ::
  87 + */
  88 + public function addHeader()
  89 + {
  90 + if (ord($this->BUF[0]{10}) & 0x80) {
  91 + $cmap = 3 * (2 << (ord($this->BUF[0]{10}) & 0x07));
  92 + $this->GIF .= substr($this->BUF[0], 6, 7);
  93 + $this->GIF .= substr($this->BUF[0], 13, $cmap);
  94 + $this->GIF .= "!\377\13NETSCAPE2.0\3\1" . $this->word($this->LOP) . "\0";
  95 + }
  96 + }
  97 +
  98 + /*
  99 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  100 + ::
  101 + :: GIFAddFrames...
  102 + ::
  103 + */
  104 + public function addFrames($i, $d)
  105 + {
  106 + $Locals_img = '';
  107 + $Locals_str = 13 + 3 * (2 << (ord($this->BUF[$i]{10}) & 0x07));
  108 + $Locals_end = strlen($this->BUF[$i]) - $Locals_str - 1;
  109 + $Locals_tmp = substr($this->BUF[$i], $Locals_str, $Locals_end);
  110 + $Global_len = 2 << (ord($this->BUF[0]{10}) & 0x07);
  111 + $Locals_len = 2 << (ord($this->BUF[$i]{10}) & 0x07);
  112 + $Global_rgb = substr($this->BUF[0], 13,
  113 + 3 * (2 << (ord($this->BUF[0]{10}) & 0x07)));
  114 + $Locals_rgb = substr($this->BUF[$i], 13,
  115 + 3 * (2 << (ord($this->BUF[$i]{10}) & 0x07)));
  116 + $Locals_ext = "!\xF9\x04" . chr(($this->DIS << 2) + 0) .
  117 + chr(($d >> 0) & 0xFF) . chr(($d >> 8) & 0xFF) . "\x0\x0";
  118 + if ($this->COL > -1 && ord($this->BUF[$i]{10}) & 0x80) {
  119 + for ($j = 0; $j < (2 << (ord($this->BUF[$i]{10}) & 0x07)); $j++) {
  120 + if (
  121 + ord($Locals_rgb{3 * $j + 0}) == (($this->COL >> 16) & 0xFF) &&
  122 + ord($Locals_rgb{3 * $j + 1}) == (($this->COL >> 8) & 0xFF) &&
  123 + ord($Locals_rgb{3 * $j + 2}) == (($this->COL >> 0) & 0xFF)
  124 + ) {
  125 + $Locals_ext = "!\xF9\x04" . chr(($this->DIS << 2) + 1) .
  126 + chr(($d >> 0) & 0xFF) . chr(($d >> 8) & 0xFF) . chr($j) . "\x0";
  127 + break;
  128 + }
  129 + }
  130 + }
  131 + switch ($Locals_tmp{0}) {
  132 + case "!":
  133 + /**
  134 + * @var string $Locals_img ;
  135 + */
  136 + $Locals_img = substr($Locals_tmp, 8, 10);
  137 + $Locals_tmp = substr($Locals_tmp, 18, strlen($Locals_tmp) - 18);
  138 + break;
  139 + case ",":
  140 + $Locals_img = substr($Locals_tmp, 0, 10);
  141 + $Locals_tmp = substr($Locals_tmp, 10, strlen($Locals_tmp) - 10);
  142 + break;
  143 + }
  144 + if (ord($this->BUF[$i]{10}) & 0x80 && $this->IMG > -1) {
  145 + if ($Global_len == $Locals_len) {
  146 + if ($this->blockCompare($Global_rgb, $Locals_rgb, $Global_len)) {
  147 + $this->GIF .= ($Locals_ext . $Locals_img . $Locals_tmp);
  148 + } else {
  149 + $byte = ord($Locals_img{9});
  150 + $byte |= 0x80;
  151 + $byte &= 0xF8;
  152 + $byte |= (ord($this->BUF[0]{10}) & 0x07);
  153 + $Locals_img{9} = chr($byte);
  154 + $this->GIF .= ($Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp);
  155 + }
  156 + } else {
  157 + $byte = ord($Locals_img{9});
  158 + $byte |= 0x80;
  159 + $byte &= 0xF8;
  160 + $byte |= (ord($this->BUF[$i]{10}) & 0x07);
  161 + $Locals_img{9} = chr($byte);
  162 + $this->GIF .= ($Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp);
  163 + }
  164 + } else {
  165 + $this->GIF .= ($Locals_ext . $Locals_img . $Locals_tmp);
  166 + }
  167 + $this->IMG = 1;
  168 + }
  169 +
  170 + /*
  171 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  172 + ::
  173 + :: GIFAddFooter...
  174 + ::
  175 + */
  176 + public function addFooter()
  177 + {
  178 + $this->GIF .= ";";
  179 + }
  180 +
  181 + /*
  182 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  183 + ::
  184 + :: GIFBlockCompare...
  185 + ::
  186 + */
  187 + public function blockCompare($GlobalBlock, $LocalBlock, $Len)
  188 + {
  189 + for ($i = 0; $i < $Len; $i++) {
  190 + if (
  191 + $GlobalBlock{3 * $i + 0} != $LocalBlock{3 * $i + 0} ||
  192 + $GlobalBlock{3 * $i + 1} != $LocalBlock{3 * $i + 1} ||
  193 + $GlobalBlock{3 * $i + 2} != $LocalBlock{3 * $i + 2}
  194 + ) {
  195 + return (0);
  196 + }
  197 + }
  198 + return (1);
  199 + }
  200 +
  201 + /*
  202 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  203 + ::
  204 + :: GIFWord...
  205 + ::
  206 + */
  207 + public function word($int)
  208 + {
  209 + return (chr($int & 0xFF) . chr(($int >> 8) & 0xFF));
  210 + }
  211 +
  212 + /*
  213 + :::::::::::::::::::::::::::::::::::::::::::::::::::
  214 + ::
  215 + :: GetAnimation...
  216 + ::
  217 + */
  218 + public function getAnimation()
  219 + {
  220 + return ($this->GIF);
  221 + }
  222 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +
  12 +namespace think\image\gif;
  13 +
  14 +class Gif
  15 +{
  16 + /**
  17 + * GIF帧列表
  18 + *
  19 + * @var array
  20 + */
  21 + private $frames = [];
  22 + /**
  23 + * 每帧等待时间列表
  24 + *
  25 + * @var array
  26 + */
  27 + private $delays = [];
  28 +
  29 + /**
  30 + * 构造方法,用于解码GIF图片
  31 + *
  32 + * @param string $src GIF图片数据
  33 + * @param string $mod 图片数据类型
  34 + * @throws \Exception
  35 + */
  36 + public function __construct($src = null, $mod = 'url')
  37 + {
  38 + if (!is_null($src)) {
  39 + if ('url' == $mod && is_file($src)) {
  40 + $src = file_get_contents($src);
  41 + }
  42 + /* 解码GIF图片 */
  43 + try {
  44 + $de = new Decoder($src);
  45 + $this->frames = $de->getFrames();
  46 + $this->delays = $de->getDelays();
  47 + } catch (\Exception $e) {
  48 + throw new \Exception("解码GIF图片出错");
  49 + }
  50 + }
  51 + }
  52 +
  53 + /**
  54 + * 设置或获取当前帧的数据
  55 + *
  56 + * @param string $stream 二进制数据流
  57 + * @return mixed 获取到的数据
  58 + */
  59 + public function image($stream = null)
  60 + {
  61 + if (is_null($stream)) {
  62 + $current = current($this->frames);
  63 + return false === $current ? reset($this->frames) : $current;
  64 + }
  65 + $this->frames[key($this->frames)] = $stream;
  66 + }
  67 +
  68 + /**
  69 + * 将当前帧移动到下一帧
  70 + *
  71 + * @return string 当前帧数据
  72 + */
  73 + public function nextImage()
  74 + {
  75 + return next($this->frames);
  76 + }
  77 +
  78 + /**
  79 + * 编码并保存当前GIF图片
  80 + *
  81 + * @param string $pathname 图片名称
  82 + */
  83 + public function save($pathname)
  84 + {
  85 + $gif = new Encoder($this->frames, $this->delays, 0, 2, 0, 0, 0, 'bin');
  86 + file_put_contents($pathname, $gif->getAnimation());
  87 + }
  88 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +namespace tests;
  12 +
  13 +use think\Image;
  14 +
  15 +class CropTest extends TestCase
  16 +{
  17 + public function testJpeg()
  18 + {
  19 + $pathname = TEST_PATH . 'tmp/crop.jpg';
  20 + $image = Image::open($this->getJpeg());
  21 +
  22 + $image->crop(200, 200, 100, 100, 300, 300)->save($pathname);
  23 +
  24 + $this->assertEquals(300, $image->width());
  25 + $this->assertEquals(300, $image->height());
  26 +
  27 + $file = new \SplFileInfo($pathname);
  28 +
  29 + $this->assertTrue($file->isFile());
  30 +
  31 + @unlink($pathname);
  32 + }
  33 +
  34 + public function testPng()
  35 + {
  36 + $pathname = TEST_PATH . 'tmp/crop.png';
  37 + $image = Image::open($this->getPng());
  38 +
  39 + $image->crop(200, 200, 100, 100, 300, 300)->save($pathname);
  40 +
  41 + $this->assertEquals(300, $image->width());
  42 + $this->assertEquals(300, $image->height());
  43 +
  44 + $file = new \SplFileInfo($pathname);
  45 +
  46 + $this->assertTrue($file->isFile());
  47 +
  48 + @unlink($pathname);
  49 + }
  50 +
  51 + public function testGif()
  52 + {
  53 + $pathname = TEST_PATH . 'tmp/crop.gif';
  54 + $image = Image::open($this->getGif());
  55 +
  56 + $image->crop(200, 200, 100, 100, 300, 300)->save($pathname);
  57 +
  58 + $this->assertEquals(300, $image->width());
  59 + $this->assertEquals(300, $image->height());
  60 +
  61 + $file = new \SplFileInfo($pathname);
  62 +
  63 + $this->assertTrue($file->isFile());
  64 +
  65 + @unlink($pathname);
  66 + }
  67 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +namespace tests;
  12 +
  13 +use think\Image;
  14 +
  15 +class FlipTest extends TestCase
  16 +{
  17 + public function testJpeg()
  18 + {
  19 + $pathname = TEST_PATH . 'tmp/flip.jpg';
  20 + $image = Image::open($this->getJpeg());
  21 + $image->flip()->save($pathname);
  22 +
  23 + $file = new \SplFileInfo($pathname);
  24 +
  25 + $this->assertTrue($file->isFile());
  26 +
  27 + @unlink($pathname);
  28 + }
  29 +
  30 +
  31 + public function testGif()
  32 + {
  33 + $pathname = TEST_PATH . 'tmp/flip.gif';
  34 + $image = Image::open($this->getGif());
  35 + $image->flip(Image::FLIP_Y)->save($pathname);
  36 +
  37 + $file = new \SplFileInfo($pathname);
  38 +
  39 + $this->assertTrue($file->isFile());
  40 +
  41 + @unlink($pathname);
  42 + }
  43 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +namespace tests;
  12 +
  13 +use think\Image;
  14 +
  15 +class InfoTest extends TestCase
  16 +{
  17 +
  18 + public function testOpen()
  19 + {
  20 + $this->setExpectedException("\\think\\image\\Exception");
  21 + Image::open('');
  22 + }
  23 +
  24 + public function testIllegal()
  25 + {
  26 + $this->setExpectedException("\\think\\image\\Exception", 'Illegal image file');
  27 + Image::open(TEST_PATH . 'images/test.bmp');
  28 + }
  29 +
  30 + public function testJpeg()
  31 + {
  32 + $image = Image::open($this->getJpeg());
  33 + $this->assertEquals(800, $image->width());
  34 + $this->assertEquals(600, $image->height());
  35 + $this->assertEquals('jpeg', $image->type());
  36 + $this->assertEquals('image/jpeg', $image->mime());
  37 + $this->assertEquals([800, 600], $image->size());
  38 + }
  39 +
  40 +
  41 + public function testPng()
  42 + {
  43 + $image = Image::open($this->getPng());
  44 + $this->assertEquals(800, $image->width());
  45 + $this->assertEquals(600, $image->height());
  46 + $this->assertEquals('png', $image->type());
  47 + $this->assertEquals('image/png', $image->mime());
  48 + $this->assertEquals([800, 600], $image->size());
  49 + }
  50 +
  51 + public function testGif()
  52 + {
  53 + $image = Image::open($this->getGif());
  54 + $this->assertEquals(380, $image->width());
  55 + $this->assertEquals(216, $image->height());
  56 + $this->assertEquals('gif', $image->type());
  57 + $this->assertEquals('image/gif', $image->mime());
  58 + $this->assertEquals([380, 216], $image->size());
  59 + }
  60 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +namespace tests;
  12 +
  13 +use think\Image;
  14 +
  15 +class RotateTest extends TestCase
  16 +{
  17 + public function testJpeg()
  18 + {
  19 + $pathname = TEST_PATH . 'tmp/rotate.jpg';
  20 + $image = Image::open($this->getJpeg());
  21 + $image->rotate(90)->save($pathname);
  22 +
  23 + $file = new \SplFileInfo($pathname);
  24 +
  25 + $this->assertTrue($file->isFile());
  26 +
  27 + @unlink($pathname);
  28 + }
  29 +
  30 + public function testGif()
  31 + {
  32 + $pathname = TEST_PATH . 'tmp/rotate.gif';
  33 + $image = Image::open($this->getGif());
  34 + $image->rotate(90)->save($pathname);
  35 +
  36 + $file = new \SplFileInfo($pathname);
  37 +
  38 + $this->assertTrue($file->isFile());
  39 +
  40 + @unlink($pathname);
  41 + }
  42 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +
  12 +namespace tests;
  13 +
  14 +use think\File;
  15 +
  16 +abstract class TestCase extends \PHPUnit_Framework_TestCase
  17 +{
  18 +
  19 + protected function getJpeg()
  20 + {
  21 + return new File(TEST_PATH . 'images/test.jpg');
  22 + }
  23 +
  24 + protected function getPng()
  25 + {
  26 + return new File(TEST_PATH . 'images/test.png');
  27 + }
  28 +
  29 + protected function getGif()
  30 + {
  31 + return new File(TEST_PATH . 'images/test.gif');
  32 + }
  33 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +namespace tests;
  12 +
  13 +use think\Image;
  14 +
  15 +class TextTest extends TestCase
  16 +{
  17 + public function testJpeg()
  18 + {
  19 + $pathname = TEST_PATH . 'tmp/text.jpg';
  20 + $image = Image::open($this->getJpeg());
  21 +
  22 + $image->text('test', TEST_PATH . 'images/test.ttf', 12)->save($pathname);
  23 +
  24 + $file = new \SplFileInfo($pathname);
  25 +
  26 + $this->assertTrue($file->isFile());
  27 +
  28 + @unlink($pathname);
  29 + }
  30 +
  31 + public function testPng()
  32 + {
  33 + $pathname = TEST_PATH . 'tmp/text.png';
  34 + $image = Image::open($this->getPng());
  35 +
  36 + $image->text('test', TEST_PATH . 'images/test.ttf', 12)->save($pathname);
  37 +
  38 + $file = new \SplFileInfo($pathname);
  39 +
  40 + $this->assertTrue($file->isFile());
  41 +
  42 + @unlink($pathname);
  43 + }
  44 +
  45 + public function testGif()
  46 + {
  47 + $pathname = TEST_PATH . 'tmp/text.gif';
  48 + $image = Image::open($this->getGif());
  49 +
  50 + $image->text('test', TEST_PATH . 'images/test.ttf', 12)->save($pathname);
  51 +
  52 + $file = new \SplFileInfo($pathname);
  53 +
  54 + $this->assertTrue($file->isFile());
  55 +
  56 + @unlink($pathname);
  57 + }
  58 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +namespace tests;
  12 +
  13 +use think\Image;
  14 +
  15 +class ThumbTest extends TestCase
  16 +{
  17 + public function testJpeg()
  18 + {
  19 + $pathname = TEST_PATH . 'tmp/thumb.jpg';
  20 +
  21 + //1
  22 + $image = Image::open($this->getJpeg());
  23 +
  24 + $image->thumb(200, 200, Image::THUMB_CENTER)->save($pathname);
  25 +
  26 + $this->assertEquals(200, $image->width());
  27 + $this->assertEquals(200, $image->height());
  28 +
  29 + $file = new \SplFileInfo($pathname);
  30 +
  31 + $this->assertTrue($file->isFile());
  32 +
  33 + @unlink($pathname);
  34 +
  35 + //2
  36 + $image = Image::open($this->getJpeg());
  37 +
  38 + $image->thumb(200, 200, Image::THUMB_SCALING)->save($pathname);
  39 +
  40 + $this->assertEquals(200, $image->width());
  41 + $this->assertEquals(150, $image->height());
  42 +
  43 + $file = new \SplFileInfo($pathname);
  44 +
  45 + $this->assertTrue($file->isFile());
  46 +
  47 + @unlink($pathname);
  48 +
  49 + //3
  50 + $image = Image::open($this->getJpeg());
  51 +
  52 + $image->thumb(200, 200, Image::THUMB_FILLED)->save($pathname);
  53 +
  54 + $this->assertEquals(200, $image->width());
  55 + $this->assertEquals(200, $image->height());
  56 +
  57 + $file = new \SplFileInfo($pathname);
  58 +
  59 + $this->assertTrue($file->isFile());
  60 +
  61 + @unlink($pathname);
  62 +
  63 + //4
  64 + $image = Image::open($this->getJpeg());
  65 +
  66 + $image->thumb(200, 200, Image::THUMB_NORTHWEST)->save($pathname);
  67 +
  68 + $this->assertEquals(200, $image->width());
  69 + $this->assertEquals(200, $image->height());
  70 +
  71 + $file = new \SplFileInfo($pathname);
  72 +
  73 + $this->assertTrue($file->isFile());
  74 +
  75 + @unlink($pathname);
  76 +
  77 + //5
  78 + $image = Image::open($this->getJpeg());
  79 +
  80 + $image->thumb(200, 200, Image::THUMB_SOUTHEAST)->save($pathname);
  81 +
  82 + $this->assertEquals(200, $image->width());
  83 + $this->assertEquals(200, $image->height());
  84 +
  85 + $file = new \SplFileInfo($pathname);
  86 +
  87 + $this->assertTrue($file->isFile());
  88 +
  89 + @unlink($pathname);
  90 +
  91 + //6
  92 + $image = Image::open($this->getJpeg());
  93 +
  94 + $image->thumb(200, 200, Image::THUMB_FIXED)->save($pathname);
  95 +
  96 + $this->assertEquals(200, $image->width());
  97 + $this->assertEquals(200, $image->height());
  98 +
  99 + $file = new \SplFileInfo($pathname);
  100 +
  101 + $this->assertTrue($file->isFile());
  102 +
  103 + @unlink($pathname);
  104 + }
  105 +
  106 +
  107 + public function testPng()
  108 + {
  109 + $pathname = TEST_PATH . 'tmp/thumb.png';
  110 +
  111 + //1
  112 + $image = Image::open($this->getPng());
  113 +
  114 + $image->thumb(200, 200, Image::THUMB_CENTER)->save($pathname);
  115 +
  116 + $this->assertEquals(200, $image->width());
  117 + $this->assertEquals(200, $image->height());
  118 +
  119 + $file = new \SplFileInfo($pathname);
  120 +
  121 + $this->assertTrue($file->isFile());
  122 +
  123 + @unlink($pathname);
  124 +
  125 + //2
  126 + $image = Image::open($this->getPng());
  127 +
  128 + $image->thumb(200, 200, Image::THUMB_SCALING)->save($pathname);
  129 +
  130 + $this->assertEquals(200, $image->width());
  131 + $this->assertEquals(150, $image->height());
  132 +
  133 + $file = new \SplFileInfo($pathname);
  134 +
  135 + $this->assertTrue($file->isFile());
  136 +
  137 + @unlink($pathname);
  138 +
  139 + //3
  140 + $image = Image::open($this->getPng());
  141 +
  142 + $image->thumb(200, 200, Image::THUMB_FILLED)->save($pathname);
  143 +
  144 + $this->assertEquals(200, $image->width());
  145 + $this->assertEquals(200, $image->height());
  146 +
  147 + $file = new \SplFileInfo($pathname);
  148 +
  149 + $this->assertTrue($file->isFile());
  150 +
  151 + @unlink($pathname);
  152 +
  153 + //4
  154 + $image = Image::open($this->getPng());
  155 +
  156 + $image->thumb(200, 200, Image::THUMB_NORTHWEST)->save($pathname);
  157 +
  158 + $this->assertEquals(200, $image->width());
  159 + $this->assertEquals(200, $image->height());
  160 +
  161 + $file = new \SplFileInfo($pathname);
  162 +
  163 + $this->assertTrue($file->isFile());
  164 +
  165 + @unlink($pathname);
  166 +
  167 + //5
  168 + $image = Image::open($this->getPng());
  169 +
  170 + $image->thumb(200, 200, Image::THUMB_SOUTHEAST)->save($pathname);
  171 +
  172 + $this->assertEquals(200, $image->width());
  173 + $this->assertEquals(200, $image->height());
  174 +
  175 + $file = new \SplFileInfo($pathname);
  176 +
  177 + $this->assertTrue($file->isFile());
  178 +
  179 + @unlink($pathname);
  180 +
  181 + //6
  182 + $image = Image::open($this->getPng());
  183 +
  184 + $image->thumb(200, 200, Image::THUMB_FIXED)->save($pathname);
  185 +
  186 + $this->assertEquals(200, $image->width());
  187 + $this->assertEquals(200, $image->height());
  188 +
  189 + $file = new \SplFileInfo($pathname);
  190 +
  191 + $this->assertTrue($file->isFile());
  192 +
  193 + @unlink($pathname);
  194 + }
  195 +
  196 + public function testGif()
  197 + {
  198 + $pathname = TEST_PATH . 'tmp/thumb.gif';
  199 +
  200 + //1
  201 + $image = Image::open($this->getGif());
  202 +
  203 + $image->thumb(200, 200, Image::THUMB_CENTER)->save($pathname);
  204 +
  205 + $this->assertEquals(200, $image->width());
  206 + $this->assertEquals(200, $image->height());
  207 +
  208 + $file = new \SplFileInfo($pathname);
  209 +
  210 + $this->assertTrue($file->isFile());
  211 +
  212 + @unlink($pathname);
  213 +
  214 + //2
  215 + $image = Image::open($this->getGif());
  216 +
  217 + $image->thumb(200, 200, Image::THUMB_SCALING)->save($pathname);
  218 +
  219 + $this->assertEquals(200, $image->width());
  220 + $this->assertEquals(113, $image->height());
  221 +
  222 + $file = new \SplFileInfo($pathname);
  223 +
  224 + $this->assertTrue($file->isFile());
  225 +
  226 + @unlink($pathname);
  227 +
  228 + //3
  229 + $image = Image::open($this->getGif());
  230 +
  231 + $image->thumb(200, 200, Image::THUMB_FILLED)->save($pathname);
  232 +
  233 + $this->assertEquals(200, $image->width());
  234 + $this->assertEquals(200, $image->height());
  235 +
  236 + $file = new \SplFileInfo($pathname);
  237 +
  238 + $this->assertTrue($file->isFile());
  239 +
  240 + @unlink($pathname);
  241 +
  242 + //4
  243 + $image = Image::open($this->getGif());
  244 +
  245 + $image->thumb(200, 200, Image::THUMB_NORTHWEST)->save($pathname);
  246 +
  247 + $this->assertEquals(200, $image->width());
  248 + $this->assertEquals(200, $image->height());
  249 +
  250 + $file = new \SplFileInfo($pathname);
  251 +
  252 + $this->assertTrue($file->isFile());
  253 +
  254 + @unlink($pathname);
  255 +
  256 + //5
  257 + $image = Image::open($this->getGif());
  258 +
  259 + $image->thumb(200, 200, Image::THUMB_SOUTHEAST)->save($pathname);
  260 +
  261 + $this->assertEquals(200, $image->width());
  262 + $this->assertEquals(200, $image->height());
  263 +
  264 + $file = new \SplFileInfo($pathname);
  265 +
  266 + $this->assertTrue($file->isFile());
  267 +
  268 + @unlink($pathname);
  269 +
  270 + //6
  271 + $image = Image::open($this->getGif());
  272 +
  273 + $image->thumb(200, 200, Image::THUMB_FIXED)->save($pathname);
  274 +
  275 + $this->assertEquals(200, $image->width());
  276 + $this->assertEquals(200, $image->height());
  277 +
  278 + $file = new \SplFileInfo($pathname);
  279 +
  280 + $this->assertTrue($file->isFile());
  281 +
  282 + @unlink($pathname);
  283 + }
  284 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +namespace tests;
  12 +
  13 +use think\Image;
  14 +
  15 +class WaterTest extends TestCase
  16 +{
  17 + public function testJpeg()
  18 + {
  19 + $pathname = TEST_PATH . 'tmp/water.jpg';
  20 + $image = Image::open($this->getJpeg());
  21 +
  22 + $image->water(TEST_PATH . 'images/test.gif')->save($pathname);
  23 +
  24 + $file = new \SplFileInfo($pathname);
  25 +
  26 + $this->assertTrue($file->isFile());
  27 +
  28 + @unlink($pathname);
  29 + }
  30 +
  31 + public function testPng()
  32 + {
  33 + $pathname = TEST_PATH . 'tmp/water.png';
  34 + $image = Image::open($this->getPng());
  35 +
  36 + $image->water(TEST_PATH . 'images/test.gif')->save($pathname);
  37 +
  38 + $file = new \SplFileInfo($pathname);
  39 +
  40 + $this->assertTrue($file->isFile());
  41 +
  42 + @unlink($pathname);
  43 + }
  44 +
  45 + public function testGif()
  46 + {
  47 + $pathname = TEST_PATH . 'tmp/water.gif';
  48 + $image = Image::open($this->getGif());
  49 +
  50 + $image->water(TEST_PATH . 'images/test.jpg')->save($pathname);
  51 +
  52 + $file = new \SplFileInfo($pathname);
  53 +
  54 + $this->assertTrue($file->isFile());
  55 +
  56 + @unlink($pathname);
  57 + }
  58 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +define('TEST_PATH', __DIR__ . '/');
  12 +// 加载框架基础文件
  13 +require __DIR__ . '/../thinkphp/base.php';
  14 +\think\Loader::addNamespace('tests', TEST_PATH);
  15 +\think\Loader::addNamespace('think', __DIR__ . '/../src/');