Image.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  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;
  12. use think\image\Exception as ImageException;
  13. use think\image\gif\Gif;
  14. class Image
  15. {
  16. /* 缩略图相关常量定义 */
  17. const THUMB_SCALING = 1; //常量,标识缩略图等比例缩放类型
  18. const THUMB_FILLED = 2; //常量,标识缩略图缩放后填充类型
  19. const THUMB_CENTER = 3; //常量,标识缩略图居中裁剪类型
  20. const THUMB_NORTHWEST = 4; //常量,标识缩略图左上角裁剪类型
  21. const THUMB_SOUTHEAST = 5; //常量,标识缩略图右下角裁剪类型
  22. const THUMB_FIXED = 6; //常量,标识缩略图固定尺寸缩放类型
  23. /* 水印相关常量定义 */
  24. const WATER_NORTHWEST = 1; //常量,标识左上角水印
  25. const WATER_NORTH = 2; //常量,标识上居中水印
  26. const WATER_NORTHEAST = 3; //常量,标识右上角水印
  27. const WATER_WEST = 4; //常量,标识左居中水印
  28. const WATER_CENTER = 5; //常量,标识居中水印
  29. const WATER_EAST = 6; //常量,标识右居中水印
  30. const WATER_SOUTHWEST = 7; //常量,标识左下角水印
  31. const WATER_SOUTH = 8; //常量,标识下居中水印
  32. const WATER_SOUTHEAST = 9; //常量,标识右下角水印
  33. /* 翻转相关常量定义 */
  34. const FLIP_X = 1; //X轴翻转
  35. const FLIP_Y = 2; //Y轴翻转
  36. /**
  37. * 图像资源对象
  38. *
  39. * @var resource
  40. */
  41. protected $im;
  42. /** @var Gif */
  43. protected $gif;
  44. /**
  45. * 图像信息,包括 width, height, type, mime, size
  46. *
  47. * @var array
  48. */
  49. protected $info;
  50. protected function __construct(\SplFileInfo $file)
  51. {
  52. //获取图像信息
  53. $info = @getimagesize($file->getPathname());
  54. //检测图像合法性
  55. if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) {
  56. throw new ImageException('Illegal image file');
  57. }
  58. //设置图像信息
  59. $this->info = [
  60. 'width' => $info[0],
  61. 'height' => $info[1],
  62. 'type' => image_type_to_extension($info[2], false),
  63. 'mime' => $info['mime'],
  64. ];
  65. //打开图像
  66. if ('gif' == $this->info['type']) {
  67. $this->gif = new Gif($file->getPathname());
  68. $this->im = @imagecreatefromstring($this->gif->image());
  69. } else {
  70. $fun = "imagecreatefrom{$this->info['type']}";
  71. $this->im = @$fun($file->getPathname());
  72. }
  73. if (empty($this->im)) {
  74. throw new ImageException('Failed to create image resources!');
  75. }
  76. }
  77. /**
  78. * 打开一个图片文件
  79. * @param \SplFileInfo|string $file
  80. * @return Image
  81. */
  82. public static function open($file)
  83. {
  84. if (is_string($file)) {
  85. $file = new \SplFileInfo($file);
  86. }
  87. if (!$file->isFile()) {
  88. throw new ImageException('image file not exist');
  89. }
  90. return new self($file);
  91. }
  92. /**
  93. * 保存图像
  94. * @param string $pathname 图像保存路径名称
  95. * @param null|string $type 图像类型
  96. * @param int $quality 图像质量
  97. * @param bool $interlace 是否对JPEG类型图像设置隔行扫描
  98. * @return $this
  99. */
  100. public function save($pathname, $type = null, $quality = 80, $interlace = true)
  101. {
  102. //自动获取图像类型
  103. if (is_null($type)) {
  104. $type = $this->info['type'];
  105. } else {
  106. $type = strtolower($type);
  107. }
  108. //保存图像
  109. if ('jpeg' == $type || 'jpg' == $type) {
  110. //JPEG图像设置隔行扫描
  111. imageinterlace($this->im, $interlace);
  112. imagejpeg($this->im, $pathname, $quality);
  113. } elseif ('gif' == $type && !empty($this->gif)) {
  114. $this->gif->save($pathname);
  115. } elseif ('png' == $type) {
  116. //设定保存完整的 alpha 通道信息
  117. imagesavealpha($this->im, true);
  118. //ImagePNG生成图像的质量范围从0到9的
  119. imagepng($this->im, $pathname, min((int) ($quality / 10), 9));
  120. } else {
  121. $fun = 'image' . $type;
  122. $fun($this->im, $pathname);
  123. }
  124. return $this;
  125. }
  126. /**
  127. * http输出图片
  128. * @return void
  129. */
  130. public function output()
  131. {
  132. $type = $this->info['type'];
  133. header("content-type: image/{$type}");
  134. switch ($type) {
  135. case 'png':
  136. imagepng($this->im);
  137. break;
  138. case 'gif':
  139. imagegif($this->im);
  140. break;
  141. case 'jpeg':
  142. imagejpeg($this->im);
  143. break;
  144. case 'wbmp':
  145. imagewbmp($this->im);
  146. break;
  147. }
  148. exit;
  149. }
  150. /**
  151. * 返回图像宽度
  152. * @return int 图像宽度
  153. */
  154. public function width()
  155. {
  156. return $this->info['width'];
  157. }
  158. /**
  159. * 返回图像高度
  160. * @return int 图像高度
  161. */
  162. public function height()
  163. {
  164. return $this->info['height'];
  165. }
  166. /**
  167. * 返回图像类型
  168. * @return string 图像类型
  169. */
  170. public function type()
  171. {
  172. return $this->info['type'];
  173. }
  174. /**
  175. * 返回图像MIME类型
  176. * @return string 图像MIME类型
  177. */
  178. public function mime()
  179. {
  180. return $this->info['mime'];
  181. }
  182. /**
  183. * 返回图像尺寸数组 0 - 图像宽度,1 - 图像高度
  184. * @return array 图像尺寸
  185. */
  186. public function size()
  187. {
  188. return [$this->info['width'], $this->info['height']];
  189. }
  190. /**
  191. * 旋转图像
  192. * @param int $degrees 顺时针旋转的度数
  193. * @return $this
  194. */
  195. public function rotate($degrees = 90)
  196. {
  197. do {
  198. $img = imagerotate($this->im, -$degrees, imagecolorallocatealpha($this->im, 0, 0, 0, 127));
  199. imagedestroy($this->im);
  200. $this->im = $img;
  201. } while (!empty($this->gif) && $this->gifNext());
  202. $this->info['width'] = imagesx($this->im);
  203. $this->info['height'] = imagesy($this->im);
  204. return $this;
  205. }
  206. /**
  207. * 翻转图像
  208. * @param integer $direction 翻转轴,X或者Y
  209. * @return $this
  210. */
  211. public function flip($direction = self::FLIP_X)
  212. {
  213. //原图宽度和高度
  214. $w = $this->info['width'];
  215. $h = $this->info['height'];
  216. do {
  217. $img = imagecreatetruecolor($w, $h);
  218. switch ($direction) {
  219. case self::FLIP_X:
  220. for ($y = 0; $y < $h; $y++) {
  221. imagecopy($img, $this->im, 0, $h - $y - 1, 0, $y, $w, 1);
  222. }
  223. break;
  224. case self::FLIP_Y:
  225. for ($x = 0; $x < $w; $x++) {
  226. imagecopy($img, $this->im, $w - $x - 1, 0, $x, 0, 1, $h);
  227. }
  228. break;
  229. default:
  230. throw new ImageException('不支持的翻转类型');
  231. }
  232. imagedestroy($this->im);
  233. $this->im = $img;
  234. } while (!empty($this->gif) && $this->gifNext());
  235. return $this;
  236. }
  237. /**
  238. * 裁剪图像
  239. *
  240. * @param integer $w 裁剪区域宽度
  241. * @param integer $h 裁剪区域高度
  242. * @param integer $x 裁剪区域x坐标
  243. * @param integer $y 裁剪区域y坐标
  244. * @param integer $width 图像保存宽度
  245. * @param integer $height 图像保存高度
  246. *
  247. * @return $this
  248. */
  249. public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null)
  250. {
  251. //设置保存尺寸
  252. empty($width) && $width = $w;
  253. empty($height) && $height = $h;
  254. do {
  255. //创建新图像
  256. $img = imagecreatetruecolor((int) $width, (int) $height);
  257. // 调整默认颜色
  258. $color = imagecolorallocate($img, 255, 255, 255);
  259. imagefill($img, 0, 0, $color);
  260. //裁剪
  261. imagecopyresampled($img, $this->im, 0, 0, (int) $x, (int) $y, (int) $width, (int) $height, $w, $h);
  262. imagedestroy($this->im); //销毁原图
  263. //设置新图像
  264. $this->im = $img;
  265. } while (!empty($this->gif) && $this->gifNext());
  266. $this->info['width'] = (int) $width;
  267. $this->info['height'] = (int) $height;
  268. return $this;
  269. }
  270. /**
  271. * 生成缩略图
  272. *
  273. * @param integer $width 缩略图最大宽度
  274. * @param integer $height 缩略图最大高度
  275. * @param int $type 缩略图裁剪类型
  276. *
  277. * @return $this
  278. */
  279. public function thumb($width, $height, $type = self::THUMB_SCALING)
  280. {
  281. //原图宽度和高度
  282. $w = $this->info['width'];
  283. $h = $this->info['height'];
  284. /* 计算缩略图生成的必要参数 */
  285. switch ($type) {
  286. /* 等比例缩放 */
  287. case self::THUMB_SCALING:
  288. //原图尺寸小于缩略图尺寸则不进行缩略
  289. if ($w < $width && $h < $height) {
  290. return $this;
  291. }
  292. //计算缩放比例
  293. $scale = min($width / $w, $height / $h);
  294. //设置缩略图的坐标及宽度和高度
  295. $x = $y = 0;
  296. $width = (int) ($w * $scale);
  297. $height = (int) ($h * $scale);
  298. break;
  299. /* 居中裁剪 */
  300. case self::THUMB_CENTER:
  301. //计算缩放比例
  302. $scale = max($width / $w, $height / $h);
  303. //设置缩略图的坐标及宽度和高度
  304. $w = (int) ($width / $scale);
  305. $h = (int) ($height / $scale);
  306. $x = (int) (($this->info['width'] - $w) / 2);
  307. $y = (int) (($this->info['height'] - $h) / 2);
  308. break;
  309. /* 左上角裁剪 */
  310. case self::THUMB_NORTHWEST:
  311. //计算缩放比例
  312. $scale = max($width / $w, $height / $h);
  313. //设置缩略图的坐标及宽度和高度
  314. $x = $y = 0;
  315. $w = (int) ($width / $scale);
  316. $h = (int) ($height / $scale);
  317. break;
  318. /* 右下角裁剪 */
  319. case self::THUMB_SOUTHEAST:
  320. //计算缩放比例
  321. $scale = max($width / $w, $height / $h);
  322. //设置缩略图的坐标及宽度和高度
  323. $w = (int) ($width / $scale);
  324. $h = (int) ($height / $scale);
  325. $x = (int) ($this->info['width'] - $w);
  326. $y = (int) ($this->info['height'] - $h);
  327. break;
  328. /* 填充 */
  329. case self::THUMB_FILLED:
  330. //计算缩放比例
  331. if ($w < $width && $h < $height) {
  332. $scale = 1;
  333. } else {
  334. $scale = min($width / $w, $height / $h);
  335. }
  336. //设置缩略图的坐标及宽度和高度
  337. $neww = (int) ($w * $scale);
  338. $newh = (int) ($h * $scale);
  339. $x = $this->info['width'] - $w;
  340. $y = $this->info['height'] - $h;
  341. $posx = (int) (($width - $w * $scale) / 2);
  342. $posy = (int) (($height - $h * $scale) / 2);
  343. do {
  344. //创建新图像
  345. $img = imagecreatetruecolor($width, $height);
  346. // 调整默认颜色
  347. $color = imagecolorallocate($img, 255, 255, 255);
  348. imagefill($img, 0, 0, $color);
  349. //裁剪
  350. imagecopyresampled($img, $this->im, $posx, $posy, $x, $y, $neww, $newh, $w, $h);
  351. imagedestroy($this->im); //销毁原图
  352. $this->im = $img;
  353. } while (!empty($this->gif) && $this->gifNext());
  354. $this->info['width'] = (int) $width;
  355. $this->info['height'] = (int) $height;
  356. return $this;
  357. /* 固定 */
  358. case self::THUMB_FIXED:
  359. $x = $y = 0;
  360. break;
  361. default:
  362. throw new ImageException('不支持的缩略图裁剪类型');
  363. }
  364. /* 裁剪图像 */
  365. return $this->crop($w, $h, $x, $y, $width, $height);
  366. }
  367. /**
  368. * 添加水印
  369. *
  370. * @param string $source 水印图片路径
  371. * @param int|array $locate 水印位置
  372. * @param int $alpha 透明度
  373. * @return $this
  374. */
  375. public function water($source, $locate = self::WATER_SOUTHEAST, $alpha = 100)
  376. {
  377. if (!is_file($source)) {
  378. throw new ImageException('水印图像不存在');
  379. }
  380. //获取水印图像信息
  381. $info = getimagesize($source);
  382. if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) {
  383. throw new ImageException('非法水印文件');
  384. }
  385. //创建水印图像资源
  386. $fun = 'imagecreatefrom' . image_type_to_extension($info[2], false);
  387. $water = $fun($source);
  388. //设定水印图像的混色模式
  389. imagealphablending($water, true);
  390. /* 设定水印位置 */
  391. switch ($locate) {
  392. /* 右下角水印 */
  393. case self::WATER_SOUTHEAST:
  394. $x = $this->info['width'] - $info[0];
  395. $y = $this->info['height'] - $info[1];
  396. break;
  397. /* 左下角水印 */
  398. case self::WATER_SOUTHWEST:
  399. $x = 0;
  400. $y = $this->info['height'] - $info[1];
  401. break;
  402. /* 左上角水印 */
  403. case self::WATER_NORTHWEST:
  404. $x = $y = 0;
  405. break;
  406. /* 右上角水印 */
  407. case self::WATER_NORTHEAST:
  408. $x = $this->info['width'] - $info[0];
  409. $y = 0;
  410. break;
  411. /* 居中水印 */
  412. case self::WATER_CENTER:
  413. $x = ($this->info['width'] - $info[0]) / 2;
  414. $y = ($this->info['height'] - $info[1]) / 2;
  415. break;
  416. /* 下居中水印 */
  417. case self::WATER_SOUTH:
  418. $x = ($this->info['width'] - $info[0]) / 2;
  419. $y = $this->info['height'] - $info[1];
  420. break;
  421. /* 右居中水印 */
  422. case self::WATER_EAST:
  423. $x = $this->info['width'] - $info[0];
  424. $y = ($this->info['height'] - $info[1]) / 2;
  425. break;
  426. /* 上居中水印 */
  427. case self::WATER_NORTH:
  428. $x = ($this->info['width'] - $info[0]) / 2;
  429. $y = 0;
  430. break;
  431. /* 左居中水印 */
  432. case self::WATER_WEST:
  433. $x = 0;
  434. $y = ($this->info['height'] - $info[1]) / 2;
  435. break;
  436. default:
  437. /* 自定义水印坐标 */
  438. if (is_array($locate)) {
  439. list($x, $y) = $locate;
  440. } else {
  441. throw new ImageException('不支持的水印位置类型');
  442. }
  443. }
  444. do {
  445. //添加水印
  446. $src = imagecreatetruecolor($info[0], $info[1]);
  447. // 调整默认颜色
  448. $color = imagecolorallocate($src, 255, 255, 255);
  449. imagefill($src, 0, 0, $color);
  450. imagecopy($src, $this->im, 0, 0, (int) $x, (int) $y, $info[0], $info[1]);
  451. imagecopy($src, $water, 0, 0, 0, 0, $info[0], $info[1]);
  452. imagecopymerge($this->im, $src, (int) $x, (int) $y, 0, 0, $info[0], $info[1], $alpha);
  453. //销毁临时图片资源
  454. imagedestroy($src);
  455. } while (!empty($this->gif) && $this->gifNext());
  456. //销毁水印资源
  457. imagedestroy($water);
  458. return $this;
  459. }
  460. /**
  461. * 图像添加文字
  462. *
  463. * @param string $text 添加的文字
  464. * @param string $font 字体路径
  465. * @param integer $size 字号
  466. * @param string $color 文字颜色
  467. * @param int|array $locate 文字写入位置
  468. * @param integer|array $offset 文字相对当前位置的偏移量
  469. * @param integer $angle 文字倾斜角度
  470. *
  471. * @return $this
  472. * @throws ImageException
  473. */
  474. public function text($text, $font, $size, $color = '#00000000',
  475. $locate = self::WATER_SOUTHEAST, $offset = 0, $angle = 0) {
  476. if (!is_file($font)) {
  477. throw new ImageException("不存在的字体文件:{$font}");
  478. }
  479. //获取文字信息
  480. $info = imagettfbbox($size, $angle, $font, $text);
  481. $minx = min($info[0], $info[2], $info[4], $info[6]);
  482. $maxx = max($info[0], $info[2], $info[4], $info[6]);
  483. $miny = min($info[1], $info[3], $info[5], $info[7]);
  484. $maxy = max($info[1], $info[3], $info[5], $info[7]);
  485. /* 计算文字初始坐标和尺寸 */
  486. $x = $minx;
  487. $y = abs($miny);
  488. $w = $maxx - $minx;
  489. $h = $maxy - $miny;
  490. /* 设定文字位置 */
  491. switch ($locate) {
  492. /* 右下角文字 */
  493. case self::WATER_SOUTHEAST:
  494. $x += $this->info['width'] - $w;
  495. $y += $this->info['height'] - $h;
  496. break;
  497. /* 左下角文字 */
  498. case self::WATER_SOUTHWEST:
  499. $y += $this->info['height'] - $h;
  500. break;
  501. /* 左上角文字 */
  502. case self::WATER_NORTHWEST:
  503. // 起始坐标即为左上角坐标,无需调整
  504. break;
  505. /* 右上角文字 */
  506. case self::WATER_NORTHEAST:
  507. $x += $this->info['width'] - $w;
  508. break;
  509. /* 居中文字 */
  510. case self::WATER_CENTER:
  511. $x += ($this->info['width'] - $w) / 2;
  512. $y += ($this->info['height'] - $h) / 2;
  513. break;
  514. /* 下居中文字 */
  515. case self::WATER_SOUTH:
  516. $x += ($this->info['width'] - $w) / 2;
  517. $y += $this->info['height'] - $h;
  518. break;
  519. /* 右居中文字 */
  520. case self::WATER_EAST:
  521. $x += $this->info['width'] - $w;
  522. $y += ($this->info['height'] - $h) / 2;
  523. break;
  524. /* 上居中文字 */
  525. case self::WATER_NORTH:
  526. $x += ($this->info['width'] - $w) / 2;
  527. break;
  528. /* 左居中文字 */
  529. case self::WATER_WEST:
  530. $y += ($this->info['height'] - $h) / 2;
  531. break;
  532. default:
  533. /* 自定义文字坐标 */
  534. if (is_array($locate)) {
  535. list($posx, $posy) = $locate;
  536. $x += $posx;
  537. $y += $posy;
  538. } else {
  539. throw new ImageException('不支持的文字位置类型');
  540. }
  541. }
  542. /* 设置偏移量 */
  543. if (is_array($offset)) {
  544. $offset = array_map('intval', $offset);
  545. list($ox, $oy) = $offset;
  546. } else {
  547. $offset = intval($offset);
  548. $ox = $oy = $offset;
  549. }
  550. /* 图片黑白检测 */
  551. if ("auto" == $color) {
  552. //X方向采集宽度:单英文字符占据宽度约为字体大小/1.6,单中文字符占据宽度约为字体大小*4/3;Y方向采集宽度:英文字符高度约为字体大小,中文会高一些。
  553. //使用保守宽度,以免在纯英文情况下采集区域超出图像范围,并且精度完全可以满足本功能。
  554. $pickX = intval(mb_strwidth($text) * ($size / 1.6));
  555. $pickY = $size;
  556. $brightness = 0;
  557. for ($i = $x + $ox; $i < $pickX + $x + $ox; $i++) {
  558. //根据文字基线确定要进行遍历的像素
  559. for ($j = $y + $oy - $pickY; $j < $y + $oy; $j++) {
  560. //基线修正
  561. $brightness += self::getBrightnessOfPixel($i, $j);
  562. }
  563. }
  564. $color = $brightness / ($pickX * $pickY) > 127 ? '#00000000' : '#ffffffff';
  565. }
  566. /* 设置颜色 */
  567. if (is_string($color) && 0 === strpos($color, '#')) {
  568. $color = str_split(substr($color, 1), 2);
  569. $color = array_map('hexdec', $color);
  570. if (empty($color[3]) || $color[3] > 127) {
  571. $color[3] = 0;
  572. }
  573. } elseif (!is_array($color)) {
  574. throw new ImageException('错误的颜色值');
  575. }
  576. do {
  577. /* 写入文字 */
  578. $col = imagecolorallocatealpha($this->im, $color[0], $color[1], $color[2], $color[3]);
  579. imagettftext($this->im, $size, $angle, $x + $ox, $y + $oy, $col, $font, $text);
  580. } while (!empty($this->gif) && $this->gifNext());
  581. return $this;
  582. }
  583. /**
  584. * 获取图片指定像素点的亮度值
  585. */
  586. private function getBrightnessOfPixel($x, $y)
  587. {
  588. $rgb = imagecolorat($this->im, $x, $y);
  589. $r = ($rgb >> 16) & 0xFF;
  590. $g = ($rgb >> 8) & 0xFF;
  591. $b = $rgb & 0xFF;
  592. //红绿蓝能量不同,亮度不同,对应系数也不同(参考https://www.w3.org/TR/AERT/#color-contrast)
  593. $brightness = intval($r * 0.299 + $g * 0.587 + $b * 0.114);
  594. return $brightness;
  595. }
  596. /**
  597. * 切换到GIF的下一帧并保存当前帧
  598. */
  599. protected function gifNext()
  600. {
  601. ob_start();
  602. ob_implicit_flush(0);
  603. imagegif($this->im);
  604. $img = ob_get_clean();
  605. $this->gif->image($img);
  606. $next = $this->gif->nextImage();
  607. if ($next) {
  608. imagedestroy($this->im);
  609. $this->im = imagecreatefromstring($next);
  610. return $next;
  611. } else {
  612. imagedestroy($this->im);
  613. $this->im = imagecreatefromstring($this->gif->image());
  614. return false;
  615. }
  616. }
  617. /**
  618. * 析构方法,用于销毁图像资源
  619. */
  620. public function __destruct()
  621. {
  622. empty($this->im) || imagedestroy($this->im);
  623. }
  624. }