查看: 232|回复: 0

[PHP代码] PHP-生成缩略图和添加水印图-学习笔记

发表于 2017-1-11 12:00:02
1.开始

在网站上传图片过程,经常用到缩略图功能。这里我自己写了一个图片处理的Image类,能生成缩略图,并且可以添加水印图。

2.如何生成缩略图

生成缩略图,关键的是如何计算缩放比率。

这里,我根据图片等比缩放,宽高的几种常见变化,得出一个算缩放比率算法是,使用新图(即缩略图)的宽高,分别除以原图的宽高,看哪个值大,就取它作为缩放比率:

缩放比率 = Max( { 新图高度 / 原图高度 , 新图宽度 / 原图宽度 } )

也就是:

If ( (新图高度 / 原图高度) > (新图宽度 / 原图宽度 ) ) {

缩放比率 = 新图高度 / 原图高度;

}ELSE {

缩放比率 = 新图宽度 / 原图宽度;

}

这里列出场景的图片缩放场景,及处理方法:

e.g

场景1原图比新图大的情况, 缩放比率 = 新图宽度 / 原图宽度 :

场景2,原图比新图大的情况,b. 缩放比率 = 新图高度 / 原图高度 :

场景3,原图比新图大的情况,而且新图宽高相等,即新图形状是正方形,那么上面的缩放算法也是适用的。

场景4,如果 “新图宽度 >= 原图宽度” ,同时 “新图高度 >= 原图高度”,那么不缩放图片,也不放大图片,保持原图。

场景5,如果 “新图宽度 < 原图宽度”,同时 “新图高度 >= 原图高度” ,那么先设置 “新图高度= 原图高度”,再剪切。

场景6,如果 “新图高度 < 原图高度”,同时 “新图宽度 >= 原图宽度” ,那么先设置 “新图宽度= 原图宽度”,再剪切。

3.如何添加水印图片

添加水印很容易,我这里没考虑那么复杂,主要是控制水印位置在图片的右下角,和控制水印在图片中的大小。如,当目标图片与水印图大小接近,那么需要先等比缩放水印图片,再添加水印图片。

左边两幅图,上面是原图,下面是水印图,右边的缩放后加水印的新图。

4.类图

5.php代码

5.1. 构造函数 __construct()

在Image类中,除了构造函数__construct()是public,其它函数都为private.也就是在函数__construct()中,直接完成了生成缩略图和添加水印图的功能。如果,只生成缩略图而不需要添加水印,那么直接在__construct()的参数$markPath,设置为null即可。

其中,“$this->quality = $quality ? $quality : 75;” 控制输出为JPG图片时,控制图片质量(0-100),默认值为75;

  1. /**
  2. * Image constructor.
  3. * @param string $imagePath 图片路径
  4. * @param string $markPath 水印图片路径
  5. * @param int $new_width 缩略图宽度
  6. * @param int $new_height 缩略图高度
  7. * @param int $quality JPG图片格输出质量
  8. */
  9. public function __construct(string $imagePath,
  10. string $markPath = null,
  11. int $new_width = null,
  12. int $new_height = null,
  13. int $quality = 75)
  14. {
  15. $this->imgPath = $_SERVER['DOCUMENT_ROOT'] . $imagePath;
  16. $this->waterMarkPath = $markPath;
  17. $this->newWidth = $new_width ? $new_width : $this->width;
  18. $this->newHeight = $new_height ? $new_height : $this->height;
  19. $this->quality = $quality ? $quality : 75;
  20. list($this->width, $this->height, $this->type) = getimagesize($this->imgPath);
  21. $this->img = $this->_loadImg($this->imgPath, $this->type);
  22. //生成缩略图
  23. $this->_thumb();
  24. //添加水印图片
  25. if (!empty($this->waterMarkPath)) $this->_addWaterMark();
  26. //输出图片
  27. $this->_outputImg();
  28. }
复制代码

Note: 先生成缩略图,再在新图上添加水印 图片。

5.2. 生成缩略图函数_thumb()

  1. /**
  2. * 缩略图(按等比例,根据设置的宽度和高度进行裁剪)
  3. */
  4. private function _thumb()
  5. {
  6. //如果原图本身小于缩略图,按原图长高
  7. if ($this->newWidth > $this->width) $this->newWidth = $this->width;
  8. if ($this->newHeight > $this->height) $this->newHeight = $this->height;
  9. //背景图长高
  10. $gd_width = $this->newWidth;
  11. $gd_height = $this->newHeight;
  12. //如果缩略图宽高,其中有一边等于原图的宽高,就直接裁剪
  13. if ($gd_width == $this->width || $gd_height == $this->height) {
  14. $this->newWidth = $this->width;
  15. $this->newHeight = $this->height;
  16. } else {
  17. //计算缩放比率
  18. $per = 1;
  19. if (($this->newHeight / $this->height) > ($this->newWidth / $this->width)) {
  20. $per = $this->newHeight / $this->height;
  21. } else {
  22. $per = $this->newWidth / $this->width;
  23. }
  24. if ($per < 1) {
  25. $this->newWidth = $this->width * $per;
  26. $this->newHeight = $this->height * $per;
  27. }
  28. }
  29. $this->newImg = $this->_CreateImg($gd_width, $gd_height, $this->type);
  30. imagecopyresampled($this->newImg, $this->img, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->width, $this->height);
  31. }
复制代码

生成缩略图函数_thumb() ,是按照前面的分析来进行编码。

5.3. 添加水印图片函数 _addWaterMark()

  1. /**
  2. * 添加水印
  3. */
  4. private function _addWaterMark()
  5. {
  6. $ratio = 1 / 5; //水印缩放比率
  7. $Width = imagesx($this->newImg);
  8. $Height = imagesy($this->newImg);
  9. $n_width = $Width * $ratio;
  10. $n_height = $Width * $ratio;
  11. list($markWidth, $markHeight, $markType) = getimagesize($this->waterMarkPath);
  12. if ($n_width > $markWidth) $n_width = $markWidth;
  13. if ($n_height > $markHeight) $n_height = $markHeight;
  14. $Img = $this->_loadImg($this->waterMarkPath, $markType);
  15. $Img = $this->_thumb1($Img, $markWidth, $markHeight, $markType, $n_width, $n_height);
  16. $markWidth = imagesx($Img);
  17. $markHeight = imagesy($Img);
  18. imagecopyresampled($this->newImg, $Img, $Width - $markWidth - 10, $Height - $markHeight - 10, 0, 0, $markWidth, $markHeight, $markWidth, $markHeight);
  19. imagedestroy($Img);
  20. }
复制代码

在添加水印图片中,用到一个_thumb1()函数来缩放水印图片:

  1. /**
  2. * 缩略图(按等比例)
  3. * @param resource $img 图像流
  4. * @param int $width
  5. * @param int $height
  6. * @param int $type
  7. * @param int $new_width
  8. * @param int $new_height
  9. * @return resource
  10. */
  11. private function _thumb1($img, $width, $height, $type, $new_width, $new_height)
  12. {
  13. if ($width < $height) {
  14. $new_width = ($new_height / $height) * $width;
  15. } else {
  16. $new_height = ($new_width / $width) * $height;
  17. }
  18. $newImg = $this->_CreateImg($new_width, $new_height, $type);
  19. imagecopyresampled($newImg, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
  20. return $newImg;
  21. }
复制代码

5.4. 完整代码:

  1. <?php
  2. /**
  3. * 图片处理,生成缩略图和添加水印图片
  4. * Created by PhpStorm.
  5. * User: andy
  6. * Date: 17-1-3
  7. * Time: 上午11:55
  8. */
  9. class Image
  10. {
  11. //原图
  12. private $imgPath; //图片地址
  13. private $width; //图片宽度
  14. private $height; //图片高度
  15. private $type; //图片类型
  16. private $img; //图片(图像流)
  17. //缩略图
  18. private $newImg; //缩略图(图像流)
  19. private $newWidth;
  20. private $newHeight;
  21. //水印图路径
  22. private $waterMarkPath;
  23. //输出图像质量,jpg有效
  24. private $quality;
  25. /**
  26. * Image constructor.
  27. * @param string $imagePath 图片路径
  28. * @param string $markPath 水印图片路径
  29. * @param int $new_width 缩略图宽度
  30. * @param int $new_height 缩略图高度
  31. * @param int $quality JPG图片格输出质量
  32. */
  33. public function __construct(string $imagePath,
  34. string $markPath = null,
  35. int $new_width = null,
  36. int $new_height = null,
  37. int $quality = 75)
  38. {
  39. $this->imgPath = $_SERVER['DOCUMENT_ROOT'] . $imagePath;
  40. $this->waterMarkPath = $markPath;
  41. $this->newWidth = $new_width ? $new_width : $this->width;
  42. $this->newHeight = $new_height ? $new_height : $this->height;
  43. $this->quality = $quality ? $quality : 75;
  44. list($this->width, $this->height, $this->type) = getimagesize($this->imgPath);
  45. $this->img = $this->_loadImg($this->imgPath, $this->type);
  46. //生成缩略图
  47. $this->_thumb();
  48. //添加水印图片
  49. if (!empty($this->waterMarkPath)) $this->_addWaterMark();
  50. //输出图片
  51. $this->_outputImg();
  52. }
  53. /**
  54. *图片输出
  55. */
  56. private function _outputImg()
  57. {
  58. switch ($this->type) {
  59. case 1: // GIF
  60. imagegif($this->newImg, $this->imgPath);
  61. break;
  62. case 2: // JPG
  63. if (intval($this->quality) < 0 || intval($this->quality) > 100) $this->quality = 75;
  64. imagejpeg($this->newImg, $this->imgPath, $this->quality);
  65. break;
  66. case 3: // PNG
  67. imagepng($this->newImg, $this->imgPath);
  68. break;
  69. }
  70. imagedestroy($this->newImg);
  71. imagedestroy($this->img);
  72. }
  73. /**
  74. * 添加水印
  75. */
  76. private function _addWaterMark()
  77. {
  78. $ratio = 1 / 5; //水印缩放比率
  79. $Width = imagesx($this->newImg);
  80. $Height = imagesy($this->newImg);
  81. $n_width = $Width * $ratio;
  82. $n_height = $Width * $ratio;
  83. list($markWidth, $markHeight, $markType) = getimagesize($this->waterMarkPath);
  84. if ($n_width > $markWidth) $n_width = $markWidth;
  85. if ($n_height > $markHeight) $n_height = $markHeight;
  86. $Img = $this->_loadImg($this->waterMarkPath, $markType);
  87. $Img = $this->_thumb1($Img, $markWidth, $markHeight, $markType, $n_width, $n_height);
  88. $markWidth = imagesx($Img);
  89. $markHeight = imagesy($Img);
  90. imagecopyresampled($this->newImg, $Img, $Width - $markWidth - 10, $Height - $markHeight - 10, 0, 0, $markWidth, $markHeight, $markWidth, $markHeight);
  91. imagedestroy($Img);
  92. }
  93. /**
  94. * 缩略图(按等比例,根据设置的宽度和高度进行裁剪)
  95. */
  96. private function _thumb()
  97. {
  98. //如果原图本身小于缩略图,按原图长高
  99. if ($this->newWidth > $this->width) $this->newWidth = $this->width;
  100. if ($this->newHeight > $this->height) $this->newHeight = $this->height;
  101. //背景图长高
  102. $gd_width = $this->newWidth;
  103. $gd_height = $this->newHeight;
  104. //如果缩略图宽高,其中有一边等于原图的宽高,就直接裁剪
  105. if ($gd_width == $this->width || $gd_height == $this->height) {
  106. $this->newWidth = $this->width;
  107. $this->newHeight = $this->height;
  108. } else {
  109. //计算缩放比率
  110. $per = 1;
  111. if (($this->newHeight / $this->height) > ($this->newWidth / $this->width)) {
  112. $per = $this->newHeight / $this->height;
  113. } else {
  114. $per = $this->newWidth / $this->width;
  115. }
  116. if ($per < 1) {
  117. $this->newWidth = $this->width * $per;
  118. $this->newHeight = $this->height * $per;
  119. }
  120. }
  121. $this->newImg = $this->_CreateImg($gd_width, $gd_height, $this->type);
  122. imagecopyresampled($this->newImg, $this->img, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->width, $this->height);
  123. }
  124. /**
  125. * 缩略图(按等比例)
  126. * @param resource $img 图像流
  127. * @param int $width
  128. * @param int $height
  129. * @param int $type
  130. * @param int $new_width
  131. * @param int $new_height
  132. * @return resource
  133. */
  134. private function _thumb1($img, $width, $height, $type, $new_width, $new_height)
  135. {
  136. if ($width < $height) {
  137. $new_width = ($new_height / $height) * $width;
  138. } else {
  139. $new_height = ($new_width / $width) * $height;
  140. }
  141. $newImg = $this->_CreateImg($new_width, $new_height, $type);
  142. imagecopyresampled($newImg, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
  143. return $newImg;
  144. }
  145. /**
  146. * 加载图片
  147. * @param string $imgPath
  148. * @param int $type
  149. * @return resource
  150. */
  151. private function _loadImg($imgPath, $type)
  152. {
  153. switch ($type) {
  154. case 1: // GIF
  155. $img = imagecreatefromgif($imgPath);
  156. break;
  157. case 2: // JPG
  158. $img = imagecreatefromjpeg($imgPath);
  159. break;
  160. case 3: // PNG
  161. $img = imagecreatefrompng($imgPath);
  162. break;
  163. default: //其他类型
  164. Tool::alertBack('不支持当前图片类型.' . $type);
  165. break;
  166. }
  167. return $img;
  168. }
  169. /**
  170. * 创建一个背景图像
  171. * @param int $width
  172. * @param int $height
  173. * @param int $type
  174. * @return resource
  175. */
  176. private function _CreateImg($width, $height, $type)
  177. {
  178. $img = imagecreatetruecolor($width, $height);
  179. switch ($type) {
  180. case 3: //png
  181. imagecolortransparent($img, 0); //设置背景为透明的
  182. imagealphablending($img, false);
  183. imagesavealpha($img, true);
  184. break;
  185. case 4://gif
  186. imagecolortransparent($img, 0);
  187. break;
  188. }
  189. return $img;
  190. }
  191. }
复制代码
Image.class.php

6.调用

调用非常简单,在引入类后,直接new 并输入对应参数即可:

e.g.

  1. new Image($_path, MARK, 400, 200, 100);
复制代码
7.小结

这个Image 类能够生成缩略图,不出现黑边,添加水印图,能根据图片的大小缩放水印图。当然有个缺点,就是不能缩放GIF的动画,因为涉及到帧的处理,比较麻烦。



回复

使用道具 举报