diff --git a/composer.json b/composer.json index 98cdadc..5b8a80d 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "tecnickcom/tcpdf": "^6.3", "weiwei/api-doc": "^1.6", "topthink/think-queue": "1.1.4", - "phpoffice/phpword": "^1.0" + "phpoffice/phpword": "^1.0", + "topthink/think-image": "^1.0" }, "autoload": { "psr-4": { diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index 2df67ee..875002b 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -19,7 +19,7 @@ private static $installed = array ( 'aliases' => array ( ), - 'reference' => '0a92e69b830447e8acf0e4eb2b0aef31ebb76d30', + 'reference' => 'ec59e99a8b0104714eafd4ba6da6acbb64f561e7', 'name' => 'topthink/think', ), 'versions' => @@ -76,7 +76,7 @@ private static $installed = array ( 'aliases' => array ( ), - 'reference' => '0a92e69b830447e8acf0e4eb2b0aef31ebb76d30', + 'reference' => 'ec59e99a8b0104714eafd4ba6da6acbb64f561e7', ), 'topthink/think-captcha' => array ( @@ -96,6 +96,15 @@ private static $installed = array ( ), 'reference' => '8ba5f66e68106369fcc3211e7d2dbaf7bc9ce455', ), + 'topthink/think-image' => + array ( + 'pretty_version' => 'v1.0.7', + 'version' => '1.0.7.0', + 'aliases' => + array ( + ), + 'reference' => '8586cf47f117481c6d415b20f7dedf62e79d5512', + ), 'topthink/think-installer' => array ( 'pretty_version' => 'v1.0.14', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 5168eef..e82dc95 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -9,7 +9,7 @@ return array( 'think\\helper\\' => array($vendorDir . '/topthink/think-helper/src'), 'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'), 'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'), - 'think\\' => array($baseDir . '/thinkphp/library/think', $vendorDir . '/topthink/think-queue/src'), + 'think\\' => array($baseDir . '/thinkphp/library/think', $vendorDir . '/topthink/think-queue/src', $vendorDir . '/topthink/think-image/src'), 'app\\' => array($baseDir . '/application'), 'PhpOffice\\PhpWord\\' => array($vendorDir . '/phpoffice/phpword/src/PhpWord'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index e49c1ae..09d56a5 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -57,6 +57,7 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd array ( 0 => __DIR__ . '/../..' . '/thinkphp/library/think', 1 => __DIR__ . '/..' . '/topthink/think-queue/src', + 2 => __DIR__ . '/..' . '/topthink/think-image/src', ), 'app\\' => array ( diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 5b56e9a..935569c 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -487,6 +487,53 @@ }, "install-path": "../topthink/think-helper" }, + { + "name": "topthink/think-image", + "version": "v1.0.7", + "version_normalized": "1.0.7.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-image.git", + "reference": "8586cf47f117481c6d415b20f7dedf62e79d5512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-image/zipball/8586cf47f117481c6d415b20f7dedf62e79d5512", + "reference": "8586cf47f117481c6d415b20f7dedf62e79d5512", + "shasum": "" + }, + "require": { + "ext-gd": "*" + }, + "require-dev": { + "phpunit/phpunit": "4.8.*", + "topthink/framework": "^5.0" + }, + "time": "2016-09-29T06:05:43+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP5 Image Package", + "support": { + "issues": "https://github.com/top-think/think-image/issues", + "source": "https://github.com/top-think/think-image/tree/master" + }, + "install-path": "../topthink/think-image" + }, { "name": "topthink/think-installer", "version": "v1.0.14", diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index c7789f6..62a31dc 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -6,7 +6,7 @@ 'aliases' => array ( ), - 'reference' => '0a92e69b830447e8acf0e4eb2b0aef31ebb76d30', + 'reference' => 'ec59e99a8b0104714eafd4ba6da6acbb64f561e7', 'name' => 'topthink/think', ), 'versions' => @@ -63,7 +63,7 @@ 'aliases' => array ( ), - 'reference' => '0a92e69b830447e8acf0e4eb2b0aef31ebb76d30', + 'reference' => 'ec59e99a8b0104714eafd4ba6da6acbb64f561e7', ), 'topthink/think-captcha' => array ( @@ -83,6 +83,15 @@ ), 'reference' => '8ba5f66e68106369fcc3211e7d2dbaf7bc9ce455', ), + 'topthink/think-image' => + array ( + 'pretty_version' => 'v1.0.7', + 'version' => '1.0.7.0', + 'aliases' => + array ( + ), + 'reference' => '8586cf47f117481c6d415b20f7dedf62e79d5512', + ), 'topthink/think-installer' => array ( 'pretty_version' => 'v1.0.14', diff --git a/vendor/topthink/think-image/.gitignore b/vendor/topthink/think-image/.gitignore new file mode 100644 index 0000000..828149d --- /dev/null +++ b/vendor/topthink/think-image/.gitignore @@ -0,0 +1,4 @@ +/vendor/ +/thinkphp/ +/composer.lock +/.idea/ \ No newline at end of file diff --git a/vendor/topthink/think-image/.travis.yml b/vendor/topthink/think-image/.travis.yml new file mode 100644 index 0000000..28ef8fb --- /dev/null +++ b/vendor/topthink/think-image/.travis.yml @@ -0,0 +1,22 @@ +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - hhvm + +matrix: + allow_failures: + - php: 7.0 + - php: hhvm + +before_script: + - composer self-update + - composer install --prefer-source --no-interaction --dev + +script: phpunit --coverage-clover=coverage.xml --configuration=phpunit.xml + +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/vendor/topthink/think-image/LICENSE b/vendor/topthink/think-image/LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/vendor/topthink/think-image/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/topthink/think-image/README.md b/vendor/topthink/think-image/README.md new file mode 100644 index 0000000..866a0b4 --- /dev/null +++ b/vendor/topthink/think-image/README.md @@ -0,0 +1,29 @@ +# The ThinkPHP5 Image Package + +[![Build Status](https://img.shields.io/travis/top-think/think-image.svg)](https://travis-ci.org/top-think/think-image) +[![Coverage Status](https://img.shields.io/codecov/c/github/top-think/think-image.svg)](https://codecov.io/github/top-think/think-image) +[![Downloads](https://img.shields.io/github/downloads/top-think/think-image/total.svg)](https://github.com/top-think/think-image/releases) +[![Releases](https://img.shields.io/github/release/top-think/think-image.svg)](https://github.com/top-think/think-image/releases/latest) +[![Releases Downloads](https://img.shields.io/github/downloads/top-think/think-image/latest/total.svg)](https://github.com/top-think/think-image/releases/latest) +[![Packagist Status](https://img.shields.io/packagist/v/top-think/think-image.svg)](https://packagist.org/packages/topthink/think-image) +[![Packagist Downloads](https://img.shields.io/packagist/dt/top-think/think-image.svg)](https://packagist.org/packages/topthink/think-image) + +## 安装 + +> composer require topthink/think-image + +## 使用 + +~~~ +$image = \think\Image::open('./image.jpg'); +或者 +$image = \think\Image::open(request()->file('image')); + + +$image->crop(...) + ->thumb(...) + ->water(...) + ->text(....) + ->save(..); + +~~~ \ No newline at end of file diff --git a/vendor/topthink/think-image/composer.json b/vendor/topthink/think-image/composer.json new file mode 100644 index 0000000..276d029 --- /dev/null +++ b/vendor/topthink/think-image/composer.json @@ -0,0 +1,26 @@ +{ + "name": "topthink/think-image", + "description": "The ThinkPHP5 Image Package", + "license": "Apache-2.0", + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "require": { + "ext-gd": "*" + }, + "require-dev": { + "topthink/framework": "^5.0", + "phpunit/phpunit": "4.8.*" + }, + "config": { + "preferred-install": "dist" + }, + "autoload": { + "psr-4": { + "think\\": "src" + } + } +} diff --git a/vendor/topthink/think-image/phpunit.xml b/vendor/topthink/think-image/phpunit.xml new file mode 100644 index 0000000..ee93855 --- /dev/null +++ b/vendor/topthink/think-image/phpunit.xml @@ -0,0 +1,20 @@ + + + + + ./tests/ + + + + + + diff --git a/vendor/topthink/think-image/src/Image.php b/vendor/topthink/think-image/src/Image.php new file mode 100644 index 0000000..e28a13d --- /dev/null +++ b/vendor/topthink/think-image/src/Image.php @@ -0,0 +1,610 @@ + +// +---------------------------------------------------------------------- + +namespace think; + +use think\image\Exception as ImageException; +use think\image\gif\Gif; + +class Image +{ + + /* 缩略图相关常量定义 */ + const THUMB_SCALING = 1; //常量,标识缩略图等比例缩放类型 + const THUMB_FILLED = 2; //常量,标识缩略图缩放后填充类型 + const THUMB_CENTER = 3; //常量,标识缩略图居中裁剪类型 + const THUMB_NORTHWEST = 4; //常量,标识缩略图左上角裁剪类型 + const THUMB_SOUTHEAST = 5; //常量,标识缩略图右下角裁剪类型 + const THUMB_FIXED = 6; //常量,标识缩略图固定尺寸缩放类型 + /* 水印相关常量定义 */ + const WATER_NORTHWEST = 1; //常量,标识左上角水印 + const WATER_NORTH = 2; //常量,标识上居中水印 + const WATER_NORTHEAST = 3; //常量,标识右上角水印 + const WATER_WEST = 4; //常量,标识左居中水印 + const WATER_CENTER = 5; //常量,标识居中水印 + const WATER_EAST = 6; //常量,标识右居中水印 + const WATER_SOUTHWEST = 7; //常量,标识左下角水印 + const WATER_SOUTH = 8; //常量,标识下居中水印 + const WATER_SOUTHEAST = 9; //常量,标识右下角水印 + /* 翻转相关常量定义 */ + const FLIP_X = 1; //X轴翻转 + const FLIP_Y = 2; //Y轴翻转 + + /** + * 图像资源对象 + * + * @var resource + */ + protected $im; + + /** @var Gif */ + protected $gif; + + /** + * 图像信息,包括 width, height, type, mime, size + * + * @var array + */ + protected $info; + + protected function __construct(\SplFileInfo $file) + { + //获取图像信息 + $info = @getimagesize($file->getPathname()); + + //检测图像合法性 + if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) { + throw new ImageException('Illegal image file'); + } + + //设置图像信息 + $this->info = [ + 'width' => $info[0], + 'height' => $info[1], + 'type' => image_type_to_extension($info[2], false), + 'mime' => $info['mime'], + ]; + + //打开图像 + if ('gif' == $this->info['type']) { + $this->gif = new Gif($file->getPathname()); + $this->im = @imagecreatefromstring($this->gif->image()); + } else { + $fun = "imagecreatefrom{$this->info['type']}"; + $this->im = @$fun($file->getPathname()); + } + + if (empty($this->im)) { + throw new ImageException('Failed to create image resources!'); + } + + } + + /** + * 打开一个图片文件 + * @param \SplFileInfo|string $file + * @return Image + */ + public static function open($file) + { + if (is_string($file)) { + $file = new \SplFileInfo($file); + } + if (!$file->isFile()) { + throw new ImageException('image file not exist'); + } + return new self($file); + } + + /** + * 保存图像 + * @param string $pathname 图像保存路径名称 + * @param null|string $type 图像类型 + * @param int $quality 图像质量 + * @param bool $interlace 是否对JPEG类型图像设置隔行扫描 + * @return $this + */ + public function save($pathname, $type = null, $quality = 80, $interlace = true) + { + //自动获取图像类型 + if (is_null($type)) { + $type = $this->info['type']; + } else { + $type = strtolower($type); + } + //保存图像 + if ('jpeg' == $type || 'jpg' == $type) { + //JPEG图像设置隔行扫描 + imageinterlace($this->im, $interlace); + imagejpeg($this->im, $pathname, $quality); + } elseif ('gif' == $type && !empty($this->gif)) { + $this->gif->save($pathname); + } elseif ('png' == $type) { + //设定保存完整的 alpha 通道信息 + imagesavealpha($this->im, true); + //ImagePNG生成图像的质量范围从0到9的 + imagepng($this->im, $pathname, min((int) ($quality / 10), 9)); + } else { + $fun = 'image' . $type; + $fun($this->im, $pathname); + } + + return $this; + } + + /** + * 返回图像宽度 + * @return int 图像宽度 + */ + public function width() + { + return $this->info['width']; + } + + /** + * 返回图像高度 + * @return int 图像高度 + */ + public function height() + { + return $this->info['height']; + } + + /** + * 返回图像类型 + * @return string 图像类型 + */ + public function type() + { + return $this->info['type']; + } + + /** + * 返回图像MIME类型 + * @return string 图像MIME类型 + */ + public function mime() + { + return $this->info['mime']; + } + + /** + * 返回图像尺寸数组 0 - 图像宽度,1 - 图像高度 + * @return array 图像尺寸 + */ + public function size() + { + return [$this->info['width'], $this->info['height']]; + } + + /** + * 旋转图像 + * @param int $degrees 顺时针旋转的度数 + * @return $this + */ + public function rotate($degrees = 90) + { + do { + $img = imagerotate($this->im, -$degrees, imagecolorallocatealpha($this->im, 0, 0, 0, 127)); + imagedestroy($this->im); + $this->im = $img; + } while (!empty($this->gif) && $this->gifNext()); + + $this->info['width'] = imagesx($this->im); + $this->info['height'] = imagesy($this->im); + + return $this; + } + + /** + * 翻转图像 + * @param integer $direction 翻转轴,X或者Y + * @return $this + */ + public function flip($direction = self::FLIP_X) + { + //原图宽度和高度 + $w = $this->info['width']; + $h = $this->info['height']; + + do { + + $img = imagecreatetruecolor($w, $h); + + switch ($direction) { + case self::FLIP_X: + for ($y = 0; $y < $h; $y++) { + imagecopy($img, $this->im, 0, $h - $y - 1, 0, $y, $w, 1); + } + break; + case self::FLIP_Y: + for ($x = 0; $x < $w; $x++) { + imagecopy($img, $this->im, $w - $x - 1, 0, $x, 0, 1, $h); + } + break; + default: + throw new ImageException('不支持的翻转类型'); + } + + imagedestroy($this->im); + $this->im = $img; + + } while (!empty($this->gif) && $this->gifNext()); + + return $this; + } + + /** + * 裁剪图像 + * + * @param integer $w 裁剪区域宽度 + * @param integer $h 裁剪区域高度 + * @param integer $x 裁剪区域x坐标 + * @param integer $y 裁剪区域y坐标 + * @param integer $width 图像保存宽度 + * @param integer $height 图像保存高度 + * + * @return $this + */ + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null) + { + //设置保存尺寸 + empty($width) && $width = $w; + empty($height) && $height = $h; + do { + //创建新图像 + $img = imagecreatetruecolor($width, $height); + // 调整默认颜色 + $color = imagecolorallocate($img, 255, 255, 255); + imagefill($img, 0, 0, $color); + //裁剪 + imagecopyresampled($img, $this->im, 0, 0, $x, $y, $width, $height, $w, $h); + imagedestroy($this->im); //销毁原图 + //设置新图像 + $this->im = $img; + } while (!empty($this->gif) && $this->gifNext()); + $this->info['width'] = (int) $width; + $this->info['height'] = (int) $height; + return $this; + } + + /** + * 生成缩略图 + * + * @param integer $width 缩略图最大宽度 + * @param integer $height 缩略图最大高度 + * @param int $type 缩略图裁剪类型 + * + * @return $this + */ + public function thumb($width, $height, $type = self::THUMB_SCALING) + { + //原图宽度和高度 + $w = $this->info['width']; + $h = $this->info['height']; + /* 计算缩略图生成的必要参数 */ + switch ($type) { + /* 等比例缩放 */ + case self::THUMB_SCALING: + //原图尺寸小于缩略图尺寸则不进行缩略 + if ($w < $width && $h < $height) { + return $this; + } + //计算缩放比例 + $scale = min($width / $w, $height / $h); + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $width = $w * $scale; + $height = $h * $scale; + break; + /* 居中裁剪 */ + case self::THUMB_CENTER: + //计算缩放比例 + $scale = max($width / $w, $height / $h); + //设置缩略图的坐标及宽度和高度 + $w = $width / $scale; + $h = $height / $scale; + $x = ($this->info['width'] - $w) / 2; + $y = ($this->info['height'] - $h) / 2; + break; + /* 左上角裁剪 */ + case self::THUMB_NORTHWEST: + //计算缩放比例 + $scale = max($width / $w, $height / $h); + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $w = $width / $scale; + $h = $height / $scale; + break; + /* 右下角裁剪 */ + case self::THUMB_SOUTHEAST: + //计算缩放比例 + $scale = max($width / $w, $height / $h); + //设置缩略图的坐标及宽度和高度 + $w = $width / $scale; + $h = $height / $scale; + $x = $this->info['width'] - $w; + $y = $this->info['height'] - $h; + break; + /* 填充 */ + case self::THUMB_FILLED: + //计算缩放比例 + if ($w < $width && $h < $height) { + $scale = 1; + } else { + $scale = min($width / $w, $height / $h); + } + //设置缩略图的坐标及宽度和高度 + $neww = $w * $scale; + $newh = $h * $scale; + $x = $this->info['width'] - $w; + $y = $this->info['height'] - $h; + $posx = ($width - $w * $scale) / 2; + $posy = ($height - $h * $scale) / 2; + do { + //创建新图像 + $img = imagecreatetruecolor($width, $height); + // 调整默认颜色 + $color = imagecolorallocate($img, 255, 255, 255); + imagefill($img, 0, 0, $color); + //裁剪 + imagecopyresampled($img, $this->im, $posx, $posy, $x, $y, $neww, $newh, $w, $h); + imagedestroy($this->im); //销毁原图 + $this->im = $img; + } while (!empty($this->gif) && $this->gifNext()); + $this->info['width'] = (int) $width; + $this->info['height'] = (int) $height; + return $this; + /* 固定 */ + case self::THUMB_FIXED: + $x = $y = 0; + break; + default: + throw new ImageException('不支持的缩略图裁剪类型'); + } + /* 裁剪图像 */ + return $this->crop($w, $h, $x, $y, $width, $height); + } + + /** + * 添加水印 + * + * @param string $source 水印图片路径 + * @param int $locate 水印位置 + * @param int $alpha 透明度 + * @return $this + */ + public function water($source, $locate = self::WATER_SOUTHEAST, $alpha = 100) + { + if (!is_file($source)) { + throw new ImageException('水印图像不存在'); + } + //获取水印图像信息 + $info = getimagesize($source); + if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) { + throw new ImageException('非法水印文件'); + } + //创建水印图像资源 + $fun = 'imagecreatefrom' . image_type_to_extension($info[2], false); + $water = $fun($source); + //设定水印图像的混色模式 + imagealphablending($water, true); + /* 设定水印位置 */ + switch ($locate) { + /* 右下角水印 */ + case self::WATER_SOUTHEAST: + $x = $this->info['width'] - $info[0]; + $y = $this->info['height'] - $info[1]; + break; + /* 左下角水印 */ + case self::WATER_SOUTHWEST: + $x = 0; + $y = $this->info['height'] - $info[1]; + break; + /* 左上角水印 */ + case self::WATER_NORTHWEST: + $x = $y = 0; + break; + /* 右上角水印 */ + case self::WATER_NORTHEAST: + $x = $this->info['width'] - $info[0]; + $y = 0; + break; + /* 居中水印 */ + case self::WATER_CENTER: + $x = ($this->info['width'] - $info[0]) / 2; + $y = ($this->info['height'] - $info[1]) / 2; + break; + /* 下居中水印 */ + case self::WATER_SOUTH: + $x = ($this->info['width'] - $info[0]) / 2; + $y = $this->info['height'] - $info[1]; + break; + /* 右居中水印 */ + case self::WATER_EAST: + $x = $this->info['width'] - $info[0]; + $y = ($this->info['height'] - $info[1]) / 2; + break; + /* 上居中水印 */ + case self::WATER_NORTH: + $x = ($this->info['width'] - $info[0]) / 2; + $y = 0; + break; + /* 左居中水印 */ + case self::WATER_WEST: + $x = 0; + $y = ($this->info['height'] - $info[1]) / 2; + break; + default: + /* 自定义水印坐标 */ + if (is_array($locate)) { + list($x, $y) = $locate; + } else { + throw new ImageException('不支持的水印位置类型'); + } + } + do { + //添加水印 + $src = imagecreatetruecolor($info[0], $info[1]); + // 调整默认颜色 + $color = imagecolorallocate($src, 255, 255, 255); + imagefill($src, 0, 0, $color); + imagecopy($src, $this->im, 0, 0, $x, $y, $info[0], $info[1]); + imagecopy($src, $water, 0, 0, 0, 0, $info[0], $info[1]); + imagecopymerge($this->im, $src, $x, $y, 0, 0, $info[0], $info[1], $alpha); + //销毁零时图片资源 + imagedestroy($src); + } while (!empty($this->gif) && $this->gifNext()); + //销毁水印资源 + imagedestroy($water); + return $this; + } + + /** + * 图像添加文字 + * + * @param string $text 添加的文字 + * @param string $font 字体路径 + * @param integer $size 字号 + * @param string $color 文字颜色 + * @param int $locate 文字写入位置 + * @param integer $offset 文字相对当前位置的偏移量 + * @param integer $angle 文字倾斜角度 + * + * @return $this + * @throws ImageException + */ + public function text($text, $font, $size, $color = '#00000000', + $locate = self::WATER_SOUTHEAST, $offset = 0, $angle = 0) { + + if (!is_file($font)) { + throw new ImageException("不存在的字体文件:{$font}"); + } + //获取文字信息 + $info = imagettfbbox($size, $angle, $font, $text); + $minx = min($info[0], $info[2], $info[4], $info[6]); + $maxx = max($info[0], $info[2], $info[4], $info[6]); + $miny = min($info[1], $info[3], $info[5], $info[7]); + $maxy = max($info[1], $info[3], $info[5], $info[7]); + /* 计算文字初始坐标和尺寸 */ + $x = $minx; + $y = abs($miny); + $w = $maxx - $minx; + $h = $maxy - $miny; + /* 设定文字位置 */ + switch ($locate) { + /* 右下角文字 */ + case self::WATER_SOUTHEAST: + $x += $this->info['width'] - $w; + $y += $this->info['height'] - $h; + break; + /* 左下角文字 */ + case self::WATER_SOUTHWEST: + $y += $this->info['height'] - $h; + break; + /* 左上角文字 */ + case self::WATER_NORTHWEST: + // 起始坐标即为左上角坐标,无需调整 + break; + /* 右上角文字 */ + case self::WATER_NORTHEAST: + $x += $this->info['width'] - $w; + break; + /* 居中文字 */ + case self::WATER_CENTER: + $x += ($this->info['width'] - $w) / 2; + $y += ($this->info['height'] - $h) / 2; + break; + /* 下居中文字 */ + case self::WATER_SOUTH: + $x += ($this->info['width'] - $w) / 2; + $y += $this->info['height'] - $h; + break; + /* 右居中文字 */ + case self::WATER_EAST: + $x += $this->info['width'] - $w; + $y += ($this->info['height'] - $h) / 2; + break; + /* 上居中文字 */ + case self::WATER_NORTH: + $x += ($this->info['width'] - $w) / 2; + break; + /* 左居中文字 */ + case self::WATER_WEST: + $y += ($this->info['height'] - $h) / 2; + break; + default: + /* 自定义文字坐标 */ + if (is_array($locate)) { + list($posx, $posy) = $locate; + $x += $posx; + $y += $posy; + } else { + throw new ImageException('不支持的文字位置类型'); + } + } + /* 设置偏移量 */ + if (is_array($offset)) { + $offset = array_map('intval', $offset); + list($ox, $oy) = $offset; + } else { + $offset = intval($offset); + $ox = $oy = $offset; + } + /* 设置颜色 */ + if (is_string($color) && 0 === strpos($color, '#')) { + $color = str_split(substr($color, 1), 2); + $color = array_map('hexdec', $color); + if (empty($color[3]) || $color[3] > 127) { + $color[3] = 0; + } + } elseif (!is_array($color)) { + throw new ImageException('错误的颜色值'); + } + do { + /* 写入文字 */ + $col = imagecolorallocatealpha($this->im, $color[0], $color[1], $color[2], $color[3]); + imagettftext($this->im, $size, $angle, $x + $ox, $y + $oy, $col, $font, $text); + } while (!empty($this->gif) && $this->gifNext()); + return $this; + } + + /** + * 切换到GIF的下一帧并保存当前帧 + */ + protected function gifNext() + { + ob_start(); + ob_implicit_flush(0); + imagegif($this->im); + $img = ob_get_clean(); + $this->gif->image($img); + $next = $this->gif->nextImage(); + if ($next) { + imagedestroy($this->im); + $this->im = imagecreatefromstring($next); + return $next; + } else { + imagedestroy($this->im); + $this->im = imagecreatefromstring($this->gif->image()); + return false; + } + } + + /** + * 析构方法,用于销毁图像资源 + */ + public function __destruct() + { + empty($this->im) || imagedestroy($this->im); + } + +} diff --git a/vendor/topthink/think-image/src/image/Exception.php b/vendor/topthink/think-image/src/image/Exception.php new file mode 100644 index 0000000..2ebafd8 --- /dev/null +++ b/vendor/topthink/think-image/src/image/Exception.php @@ -0,0 +1,18 @@ + +// +---------------------------------------------------------------------- + +namespace think\image; + + +class Exception extends \RuntimeException +{ + +} \ No newline at end of file diff --git a/vendor/topthink/think-image/src/image/gif/Decoder.php b/vendor/topthink/think-image/src/image/gif/Decoder.php new file mode 100644 index 0000000..a563092 --- /dev/null +++ b/vendor/topthink/think-image/src/image/gif/Decoder.php @@ -0,0 +1,207 @@ + +// +---------------------------------------------------------------------- + +namespace think\image\gif; + + +class Decoder +{ + public $GIF_buffer = []; + public $GIF_arrays = []; + public $GIF_delays = []; + public $GIF_stream = ""; + public $GIF_string = ""; + public $GIF_bfseek = 0; + public $GIF_screen = []; + public $GIF_global = []; + public $GIF_sorted; + public $GIF_colorS; + public $GIF_colorC; + public $GIF_colorF; + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFDecoder ( $GIF_pointer ) + :: + */ + public function __construct($GIF_pointer) + { + $this->GIF_stream = $GIF_pointer; + $this->getByte(6); // GIF89a + $this->getByte(7); // Logical Screen Descriptor + $this->GIF_screen = $this->GIF_buffer; + $this->GIF_colorF = $this->GIF_buffer[4] & 0x80 ? 1 : 0; + $this->GIF_sorted = $this->GIF_buffer[4] & 0x08 ? 1 : 0; + $this->GIF_colorC = $this->GIF_buffer[4] & 0x07; + $this->GIF_colorS = 2 << $this->GIF_colorC; + if (1 == $this->GIF_colorF) { + $this->getByte(3 * $this->GIF_colorS); + $this->GIF_global = $this->GIF_buffer; + } + + for ($cycle = 1; $cycle;) { + if ($this->getByte(1)) { + switch ($this->GIF_buffer[0]) { + case 0x21: + $this->readExtensions(); + break; + case 0x2C: + $this->readDescriptor(); + break; + case 0x3B: + $cycle = 0; + break; + } + } else { + $cycle = 0; + } + } + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFReadExtension ( ) + :: + */ + public function readExtensions() + { + $this->getByte(1); + for (; ;) { + $this->getByte(1); + if (($u = $this->GIF_buffer[0]) == 0x00) { + break; + } + $this->getByte($u); + /* + * 07.05.2007. + * Implemented a new line for a new function + * to determine the originaly delays between + * frames. + * + */ + if (4 == $u) { + $this->GIF_delays[] = ($this->GIF_buffer[1] | $this->GIF_buffer[2] << 8); + } + } + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFReadExtension ( ) + :: + */ + public function readDescriptor() + { + $this->getByte(9); + $GIF_screen = $this->GIF_buffer; + $GIF_colorF = $this->GIF_buffer[8] & 0x80 ? 1 : 0; + if ($GIF_colorF) { + $GIF_code = $this->GIF_buffer[8] & 0x07; + $GIF_sort = $this->GIF_buffer[8] & 0x20 ? 1 : 0; + } else { + $GIF_code = $this->GIF_colorC; + $GIF_sort = $this->GIF_sorted; + } + $GIF_size = 2 << $GIF_code; + $this->GIF_screen[4] &= 0x70; + $this->GIF_screen[4] |= 0x80; + $this->GIF_screen[4] |= $GIF_code; + if ($GIF_sort) { + $this->GIF_screen[4] |= 0x08; + } + $this->GIF_string = "GIF87a"; + $this->putByte($this->GIF_screen); + if (1 == $GIF_colorF) { + $this->getByte(3 * $GIF_size); + $this->putByte($this->GIF_buffer); + } else { + $this->putByte($this->GIF_global); + } + $this->GIF_string .= chr(0x2C); + $GIF_screen[8] &= 0x40; + $this->putByte($GIF_screen); + $this->getByte(1); + $this->putByte($this->GIF_buffer); + for (; ;) { + $this->getByte(1); + $this->putByte($this->GIF_buffer); + if (($u = $this->GIF_buffer[0]) == 0x00) { + break; + } + $this->getByte($u); + $this->putByte($this->GIF_buffer); + } + $this->GIF_string .= chr(0x3B); + /* + Add frames into $GIF_stream array... + */ + $this->GIF_arrays[] = $this->GIF_string; + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFGetByte ( $len ) + :: + */ + public function getByte($len) + { + $this->GIF_buffer = []; + for ($i = 0; $i < $len; $i++) { + if ($this->GIF_bfseek > strlen($this->GIF_stream)) { + return 0; + } + $this->GIF_buffer[] = ord($this->GIF_stream{$this->GIF_bfseek++}); + } + return 1; + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFPutByte ( $bytes ) + :: + */ + public function putByte($bytes) + { + for ($i = 0; $i < count($bytes); $i++) { + $this->GIF_string .= chr($bytes[$i]); + } + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: PUBLIC FUNCTIONS + :: + :: + :: GIFGetFrames ( ) + :: + */ + public function getFrames() + { + return ($this->GIF_arrays); + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFGetDelays ( ) + :: + */ + public function getDelays() + { + return ($this->GIF_delays); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/src/image/gif/Encoder.php b/vendor/topthink/think-image/src/image/gif/Encoder.php new file mode 100644 index 0000000..688f7a0 --- /dev/null +++ b/vendor/topthink/think-image/src/image/gif/Encoder.php @@ -0,0 +1,222 @@ + +// +---------------------------------------------------------------------- +namespace think\image\gif; + +class Encoder +{ + public $GIF = "GIF89a"; /* GIF header 6 bytes */ + public $VER = "GIFEncoder V2.05"; /* Encoder version */ + public $BUF = []; + public $LOP = 0; + public $DIS = 2; + public $COL = -1; + public $IMG = -1; + public $ERR = [ + 'ERR00' => "Does not supported function for only one image!", + 'ERR01' => "Source is not a GIF image!", + 'ERR02' => "Unintelligible flag ", + 'ERR03' => "Does not make animation from animated GIF source", + ]; + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFEncoder... + :: + */ + public function __construct( + $GIF_src, $GIF_dly, $GIF_lop, $GIF_dis, + $GIF_red, $GIF_grn, $GIF_blu, $GIF_mod + ) + { + if (!is_array($GIF_src)) { + printf("%s: %s", $this->VER, $this->ERR['ERR00']); + exit(0); + } + $this->LOP = ($GIF_lop > -1) ? $GIF_lop : 0; + $this->DIS = ($GIF_dis > -1) ? (($GIF_dis < 3) ? $GIF_dis : 3) : 2; + $this->COL = ($GIF_red > -1 && $GIF_grn > -1 && $GIF_blu > -1) ? + ($GIF_red | ($GIF_grn << 8) | ($GIF_blu << 16)) : -1; + for ($i = 0; $i < count($GIF_src); $i++) { + if (strtolower($GIF_mod) == "url") { + $this->BUF[] = fread(fopen($GIF_src[$i], "rb"), filesize($GIF_src[$i])); + } else if (strtolower($GIF_mod) == "bin") { + $this->BUF[] = $GIF_src[$i]; + } else { + printf("%s: %s ( %s )!", $this->VER, $this->ERR['ERR02'], $GIF_mod); + exit(0); + } + if (substr($this->BUF[$i], 0, 6) != "GIF87a" && substr($this->BUF[$i], 0, 6) != "GIF89a") { + printf("%s: %d %s", $this->VER, $i, $this->ERR['ERR01']); + exit(0); + } + for ($j = (13 + 3 * (2 << (ord($this->BUF[$i]{10}) & 0x07))), $k = true; $k; $j++) { + switch ($this->BUF[$i]{$j}) { + case "!": + if ((substr($this->BUF[$i], ($j + 3), 8)) == "NETSCAPE") { + printf("%s: %s ( %s source )!", $this->VER, $this->ERR['ERR03'], ($i + 1)); + exit(0); + } + break; + case ";": + $k = false; + break; + } + } + } + $this->addHeader(); + for ($i = 0; $i < count($this->BUF); $i++) { + $this->addFrames($i, $GIF_dly[$i]); + } + $this->addFooter(); + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddHeader... + :: + */ + public function addHeader() + { + if (ord($this->BUF[0]{10}) & 0x80) { + $cmap = 3 * (2 << (ord($this->BUF[0]{10}) & 0x07)); + $this->GIF .= substr($this->BUF[0], 6, 7); + $this->GIF .= substr($this->BUF[0], 13, $cmap); + $this->GIF .= "!\377\13NETSCAPE2.0\3\1" . $this->word($this->LOP) . "\0"; + } + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddFrames... + :: + */ + public function addFrames($i, $d) + { + $Locals_img = ''; + $Locals_str = 13 + 3 * (2 << (ord($this->BUF[$i]{10}) & 0x07)); + $Locals_end = strlen($this->BUF[$i]) - $Locals_str - 1; + $Locals_tmp = substr($this->BUF[$i], $Locals_str, $Locals_end); + $Global_len = 2 << (ord($this->BUF[0]{10}) & 0x07); + $Locals_len = 2 << (ord($this->BUF[$i]{10}) & 0x07); + $Global_rgb = substr($this->BUF[0], 13, + 3 * (2 << (ord($this->BUF[0]{10}) & 0x07))); + $Locals_rgb = substr($this->BUF[$i], 13, + 3 * (2 << (ord($this->BUF[$i]{10}) & 0x07))); + $Locals_ext = "!\xF9\x04" . chr(($this->DIS << 2) + 0) . + chr(($d >> 0) & 0xFF) . chr(($d >> 8) & 0xFF) . "\x0\x0"; + if ($this->COL > -1 && ord($this->BUF[$i]{10}) & 0x80) { + for ($j = 0; $j < (2 << (ord($this->BUF[$i]{10}) & 0x07)); $j++) { + if ( + ord($Locals_rgb{3 * $j + 0}) == (($this->COL >> 16) & 0xFF) && + ord($Locals_rgb{3 * $j + 1}) == (($this->COL >> 8) & 0xFF) && + ord($Locals_rgb{3 * $j + 2}) == (($this->COL >> 0) & 0xFF) + ) { + $Locals_ext = "!\xF9\x04" . chr(($this->DIS << 2) + 1) . + chr(($d >> 0) & 0xFF) . chr(($d >> 8) & 0xFF) . chr($j) . "\x0"; + break; + } + } + } + switch ($Locals_tmp{0}) { + case "!": + /** + * @var string $Locals_img ; + */ + $Locals_img = substr($Locals_tmp, 8, 10); + $Locals_tmp = substr($Locals_tmp, 18, strlen($Locals_tmp) - 18); + break; + case ",": + $Locals_img = substr($Locals_tmp, 0, 10); + $Locals_tmp = substr($Locals_tmp, 10, strlen($Locals_tmp) - 10); + break; + } + if (ord($this->BUF[$i]{10}) & 0x80 && $this->IMG > -1) { + if ($Global_len == $Locals_len) { + if ($this->blockCompare($Global_rgb, $Locals_rgb, $Global_len)) { + $this->GIF .= ($Locals_ext . $Locals_img . $Locals_tmp); + } else { + $byte = ord($Locals_img{9}); + $byte |= 0x80; + $byte &= 0xF8; + $byte |= (ord($this->BUF[0]{10}) & 0x07); + $Locals_img{9} = chr($byte); + $this->GIF .= ($Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp); + } + } else { + $byte = ord($Locals_img{9}); + $byte |= 0x80; + $byte &= 0xF8; + $byte |= (ord($this->BUF[$i]{10}) & 0x07); + $Locals_img{9} = chr($byte); + $this->GIF .= ($Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp); + } + } else { + $this->GIF .= ($Locals_ext . $Locals_img . $Locals_tmp); + } + $this->IMG = 1; + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddFooter... + :: + */ + public function addFooter() + { + $this->GIF .= ";"; + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFBlockCompare... + :: + */ + public function blockCompare($GlobalBlock, $LocalBlock, $Len) + { + for ($i = 0; $i < $Len; $i++) { + if ( + $GlobalBlock{3 * $i + 0} != $LocalBlock{3 * $i + 0} || + $GlobalBlock{3 * $i + 1} != $LocalBlock{3 * $i + 1} || + $GlobalBlock{3 * $i + 2} != $LocalBlock{3 * $i + 2} + ) { + return (0); + } + } + return (1); + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFWord... + :: + */ + public function word($int) + { + return (chr($int & 0xFF) . chr(($int >> 8) & 0xFF)); + } + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GetAnimation... + :: + */ + public function getAnimation() + { + return ($this->GIF); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/src/image/gif/Gif.php b/vendor/topthink/think-image/src/image/gif/Gif.php new file mode 100644 index 0000000..b890915 --- /dev/null +++ b/vendor/topthink/think-image/src/image/gif/Gif.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- + +namespace think\image\gif; + +class Gif +{ + /** + * GIF帧列表 + * + * @var array + */ + private $frames = []; + /** + * 每帧等待时间列表 + * + * @var array + */ + private $delays = []; + + /** + * 构造方法,用于解码GIF图片 + * + * @param string $src GIF图片数据 + * @param string $mod 图片数据类型 + * @throws \Exception + */ + public function __construct($src = null, $mod = 'url') + { + if (!is_null($src)) { + if ('url' == $mod && is_file($src)) { + $src = file_get_contents($src); + } + /* 解码GIF图片 */ + try { + $de = new Decoder($src); + $this->frames = $de->getFrames(); + $this->delays = $de->getDelays(); + } catch (\Exception $e) { + throw new \Exception("解码GIF图片出错"); + } + } + } + + /** + * 设置或获取当前帧的数据 + * + * @param string $stream 二进制数据流 + * @return mixed 获取到的数据 + */ + public function image($stream = null) + { + if (is_null($stream)) { + $current = current($this->frames); + return false === $current ? reset($this->frames) : $current; + } + $this->frames[key($this->frames)] = $stream; + } + + /** + * 将当前帧移动到下一帧 + * + * @return string 当前帧数据 + */ + public function nextImage() + { + return next($this->frames); + } + + /** + * 编码并保存当前GIF图片 + * + * @param string $pathname 图片名称 + */ + public function save($pathname) + { + $gif = new Encoder($this->frames, $this->delays, 0, 2, 0, 0, 0, 'bin'); + file_put_contents($pathname, $gif->getAnimation()); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/CropTest.php b/vendor/topthink/think-image/tests/CropTest.php new file mode 100644 index 0000000..26a0531 --- /dev/null +++ b/vendor/topthink/think-image/tests/CropTest.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- +namespace tests; + +use think\Image; + +class CropTest extends TestCase +{ + public function testJpeg() + { + $pathname = TEST_PATH . 'tmp/crop.jpg'; + $image = Image::open($this->getJpeg()); + + $image->crop(200, 200, 100, 100, 300, 300)->save($pathname); + + $this->assertEquals(300, $image->width()); + $this->assertEquals(300, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + public function testPng() + { + $pathname = TEST_PATH . 'tmp/crop.png'; + $image = Image::open($this->getPng()); + + $image->crop(200, 200, 100, 100, 300, 300)->save($pathname); + + $this->assertEquals(300, $image->width()); + $this->assertEquals(300, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + public function testGif() + { + $pathname = TEST_PATH . 'tmp/crop.gif'; + $image = Image::open($this->getGif()); + + $image->crop(200, 200, 100, 100, 300, 300)->save($pathname); + + $this->assertEquals(300, $image->width()); + $this->assertEquals(300, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/FlipTest.php b/vendor/topthink/think-image/tests/FlipTest.php new file mode 100644 index 0000000..bf7a5e2 --- /dev/null +++ b/vendor/topthink/think-image/tests/FlipTest.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- +namespace tests; + +use think\Image; + +class FlipTest extends TestCase +{ + public function testJpeg() + { + $pathname = TEST_PATH . 'tmp/flip.jpg'; + $image = Image::open($this->getJpeg()); + $image->flip()->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + + public function testGif() + { + $pathname = TEST_PATH . 'tmp/flip.gif'; + $image = Image::open($this->getGif()); + $image->flip(Image::FLIP_Y)->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/InfoTest.php b/vendor/topthink/think-image/tests/InfoTest.php new file mode 100644 index 0000000..22132ca --- /dev/null +++ b/vendor/topthink/think-image/tests/InfoTest.php @@ -0,0 +1,60 @@ + +// +---------------------------------------------------------------------- +namespace tests; + +use think\Image; + +class InfoTest extends TestCase +{ + + public function testOpen() + { + $this->setExpectedException("\\think\\image\\Exception"); + Image::open(''); + } + + public function testIllegal() + { + $this->setExpectedException("\\think\\image\\Exception", 'Illegal image file'); + Image::open(TEST_PATH . 'images/test.bmp'); + } + + public function testJpeg() + { + $image = Image::open($this->getJpeg()); + $this->assertEquals(800, $image->width()); + $this->assertEquals(600, $image->height()); + $this->assertEquals('jpeg', $image->type()); + $this->assertEquals('image/jpeg', $image->mime()); + $this->assertEquals([800, 600], $image->size()); + } + + + public function testPng() + { + $image = Image::open($this->getPng()); + $this->assertEquals(800, $image->width()); + $this->assertEquals(600, $image->height()); + $this->assertEquals('png', $image->type()); + $this->assertEquals('image/png', $image->mime()); + $this->assertEquals([800, 600], $image->size()); + } + + public function testGif() + { + $image = Image::open($this->getGif()); + $this->assertEquals(380, $image->width()); + $this->assertEquals(216, $image->height()); + $this->assertEquals('gif', $image->type()); + $this->assertEquals('image/gif', $image->mime()); + $this->assertEquals([380, 216], $image->size()); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/RotateTest.php b/vendor/topthink/think-image/tests/RotateTest.php new file mode 100644 index 0000000..56572d2 --- /dev/null +++ b/vendor/topthink/think-image/tests/RotateTest.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- +namespace tests; + +use think\Image; + +class RotateTest extends TestCase +{ + public function testJpeg() + { + $pathname = TEST_PATH . 'tmp/rotate.jpg'; + $image = Image::open($this->getJpeg()); + $image->rotate(90)->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + public function testGif() + { + $pathname = TEST_PATH . 'tmp/rotate.gif'; + $image = Image::open($this->getGif()); + $image->rotate(90)->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/TestCase.php b/vendor/topthink/think-image/tests/TestCase.php new file mode 100644 index 0000000..89ba1b4 --- /dev/null +++ b/vendor/topthink/think-image/tests/TestCase.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + +namespace tests; + +use think\File; + +abstract class TestCase extends \PHPUnit_Framework_TestCase +{ + + protected function getJpeg() + { + return new File(TEST_PATH . 'images/test.jpg'); + } + + protected function getPng() + { + return new File(TEST_PATH . 'images/test.png'); + } + + protected function getGif() + { + return new File(TEST_PATH . 'images/test.gif'); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/TextTest.php b/vendor/topthink/think-image/tests/TextTest.php new file mode 100644 index 0000000..04506a2 --- /dev/null +++ b/vendor/topthink/think-image/tests/TextTest.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- +namespace tests; + +use think\Image; + +class TextTest extends TestCase +{ + public function testJpeg() + { + $pathname = TEST_PATH . 'tmp/text.jpg'; + $image = Image::open($this->getJpeg()); + + $image->text('test', TEST_PATH . 'images/test.ttf', 12)->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + public function testPng() + { + $pathname = TEST_PATH . 'tmp/text.png'; + $image = Image::open($this->getPng()); + + $image->text('test', TEST_PATH . 'images/test.ttf', 12)->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + public function testGif() + { + $pathname = TEST_PATH . 'tmp/text.gif'; + $image = Image::open($this->getGif()); + + $image->text('test', TEST_PATH . 'images/test.ttf', 12)->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/ThumbTest.php b/vendor/topthink/think-image/tests/ThumbTest.php new file mode 100644 index 0000000..07113c8 --- /dev/null +++ b/vendor/topthink/think-image/tests/ThumbTest.php @@ -0,0 +1,284 @@ + +// +---------------------------------------------------------------------- +namespace tests; + +use think\Image; + +class ThumbTest extends TestCase +{ + public function testJpeg() + { + $pathname = TEST_PATH . 'tmp/thumb.jpg'; + + //1 + $image = Image::open($this->getJpeg()); + + $image->thumb(200, 200, Image::THUMB_CENTER)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //2 + $image = Image::open($this->getJpeg()); + + $image->thumb(200, 200, Image::THUMB_SCALING)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(150, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //3 + $image = Image::open($this->getJpeg()); + + $image->thumb(200, 200, Image::THUMB_FILLED)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //4 + $image = Image::open($this->getJpeg()); + + $image->thumb(200, 200, Image::THUMB_NORTHWEST)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //5 + $image = Image::open($this->getJpeg()); + + $image->thumb(200, 200, Image::THUMB_SOUTHEAST)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //6 + $image = Image::open($this->getJpeg()); + + $image->thumb(200, 200, Image::THUMB_FIXED)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + + public function testPng() + { + $pathname = TEST_PATH . 'tmp/thumb.png'; + + //1 + $image = Image::open($this->getPng()); + + $image->thumb(200, 200, Image::THUMB_CENTER)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //2 + $image = Image::open($this->getPng()); + + $image->thumb(200, 200, Image::THUMB_SCALING)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(150, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //3 + $image = Image::open($this->getPng()); + + $image->thumb(200, 200, Image::THUMB_FILLED)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //4 + $image = Image::open($this->getPng()); + + $image->thumb(200, 200, Image::THUMB_NORTHWEST)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //5 + $image = Image::open($this->getPng()); + + $image->thumb(200, 200, Image::THUMB_SOUTHEAST)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //6 + $image = Image::open($this->getPng()); + + $image->thumb(200, 200, Image::THUMB_FIXED)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + public function testGif() + { + $pathname = TEST_PATH . 'tmp/thumb.gif'; + + //1 + $image = Image::open($this->getGif()); + + $image->thumb(200, 200, Image::THUMB_CENTER)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //2 + $image = Image::open($this->getGif()); + + $image->thumb(200, 200, Image::THUMB_SCALING)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(113, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //3 + $image = Image::open($this->getGif()); + + $image->thumb(200, 200, Image::THUMB_FILLED)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //4 + $image = Image::open($this->getGif()); + + $image->thumb(200, 200, Image::THUMB_NORTHWEST)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //5 + $image = Image::open($this->getGif()); + + $image->thumb(200, 200, Image::THUMB_SOUTHEAST)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + + //6 + $image = Image::open($this->getGif()); + + $image->thumb(200, 200, Image::THUMB_FIXED)->save($pathname); + + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/WaterTest.php b/vendor/topthink/think-image/tests/WaterTest.php new file mode 100644 index 0000000..b6a2bcc --- /dev/null +++ b/vendor/topthink/think-image/tests/WaterTest.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- +namespace tests; + +use think\Image; + +class WaterTest extends TestCase +{ + public function testJpeg() + { + $pathname = TEST_PATH . 'tmp/water.jpg'; + $image = Image::open($this->getJpeg()); + + $image->water(TEST_PATH . 'images/test.gif')->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + public function testPng() + { + $pathname = TEST_PATH . 'tmp/water.png'; + $image = Image::open($this->getPng()); + + $image->water(TEST_PATH . 'images/test.gif')->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } + + public function testGif() + { + $pathname = TEST_PATH . 'tmp/water.gif'; + $image = Image::open($this->getGif()); + + $image->water(TEST_PATH . 'images/test.jpg')->save($pathname); + + $file = new \SplFileInfo($pathname); + + $this->assertTrue($file->isFile()); + + @unlink($pathname); + } +} \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/autoload.php b/vendor/topthink/think-image/tests/autoload.php new file mode 100644 index 0000000..f2e8aae --- /dev/null +++ b/vendor/topthink/think-image/tests/autoload.php @@ -0,0 +1,15 @@ + +// +---------------------------------------------------------------------- +define('TEST_PATH', __DIR__ . '/'); +// 加载框架基础文件 +require __DIR__ . '/../thinkphp/base.php'; +\think\Loader::addNamespace('tests', TEST_PATH); +\think\Loader::addNamespace('think', __DIR__ . '/../src/'); \ No newline at end of file diff --git a/vendor/topthink/think-image/tests/images/test.bmp b/vendor/topthink/think-image/tests/images/test.bmp new file mode 100644 index 0000000..e69de29 diff --git a/vendor/topthink/think-image/tests/images/test.gif b/vendor/topthink/think-image/tests/images/test.gif new file mode 100644 index 0000000..c6d5472 Binary files /dev/null and b/vendor/topthink/think-image/tests/images/test.gif differ diff --git a/vendor/topthink/think-image/tests/images/test.jpg b/vendor/topthink/think-image/tests/images/test.jpg new file mode 100644 index 0000000..4bb6549 Binary files /dev/null and b/vendor/topthink/think-image/tests/images/test.jpg differ diff --git a/vendor/topthink/think-image/tests/images/test.png b/vendor/topthink/think-image/tests/images/test.png new file mode 100644 index 0000000..f4830e3 Binary files /dev/null and b/vendor/topthink/think-image/tests/images/test.png differ diff --git a/vendor/topthink/think-image/tests/images/test.ttf b/vendor/topthink/think-image/tests/images/test.ttf new file mode 100644 index 0000000..4f985c8 Binary files /dev/null and b/vendor/topthink/think-image/tests/images/test.ttf differ diff --git a/vendor/topthink/think-image/tests/tmp/.gitignore b/vendor/topthink/think-image/tests/tmp/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/vendor/topthink/think-image/tests/tmp/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file