这几天学习了一下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