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


Posted in PHP onJanuary 07, 2017

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;

/**
   * 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()

/**
   * 缩略图(按等比例,根据设置的宽度和高度进行裁剪)
   */
  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()    

/**
   * 添加水印
   */
  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()函数来缩放水印图片:

/**
   * 缩略图(按等比例)
   * @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. 完整代码:

<?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的动画,因为涉及到帧的处理,比较麻烦。

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
用PHP读取IMAP邮件
Oct 09 PHP
?算你??的 PHP 程式大小
Dec 06 PHP
PHP实现的汉字拼音转换和公历农历转换类及使用示例
Jul 01 PHP
PHP中绘制图像的一些函数总结
Nov 19 PHP
php网页病毒清除类
Dec 08 PHP
php使用PDO方法详解
Dec 27 PHP
Symfony学习十分钟入门经典教程
Feb 03 PHP
php异步:在php中使用fsockopen curl实现类似异步处理的功能方法
Dec 10 PHP
Laravel框架用户登陆身份验证实现方法详解
Sep 14 PHP
详细对比php中类继承和接口继承
Oct 11 PHP
Yii框架的redis命令使用方法简单示例
Oct 15 PHP
使用laravel指定日志文件记录任意日志
Oct 17 PHP
php使用preg_match()函数验证ip地址的方法
Jan 07 #PHP
PHP实现移除数组中为空或为某值元素的方法
Jan 07 #PHP
PHP中仿制 ecshop验证码实例
Jan 06 #PHP
利用PHP判断文件是否为图片的方法总结
Jan 06 #PHP
基于thinkPHP类的插入数据库操作功能示例
Jan 06 #PHP
PHP 文件上传后端处理实用技巧方法
Jan 06 #PHP
PHP+mysql实现从数据库获取下拉树功能示例
Jan 06 #PHP
You might like
PHP的foreach中使用引用时需要注意的一个问题和解决方法
2014/05/29 PHP
php中关于socket的系列函数总结
2015/05/18 PHP
PHP+MYSQL中文乱码问题
2015/07/01 PHP
PHP中__set()实例用法和基础讲解
2019/07/23 PHP
jquery复选框CHECKBOX全选、反选
2008/08/30 Javascript
javascript检测浏览器flash版本的实现代码
2011/12/06 Javascript
js汉字转拼音实现代码
2013/02/06 Javascript
浅析JavaScript中的事件机制
2015/06/04 Javascript
jquery实现刷新随机变化样式特效(tag标签样式)
2017/02/03 Javascript
jquery实现页面加载效果
2017/02/21 Javascript
vue下使用nginx刷新页面404的问题解决
2019/08/02 Javascript
jQuery 查找元素操作实例小结
2019/10/02 jQuery
Vue数据双向绑定原理实例解析
2020/05/15 Javascript
JavaScript如何使用插值实现图像渐变
2020/06/28 Javascript
Element-UI 使用el-row 分栏布局的教程
2020/10/26 Javascript
ES6中的类(Class)示例详解
2020/12/09 Javascript
[01:31]DOTA2上海特级锦标赛 SECRET战队完整宣传片
2016/03/16 DOTA
Python标准库内置函数complex介绍
2014/11/25 Python
Python实现网站文件的全备份和差异备份
2014/11/30 Python
Ruby元编程基础学习笔记整理
2016/07/02 Python
django实现用户登陆功能详解
2017/12/11 Python
matplotlib设置legend图例代码示例
2017/12/19 Python
Python读取txt内容写入xls格式excel中的方法
2018/10/11 Python
pytorch多进程加速及代码优化方法
2019/08/19 Python
Python魔术方法专题
2020/06/19 Python
python 识别登录验证码图片功能的实现代码(完整代码)
2020/07/03 Python
Python调用飞书发送消息的示例
2020/11/10 Python
详解canvas.toDataURL()报错的解决方案全都在这了
2020/03/31 HTML / CSS
.NET remoting中对象激活的两种方式
2015/06/08 面试题
群众路线自我剖析范文
2014/11/04 职场文书
行政人事主管岗位职责
2015/04/11 职场文书
大学生受助感言
2015/08/01 职场文书
物资采购管理制度
2015/08/06 职场文书
PyQt5结合QtDesigner实现文本框读写操作
2021/06/11 Python
如何设置多台电脑共享打印机?多台电脑共享打印机的方法
2022/04/08 数码科技
Zabbix对Kafka topic积压数据监控的解决方案
2022/07/07 Servers