PHP缩略图生成和图片水印制作

时间:2022-08-23 23:19:32

1.开始

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

2.如何生成缩略图

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

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

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

     也就是:

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

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

      }else {

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

     }

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

 e.g

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

PHP缩略图生成和图片水印制作

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

PHP缩略图生成和图片水印制作

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

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

PHP缩略图生成和图片水印制作

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

PHP缩略图生成和图片水印制作

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

PHP缩略图生成和图片水印制作

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

PHP缩略图生成和图片水印制作

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

 4.类图

PHP缩略图生成和图片水印制作

5.php代码

5.1. 构造函数 __construct()

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
 * image constructor.
 * @param string $imagepath 图片路径
 * @param string $markpath 水印图片路径
 * @param int $new_width 缩略图宽度
 * @param int $new_height 缩略图高度
 * @param int $quality jpg图片格输出质量
 */
public function __construct(string $imagepath,
              string $markpath = null,
              int $new_width = null,
              int $new_height = null,
              int $quality = 75)
{
  $this->imgpath = $_server['document_root'] . $imagepath;
  $this->watermarkpath = $markpath;
  $this->newwidth = $new_width ? $new_width : $this->width;
  $this->newheight = $new_height ? $new_height : $this->height;
  $this->quality = $quality ? $quality : 75;
 
  list($this->width, $this->height, $this->type) = getimagesize($this->imgpath);
  $this->img = $this->_loadimg($this->imgpath, $this->type);
 
 
  //生成缩略图
  $this->_thumb();
  //添加水印图片
  if (!empty($this->watermarkpath)) $this->_addwatermark();
  //输出图片
  $this->_outputimg();
}

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

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * 添加水印
 */
private function _addwatermark()
{
  $ratio = 1 / 5; //水印缩放比率
 
  $width = imagesx($this->newimg);
  $height = imagesy($this->newimg);
 
  $n_width = $width * $ratio;
  $n_height = $width * $ratio;
 
  list($markwidth, $markheight, $marktype) = getimagesize($this->watermarkpath);
 
  if ($n_width > $markwidth) $n_width = $markwidth;
  if ($n_height > $markheight) $n_height = $markheight;
 
  $img = $this->_loadimg($this->watermarkpath, $marktype);
  $img = $this->_thumb1($img, $markwidth, $markheight, $marktype, $n_width, $n_height);
  $markwidth = imagesx($img);
  $markheight = imagesy($img);
  imagecopyresampled($this->newimg, $img, $width - $markwidth - 10, $height - $markheight - 10, 0, 0, $markwidth, $markheight, $markwidth, $markheight);
  imagedestroy($img);
}

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

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

5.4. 完整代码:

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

6.调用

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

e.g.

new image($_path, mark, 400, 200, 100);

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

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。