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 相关文章推荐
一个用于mysql的数据库抽象层函数库
Oct 09 PHP
模拟SQLSERVER的两个函数:dateadd(),datediff()
Oct 09 PHP
模仿OSO的论坛(一)
Oct 09 PHP
一个捕获函数输出的函数
Feb 14 PHP
PHP5 的对象赋值机制介绍
Aug 02 PHP
PHP中将字符串转化为整数(int) intval() printf() 性能测试
Mar 20 PHP
php中读写文件与读写数据库的效率比较分享
Oct 19 PHP
php获取文件内容最后一行示例
Jan 09 PHP
php实现通过ftp上传文件
Jun 19 PHP
CI框架(CodeIgniter)操作redis的方法详解
Jan 25 PHP
php json转换相关知识(小结)
Dec 21 PHP
Laravel框架下载,安装及路由操作图文详解
Dec 04 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实现只保留mysql中最新1000条记录
2015/06/18 PHP
程序员的表白神器“520”大声喊出来
2016/05/20 PHP
基于php判断客户端类型
2016/10/14 PHP
小议javascript 设计模式 推荐
2009/10/28 Javascript
新老版本juqery获取radio对象的方法
2010/03/01 Javascript
js+JQuery返回顶部功能如何实现
2012/12/03 Javascript
Javascript new Date().valueOf()的作用与时间戳由来详解
2013/04/24 Javascript
js实现瀑布流的一种简单方法实例分享
2013/11/04 Javascript
jquery中的$(document).ready()使用小结
2014/02/14 Javascript
jQuery随机密码生成的方法
2015/03/09 Javascript
jquery实现页面关键词高亮显示的方法
2015/03/12 Javascript
jQuery模仿京东/天猫商品左侧分类导航菜单效果
2016/06/29 Javascript
Bootstrap基本插件学习笔记之Popover提示框(19)
2016/12/08 Javascript
整理一些最近经常遇到的前端面试题
2017/04/25 Javascript
Bootstrap table学习笔记(2) 前后端分页模糊查询
2017/05/18 Javascript
angular2+node.js express打包部署的实战
2017/07/27 Javascript
webpack引入eslint配置详解
2018/01/22 Javascript
JS实现的邮箱提示补全效果示例
2018/01/30 Javascript
使用vux实现上拉刷新功能遇到的坑
2018/02/08 Javascript
react-native android状态栏的实现
2018/06/15 Javascript
layui输入框只允许输入中文且判断长度的例子
2019/09/18 Javascript
python模拟登录百度代码分享(获取百度贴吧等级)
2013/12/27 Python
python实现将英文单词表示的数字转换成阿拉伯数字的方法
2015/07/02 Python
深入理解python对json的操作总结
2017/01/05 Python
python 发送和接收ActiveMQ消息的实例
2019/01/30 Python
pycharm修改文件的默认打开方式的步骤
2019/07/29 Python
Python面向对象魔法方法和单例模块代码实例
2020/03/25 Python
解决jupyter notebook 前面书写后面内容消失的问题
2020/04/13 Python
python退出循环的方法
2020/06/18 Python
一篇文章带你学习CSS3图片边框
2020/11/04 HTML / CSS
Rockport乐步美国官网:风靡美国的白宫鞋
2016/11/24 全球购物
WEB控件可以激发服务端事件,请谈谈服务端事件是怎么发生并解释其原理?自动传回是什么?为什么要使用自动传回?
2012/02/21 面试题
如何撰写一封出色的求职信
2014/04/27 职场文书
2015届本科毕业生自我鉴定
2014/09/27 职场文书
浅谈自定义校验注解ConstraintValidator
2021/06/30 Java/Android
MySQL添加索引特点及优化问题
2022/07/23 MySQL