🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 实验知识点 * 图片水印以及缩略图的基本原理 * PHP 代码对图片水印以及缩略图具体实现 * 对水印以及缩略功能进行封装 #### 实验环境 * Ubuntu 14.04.5 * Nginx 1.4.6 * PHP 7.2 * `sublime text`文本编辑器。 #### 适合人群 本课程难度为一般,属于初级级别课程,适合具有 PHP 基础的用户,熟悉 PHP 基础知识加深巩固。 # 原理 通过 PHP 的 GD 图形拓展库进行以下操作生成图片水印以及缩略图: 1. 打开图像 2. 操作图像 3. 输出图像 4. 销毁图像 ![图片描述](https://doc.shiyanlou.com/document-uid572534labid4129timestamp1512610694626.png) # 开发准备 因为环境里已经安装了 php-gd 库,所以不用再安装,如果没有安装需要执行`sudo apt install php-gd`命令安装。 首先我们修改 Nginx 配置文件`/etc/nginx/sites-available/default`,执行命令: ~~~bash sudo vim /etc/nginx/sites-available/default ~~~ 注释掉`root /home/shiyanlou/Code/myweb/public`,同时取消`root /usr/share/nginx/html`的注释。 ![图片描述](https://doc.shiyanlou.com/courses/uid871732-20200824-1598237216788) 修改配置文件之后,我们重新加载 nginx 配置: ~~~bash sudo service nginx reload ~~~ 打开`Xfce终端`,依次启动 Nginx 和 PHP 服务: ~~~bash sudo service nginx start sudo service php7.2-fpm start ~~~ 因为我们要在 Nginx 服务器根目录下写入文件,所以首先我们需要修改`/usr/share/nginx/html`目录的权限: ~~~bash sudo chmod 777 -R /usr/share/nginx/html ~~~ 在目录`/usr/share/nginx/html`下,需要下载 2 张图片。首先进入`/usr/share/nginx/html`目录: ~~~bash cd /usr/share/nginx/html ~~~ 然后再下载图片: ~~~bash wget http://labfile.oss.aliyuncs.com/courses/994/image.jpg wget http://labfile.oss.aliyuncs.com/courses/994/shuiyin.png ~~~ ![图片描述](https://doc.shiyanlou.com/courses/uid871732-20200824-1598237517802) # 水印实现 打开`sublime`编辑器 ![此处输入图片的描述](https://doc.shiyanlou.com/document-uid572534labid4129timestamp1512611576905.png) 通过`sublime`编辑器打开文件夹`/var/www/html`并创建文件`watermark.php`。 编辑文件`watermark.php`: ~~~php <?php //打开图像 $image_path = 'image.jpg'; $image_info = getimagesize($image_path); echo "<pre>"; print_r($image_info); echo "</pre>"; ?> ~~~ 然后打开火狐浏览器输入地址`localhost/watermark.php`,可以看到浏览器打印出了变量`image_info`: ![此处输入图片的描述](https://doc.shiyanlou.com/document-uid572534labid4129timestamp1512639802552.png) | 索引 | 意义 | | :-- | :-- | | 0 | 图像宽度的像素值 | | 1 | 图像高度的像素值 | | 2 | 图像的类型,返回的是数字**1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM** | | 3 | 宽度和高度的字符串,可以直接用于 HTML 的`<image>`标签 | | bits | 图像的每种颜色的位数,二进制格式 | | channels | 图像的通道值,RGB 图像默认是 3 | | mime | 图像的 MIME 信息 | 然后接下来删除如下打印相关的代码: ~~~php echo "<pre>"; print_r($image_info); echo "</pre>"; ~~~ 修改文件内容,补充代码为如下所示: **复制过去的代码中,中文会以`???`的形式显示,如果有影响到程序,可以直接删除。** ~~~php <?php //打开图像 $image_path = 'image.jpg'; $image_info = getimagesize($image_path); //取得图像类型的文件后缀 $image_type = image_type_to_extension($image_info[2], false); //在内存中,创建动态图像 $image_fun = "imagecreatefrom$image_type"; $image = $image_fun($image_path); $image2_path = 'shuiyin.png'; $image2_info = getimagesize($image2_path); //取得图像类型的文件后缀 $image2_type = image_type_to_extension($image2_info[2], false); //在内存中,创建动态图像 $image2_fun = "imagecreatefrom$image2_type"; $image2 = $image2_fun($image2_path); //操作图像 //获取image和shuiyin的宽高 $image_x = imagesx($image); $image_y = imagesy($image); $image2_x = imagesx($image2); $image2_y = imagesy($image2); //水印定位到右下角 $x = $image_x - $image2_x; $y = $image_y - $image2_y; imagecopy($image, $image2, $x, $y, 0, 0, $image2_info[0], $image2_info[1]); //销毁水印图像 imagedestroy($image2); // 输出图像 header('Content-type:',$image_info['mime']); $funs = "image$image_type"; $funs($image, null, 100); ?> ~~~ 水印可以是透明的图片或者是带有背景颜色的图片。 GIF 格式的图片可以保存透明信息,但 GIF 格式的图片最多只能有 256 种颜色,因而只能使用在对图片要求不高的场合。 另一种格式:PNG 格式,PNG 格式的图片支持无损压缩,而且可以很好地保存透明信息。 然后 PNG 的透明背景的水印在函数`imagecopymerge()`里显示背景为白色。所以在这里暂时假定都用 PNG 格式的背景透明图片做水印,所以暂时就用函数`imagecopy()`,这样才能使得背景透明的图片正常显示。(在后面小节的类封装会有一个封装新的方法来解决这个问题) ~~~php bool imagecopy ( resource $dst_im , resource $src_im , int $dst_x , int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h ) ~~~ | `imagecopy()`参数 | 意义 | | :-- | :-- | | `dst_im` | 目标图像 | | `src_im` | 被拷贝的源图像 | | `dst_x` | 目标图像开始 x 坐标 | | `dst_y` | 目标图像开始 y 坐标,x,y 同为 0 则从左上角开始 | | `src_x` | 拷贝图像开始 x 坐标 | | `src_y` | 拷贝图像开始 y 坐标,x,y 同为 0 则从左上角开始拷贝 | | `src_w` | 从`src_x`开始,拷贝的宽度 | | `src_h` | 从`src_y`开始,拷贝的高度 | ~~~php bool imagecopymerge ( resource $dst_im , resource $src_im , int $dst_x , int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h , int $pct ) ~~~ 前 8 个参数和函数`imagecopy()`一样,只多出了一个`pct`参数。 | `imagecopymerge()`参数 | 意义 | | :-- | :-- | | `pct` | 图像合并程度,取值 0-100 | 然后打开火狐浏览器输入地址`localhost/watermark.php`就可以看到效果图了: ![此处输入图片的描述](https://doc.shiyanlou.com/document-uid572534labid4129timestamp1512640786979.png) 输出图片也可以是保存图片,编辑`watermark.php`注释掉浏览器输出图像的代码,添加保存到本地的代码: ~~~php //输出图像 // header('Content-type:',$image_info['mime']); // $funs = "image$image_type"; // $funs($image, null, 100); //保存在本地 $funs = "image$image_type"; $funs($image,'watermark.'.$image_type); ~~~ ![图片描述](https://doc.shiyanlou.com/courses/uid871732-20200824-1598238593827) 在终端输入`ls -alh`可以显示当前目录下的文件情况: ![图片描述](https://doc.shiyanlou.com/courses/uid871732-20200824-1598238675485) 然后再浏览器刷新`localhost/watermark.php`页面,此时不会有任何输出。 我们再在终端执行`ls -alh`可以看出生成了图片`watermark.jpeg` ![图片描述](https://doc.shiyanlou.com/courses/uid871732-20200824-1598238785524) 可以用浏览器打开查看输出效果,在终端输入`firefox watermark.jpeg`: ![图片描述](https://doc.shiyanlou.com/courses/uid871732-20200824-1598238851000) # 缩略图实现 接下来我们开始缩略图的实现。在目录下创建文件`thumbnail.php`,输入如下内容: ~~~php <?php // 获取图片路径、以及设置缩略的宽高 $filename = "image.jpg"; $xmax = 500; $ymax = 400; // 开打图像 $image_info = getimagesize($filename); // 获取图像类型 $type = image_type_to_extension($image_info[2], false); // 在内存中,创建一个图像对应的图像类型创建一个新图像 $imagecreate = "imagecreatefrom$type"; // 把图像复制到内存中 $image = $imagecreate($filename); //操作图像 //获取原图的高度和宽度 $x = imagesx($image); $y = imagesy($image); //按比例缩放 if($x >= $y) { $newx = $xmax; $newy = $newx * $y / $x; } else { $newy = $ymax; $newx = $x / $y * $newy; } //创建新图像 $image2 = imagecreatetruecolor($newx, $newy); // 复制图像进行缩略 imagecopyresized($image2, $image, 0, 0, 0, 0, floor($newx), floor($newy), $x, $y); // 销毁图像 imagedestroy($image); // 输出图像 header("Content-type: image/png"); header('Content-type:',$image_info['mime']); $funs = "image$type"; $funs($image2); // 销毁图像 imagedestroy($image2); ?> ~~~ * `imagecreatetruecolor()`新建一个真彩色图像。 * `imagecopyresized()`拷贝图像或图像的一部分并调整大小。 ~~~php bool imagecopyresized( resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y,int dst_w, int dst_h, int src_w, int src_h ) ~~~ 前八项也和上面的函数`imagecopy()`一样,为了方便查看还是全部列出来: | `imagecopyresized()`参数 | 意义 | | :-- | :-- | | `dst_im` | 目标图像 | | `src_im` | 被拷贝的源图像 | | `dst_x` | 目标图像开始 x 坐标 | | `dst_y` | 目标图像开始 y 坐标,`x,y`同为 0 则从左上角开始 | | `src_x` | 拷贝图像开始 x 坐标 | | `src_y` | 拷贝图像开始 y 坐标,`x,y`同为 0 则从左上角开始拷贝 | | `src_w` | 从`src_x`开始,拷贝的宽度 | | `src_h` | 从`src_y`开始,拷贝的高度 | | `dst_w` | 目标图像的宽度 | | `dst_h` | 目标图像的高度 | 然后打开火狐浏览器输入地址`localhost/thumbnail.php`就可以看到效果图了 ![此处输入图片的描述](https://doc.shiyanlou.com/document-uid572534labid4129timestamp1512641150288.png) 有上面的打印出的`image_info()`可知,图片`image.jpg`原始长宽是:819 \* 423 然后由于图像`image.jpg`的长像素比宽的大,所以就是以你所设置的变量`xmax`(长)为界定,然后根据原始图片的宽长比来进行缩放(反之就是长宽比)再乘以变量`xmax`就是缩放后图的宽了,因为要等比例缩放。 保存图片代码逻辑和实现图片水印的一致。这里就不在添加到文件`thumbnail.php`中了。 # 封装 对图片水印与缩略图代码进行封装。 可以自己先封装,要实在是封装不好的话,再看看代码。然后多进行几遍。争取能自己熟练书写出来。提高自己编写代码的能力。 创建文件`image.class.php`,输入下面的代码: ~~~php <?php class Image{ private $image; //内存中的图片 private $info; //图片的基本信息 //打开图片 public function __construct($filepath){ $info = getimagesize($filepath); $this->info=array( 'width'=>$info[0], 'height'=>$info[1], 'type'=>image_type_to_extension($info['2'],false), 'mime'=>$info['mime'] ); $fun = "imagecreatefrom{$this->info['type']}"; $this->image=$fun($filepath); } //操作图片 /** * thumbnail 缩略图 * @param $xmax 设置缩放的宽 * @param $ymax 设置缩放的高 */ public function thumbnail($xmax,$ymax){ //获取原图的高度和宽度 $x = imagesx($this->image); $y = imagesy($this->image); //限制只能缩小 if($x <= $xmax && $y <= $ymax){ return $this->image; } //按比例缩小 if($x >= $y) { $newx = $xmax; $newy = $newx * $y / $x; }else { $newy = $ymax; $newx = $x / $y * $newy; } //创建新图像 $newimage = imagecreatetruecolor($newx, $newy); imagecopyresized($newimage, $this->image, 0, 0, 0, 0, floor($newx), floor($newy), $x, $y); $this->image = $newimage; } /** * waterMark 添加图片水印 * @param $waterMark 水印图片路径 * @param $alpha 透明度 */ public function waterMark($waterMark, $alpha = 0){ $info = getimagesize($waterMark); $type = image_type_to_extension($info[2],false); $funMark = "imagecreatefrom{$type}"; $water = $funMark($waterMark); //获取 image 和 water 的宽高 $image_x = imagesx($this->image); $image_y = imagesy($this->image); $water_x = imagesx($water); $water_y = imagesy($water); //水印定位到右下角 $x = $image_x - $water_x; $y = $image_y - $water_y; $this->imagecopymerge_alpha($this->image, $water, $x, $y, 0, 0, $info[0], $info[1], $alpha); imagedestroy($water); } // 输出图片 /** * show 在浏览器中输出图片 */ public function show(){ header("Content-type:".$this->info['mime']); $funs = "image{$this->info['type']}"; $funs($this->image); } /** * save 把图片保存在硬盘里 * @param $newname 图片命名 */ public function save($newname){ $funs = "image{$this->info['type']}"; $funs($this->image,$newname.'.'.$this->info['type']); } public function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){ $opacity=$pct; // getting the watermark width $w = imagesx($src_im); // getting the watermark height $h = imagesy($src_im); // creating a cut resource $cut = imagecreatetruecolor($src_w, $src_h); // copying that section of the background to the cut imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h); // inverting the opacity $opacity = 100 - $opacity; // placing the watermark now imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h); imagecopymerge($dst_im, $cut, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $opacity); } //销毁图片 public function __destruct(){ imagedestroy($this->image); } } ?> ~~~ 然后创建文件`demo.php`,输入下面的代码实现图片水印: ~~~php <?php //引入Iamge类文件 include 'image.class.php'; $filepath = 'image.jpg'; $image = new Image($filepath); //60是透明度参数默认设置为0 $image->waterMark('shuiyin.png', 60); $image->show(); $image->save('sc_shuiyintu'); ?> ~~~ 在浏览器输入`localhost/demo.php`: ![此处输入图片的描述](https://doc.shiyanlou.com/document-uid572534labid4129timestamp1512643138980.png) 然后在终端输入`ls -alh`查看输出的水印图片文件: ![图片描述](https://doc.shiyanlou.com/courses/uid871732-20200824-1598239753248) 注释掉`demo.php`里的生成水印的代码,添加实现缩略图的代码: ~~~php <?php //引入 Iamge 类文件 include 'image.class.php'; //图片水印 // $filepath = 'image.jpg'; // $image = new Image($filepath); // $image->waterMark('shuiyin.png', 60); // $image->show(); // $image->save('sc_shuiyintu'); //缩略图 $filepath = 'image.jpg'; $image = new Image($filepath); $image->thumbnail(600, 300); $image->show(); $image->save('sc_suoluetu'); ?> ~~~ 在浏览器输入`localhost/demo.php`: ![此处输入图片的描述](https://doc.shiyanlou.com/document-uid572534labid4129timestamp1512643337199.png) 然后在终端输入`ls -alh`查看输出的水印图片文件: ![图片描述](https://doc.shiyanlou.com/courses/uid871732-20200824-1598239994987) [](javascript:;) 完成学习