PHP图片水印类(GD库)

这几天学习了一下GD扩展库,昨天写了一个图片验证码,今天继续写了一个给图片增加水印的类。

什么是图片水印

先来看一下什么是水印:

水印,是指在造纸过程中形成的,“夹”在纸中而不是在纸的表面,迎光透视时可以清晰看到有明暗纹理的图形、人像或文字,它是纸张在生产过程中用改变纸浆纤维密度的方法而制成的。通常人民币、购物卷、粮票、证劵等等,都采用此方式,以防止造假

类似的,图片水印就是在自己制作的图片或自己网站的图片上贴上一个标签 , 表明作者信息或网站信息,也可以防止别人盗用。
通常水印可以是文字或者另一图片,并且有一定透明度,不影响原图的查看。

PHP生成水印图的步骤

这里的水印可以是文字或者是图片。
1. 打开需要处理的图片
2. 计算水印的位置
3. 增加水印(文字或图片)
4. 保存新图片
5. 释放资源(可以省略,php可以自动释放)

所使用的GD函数

打开和关闭图片就不说了,这里说的是处理图片水印所需要的GD函数

1.计算文本框大小所需要的函数

array imageftbbox ( float $size , float $angle , string $fontfile , string $text [, array $extrainfo ] )

该函数返回文本框四个角的坐标,利用这些坐标就可以计算出文本的宽度和高度了。

2.计算图片大小所需要的函数:

int imagesx ( resource $image )
int imagesy ( resource $image )

imagesx 返回图片宽度,imagesy 返回图片高度

3.贴图函数1

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 )

说明:

将 src_im 图像中坐标从 src_x,src_y 开始,宽度为 src_w,高度为 src_h 的一部分拷贝到 dst_im 图像中坐标为 dst_x 和 dst_y 的位置上。

4.贴图函数2

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 )

说明:

将 src_im 图像中坐标从 src_x,src_y 开始,宽度为 src_w,高度为 src_h 的一部分拷贝到 dst_im 图像中坐标为 dst_x 和 dst_y 的位置上。两图像将根据 pct 来决定合并程度,其值范围从 0 到 100。当 pct = 0 时,实际上什么也没做,当为 100 时对于调色板图像本函数和 imagecopy() 完全一样,它对真彩色图像实现了 alpha 透明。

5.添加文字水印

array imagettftext ( resource $image , float $size , float $angle , int $x , int $y , int $color , string $fontfile , string $text )

说明:使用 TrueType 字体将 指定的 text 写入图像。

更详细的说明:请戳这里

PHP图片水印类

下面的图片水印类所实现的功能:
1. 增加文字水印
2. 增加图片水印
3. 保存水印后的图片
4. 输出水印后的图片
5. 可以在9个固定位置增加水印:左上、上中、右上、左中、居中、右中、左下、下中、右下

使用时需要注意的问题:
1.水印图片或者文字大小不能超过原图的大小,否则会处理失败。
2.保存图片和输出到浏览器同时使用时,需要先输出到浏览器,不然无法保存。

图片水印类代码:ImageStamp.class.php

<?php

/**
 * 图片水印类
 * 支持文字水印和图片水印, 支持水印透明度设置
 * 支持的图片类型: 'jpg', 'png', 'gif'
 * @author luoluolzb 2017/6/17
 */
class ImageStamp
{
    /**
     * 确定水印位置的常量
     * @var const
     */
    const
    STAMP_TOP = 1,
    STAMP_BOTTOM = 2,
    STAMP_LEFT = 4,
    STAMP_RIGHT = 8,
    STAMP_CENTER = 16;

    /**
     * 水印距离图片边缘的距离(非居中时)常量
     * @var const
     */
    const STAMP_SIDE = 10;

    /**
     * 水印默认位置
     * @var const
     */
    const STAMP_DEFAULT_LOC = 10;    //STAMP_BOTTOM | STAMP_RIGHT

    /**
     * @var private
     */
    private $fileName, $mimeString, $imgRes;
    private $imgWidth, $imgHeight;

    /**
     * 打开需要加水印的图片
     * 此函数可以多次使用, 第二次会覆盖第一次
     * @param   string $fileName 图片文件
     * @return  bool   操作结果
     */
    public function Open($fileName){
        if(!file_exists($fileName)){
            return false;
        }
        if($this->imgRes){
            imagedestroy($this->imgRes);
        }

        $this->fileName = $fileName;
        $this->mimeString = self::GetImageMime($fileName);
        $this->imgRes = self::ImageCreate($fileName, $this->mimeString);

        if(! $this->imgRes){
            return false;
        }
        $this->imgWidth = imagesx($this->imgRes);
        $this->imgHeight = imagesy($this->imgRes);
        return true;
    }

    function __destruct(){
        if($this->imgRes){
            imagedestroy($this->imgRes);
        }
    }

    /**
     * 发送图片到浏览器
     * @return  bool   操作结果
     */
    public function Send(){
        if(! $this->imgRes){
            return false;
        }
        header('Content-Type: '.$this->mimeString);
        if($this->mimeString === 'image/jpeg'){
            return imagejpeg($this->imgRes);
        }
        else if($this->mimeString === 'image/png'){
            return imagepng($this->imgRes);
        }
        else if($this->mimeString === 'image/gif'){
            return imagegif($this->imgRes);
        }
        return false;
    }

    /**
     * 保存图片(文件后缀名决定保存类型, 只能是:jpg, png, gif)
     * @return  bool   操作结果
     */
    public function Save($fileName){
        if(! $this->imgRes){
            return false;
        }
        $t = explode('.', $fileName);
        $ext = end($t);
        if($ext === 'jpg'){
            return imagejpeg($this->imgRes, $fileName);
        }
        else if($ext === 'png'){
            return imagepng($this->imgRes, $fileName);
        }
        else if($ext === 'gif'){
            return imagegif($this->imgRes, $fileName);
        }
        return false;
    }

    /**
     * 给图片添加文字水印
     * @param   string  $text     文字
     * @param   integer $fontSize 字体大小
     * @param   string  $fontFile 字体文件
     * @param   array   $rgba     颜色(rgb+alpha格式, alpha:0-127, 0完全不透明, 127完全透明)
     * @param   integer $location 水印位置(水印位置常量组合而成,使用'|'运算符)
     * @return  bool   操作结果
     */
    public function AddTextStamp($text, $fontSize, $fontFile, $rgba, $location = self::STAMP_DEFAULT_LOC){
        if(! $this->imgRes){
            return false;
        }

        $color = imagecolorallocatealpha($this->imgRes, $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
        $box = imagettfbbox($fontSize, 0, $fontFile, $text);
        $stampWidth = abs($box[2] - $box[0]);
        $stampHeight = abs($box[7] - $box[1]);

        if($stampWidth >= $this->imgWidth || $stampHeight >= $this->imgHeight){
            return false;
        }
        $loc = $this->StampLocation(true, $stampWidth, $stampHeight, $location);
        return imagettftext($this->imgRes, $fontSize, 0, $loc['x'], $loc['y'], $color, $fontFile, $text);
    }

    /**
     * 给图片添加图片水印
     * @param   string   $stampFile 图片文件
     * @param   $integer $alpha     水印图的透明度(0~100, 0完全透明, 100完全不透明)
     * @param   string   $location  水印位置(水印位置常量组合而成,使用'|'运算符)
     * @return  bool     操作结果
     */
    public function AddImageStamp($stampFile, $alpha, $location = self::STAMP_DEFAULT_LOC){
        if(! $this->imgRes){
            return false;
        }

        $stampMimeString = self::GetImageMime($stampFile);
        $stampRes = self::ImageCreate($stampFile, $stampMimeString);
        if(! $stampRes){
            return false;
        }
        $stampWidth = imagesx($stampRes);
        $stampHeight = imagesy($stampRes);

        if($stampWidth >= $this->imgWidth || $stampHeight >= $this->imgHeight){
            return false;
        }
        $loc = $this->StampLocation(false, imagesx($stampRes), imagesy($stampRes), $location);
        return self::imagecopymerge_alpha($this->imgRes, $stampRes, $loc['x'], $loc['y'], 0, 0, $stampWidth, $stampHeight, $alpha);
    }

    /**
     * 私有工具函数: 计算水印位置
     * @return  array ['x' => , 'y' => ]
     */
    private function StampLocation($isTextStamp, $stampWidth, $stampHeight, $location){
        $ret = array(
            'x' => self::STAMP_SIDE,
            'y' =>self::STAMP_SIDE
        );

        if($location & self::STAMP_LEFT){
            $ret['x'] = self::STAMP_SIDE;
        }
        else if($location & self::STAMP_RIGHT){
            $ret['x'] = $this->imgWidth - $stampWidth - self::STAMP_SIDE;
        }

        if($location & self::STAMP_TOP){
            if($isTextStamp){
                $ret['y'] = $stampHeight + self::STAMP_SIDE;
            }else{
                $ret['y'] = self::STAMP_SIDE;
            }
        }
        else if($location & self::STAMP_BOTTOM){
            if($isTextStamp){
                $ret['y'] = $this->imgHeight - self::STAMP_SIDE;
            }else{
                $ret['y'] = $this->imgHeight - $stampHeight - self::STAMP_SIDE;
            }
        }

        if($location & self::STAMP_CENTER){
            /*竖直方向上的居中*/
            if(($location & self::STAMP_LEFT) || ($location & self::STAMP_RIGHT)){
                if($isTextStamp){
                    $ret['y'] = ($this->imgHeight - $stampHeight) / 2 + $stampHeight;
                }else{
                    $ret['y'] = ($this->imgHeight - $stampHeight) / 2;
                }
            }

            /*水平方向上的居中*/
            else if(($location & self::STAMP_TOP) || ($location & self::STAMP_BOTTOM)){
                $ret['x'] = ($this->imgWidth - $stampWidth) / 2;
            }

            /*水平和竖直都居中*/
            else{
                if($isTextStamp){
                    $ret['y'] = ($this->imgHeight - $stampHeight) / 2 + $stampHeight;
                }else{
                    $ret['y'] = ($this->imgHeight - $stampHeight) / 2;
                }
                $ret['x'] = ($this->imgWidth - $stampWidth) / 2;
            }
        }

        return $ret;
    }

    /**
     * 通用工具函数: 贴图函数, 并可以设置贴图的alpha透明
     * 参数同 imagecopymerge
     */
    public static function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){
        $cut = imagecreatetruecolor($src_w, $src_h); 
        imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h); 
        imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h); 
        imagecopymerge($dst_im, $cut, $dst_x, $dst_y, 0, 0, $src_w, $src_h, $pct); 
    } 

    /**
     * 通用工具函数: 获取图片mime类型
     * @param string $fileName 图片文件
     * @return false 失败, string mime串
     */
    public static function GetImageMime($fileName){
        $fhanle = fopen($fileName,'rb');
        if ($fhanle) { 
            $bytes6 = fread($fhanle, 6);
            fclose($fhanle); 
            if ($bytes6 === false) return false;
            if (substr($bytes6,0,3) == "\xff\xd8\xff") return 'image/jpeg';
            if ($bytes6 == "\x89PNG\x0d\x0a") return 'image/png';
            if ($bytes6 == "GIF87a" || $bytes6 == "GIF89a") return 'image/gif';
        }
        return false;
    }

    /**
     * 通用工具函数: 使用gd库打开图片
     * @param  string $fileName   图片文件
     * @return false 操作失败, string $mimeString 图片mime串
     */
    public static function ImageCreate($fileName, $mimeString){
        switch ($mimeString) {
            case 'image/jpeg':
                return imagecreatefromjpeg($fileName);
                break;

            case 'image/png':
                return imagecreatefrompng($fileName);
                break;

            case 'image/gif':
                return imagecreatefromgif($fileName);
                break;

            default:
                return false;
                break;
        }
    }
}
?>

使用方法:(test-ImageStamp.php

<?php
require 'ImageStamp.class.php';

$imgStamp = new ImageStamp();

/* 增加文字水印 */
$imgStamp->open('3.jpg');          //打开所要处理的图片
$text = 'luoluolzb.cn';            //水印文字
$fontSize = 16;                    //文字大小
$fontFile = 'Monaco.ttf';          //字体文件
$rgba = array(200, 200, 228, 64);  //文字颜色(rgb+alpha格式)

//左上
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_TOP | ImageStamp::STAMP_LEFT
);
//上中
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_TOP | ImageStamp::STAMP_CENTER
);
//右上
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_TOP | ImageStamp::STAMP_RIGHT
);

//左中
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_LEFT | ImageStamp::STAMP_CENTER
);
//居中
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_CENTER
);
//右中
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_RIGHT | ImageStamp::STAMP_CENTER
);

//左下
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_BOTTOM | ImageStamp::STAMP_LEFT
);
//下中
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_BOTTOM | ImageStamp::STAMP_CENTER
);
//右下
$imgStamp->AddTextStamp($text, $fontSize, $fontFile, $rgba,
    ImageStamp::STAMP_BOTTOM | ImageStamp::STAMP_RIGHT
);
$imgStamp->Save('3stamp.jpg');

/* 增加图片水印 */
$imgStamp->open('3.jpg');  //打开所要处理的图片
$alpha = 70;               //水印透明度

$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_TOP | ImageStamp::STAMP_LEFT);    //左上
$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_TOP | ImageStamp::STAMP_CENTER);  //上中
$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_TOP | ImageStamp::STAMP_RIGHT);   //右上

$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_LEFT | ImageStamp::STAMP_CENTER);  //左中
$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_CENTER);                           //居中
$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_RIGHT | ImageStamp::STAMP_CENTER); //右中

$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_BOTTOM | ImageStamp::STAMP_LEFT);   //左下
$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_BOTTOM | ImageStamp::STAMP_CENTER); //下中
$imgStamp->AddImageStamp('stamp.png', $alpha, ImageStamp::STAMP_BOTTOM | ImageStamp::STAMP_RIGHT);  //右下

$imgStamp->Send();
?>

原图:
原图

增加文字水印后:
增加文字水印后

增加图片水印后:
增加图片水印后

代码下载

最后附上完整代码(带有字体文件和例子图片):
链接:https://pan.baidu.com/s/1geA6NPx
密码:i0hv

猜你喜欢

转载自blog.csdn.net/luoluozlb/article/details/73351184