GD图像处理基本技术
目录
GD库的引入和介绍
API:外部提供的应用接口,已经准备好了一套处理某些功能的机制,用户只需要按照指定的数据要求,调用指定的函数或者方法(类)就可以实现某个功能。
1)GD库的概念:Graphics Device,图像处理扩展(外部提供的API),能够允许PHP在脚本中使用对应的函数来实现某些图像制作功能
2)GD库的引入:GD库是外部提供的API,已经被集成到PHP扩展库中,(不需要下载),但是需要在PHP配置文件中开启对应的扩展。GD扩展(GD2)
注意:记得重启Apache
创建画布资源
1)imagecreate(int $x_size , int $y_size):创建一个空白画布(背景色是白色的)
2)imagecreatetruecolor(int $width , int $height):创建一个真彩画布(背景色是黑色的,需要填充)
3)imagecreatefromjpeg(string $filename):打开一个jpeg格式的图片资源
4)imagecreatefromgif(string $filename):打开一个GIF格式资源(PHP中无法实现动态)
5)imagecreatefrompng(string $filename):打开png格式图片资源
如果从已知文件创建图片资源,那么一定要匹配打开方式,否则会出错。
操作画布资源
说明:所有的画布资源操作都是需要指定画布资源,而且都是第一个参数
1)分配颜色:imagecolorallocate(resource $image , int $red , int $green , int $blue):根据RGB三色组给指定画布资源分配一组颜色,会返回一个颜色句柄(一组整数)。
在真彩图片资源中,所有分配的颜色都不会自动给图片资源上色,是用来后续操作图片资源的时候,指定着色的;但是如果当前使用imagecreate创建的图片资源,那么第一个分配的颜色,会自动被着色为图片背景色。
注意:凡是给图片增加内容,基本都需要分配颜色(每一个操作图片的函数之前,都需要先调用分配颜色的函数得到一个颜色)。
2)填充区域:imagefill(resource $image , int $x , int $y , int $color):指定位置开始填充指定颜色
Imagefill的填充逻辑:从指定点开始自动匹配相邻点,如果颜色一致,自动渲染,扩展到全图。
3)画直线:imageline(resource $image , int $x1 , int $y1 , int $x2 , int $y2 , int $color):制作一条直线
4)画矩形:imagerectangle(resource $image , int $x1 , int $y1 , int $x2 , int $y2 , int $color):制作一个矩形
5)画圆弧:imagearc(resource $image , int $cx , int $cy , int $w , int $h , int $s , int $e , int $color):imagearc() 以 cx,cy(图像左上角为 0, 0)为中心在 image 所代表的图像中画一个椭圆弧。w 和 h 分别指定了椭圆的宽度和高度,起始和结束点以 s 和 e 参数以角度指定。0°位于三点钟位置,以顺时针方向绘画。
6)在画布上写字:
imagestring(resource $image , int $font , int $x , int $y , string $s , int $col):用来书写ASCII对应的字符(英文),imagestring() 用 col 颜色将字符串 s 画到 image 所代表的图像的 x,y 坐标处(这是字符串左上角坐标,整幅图像的左上角为 0,0)。如果 font 是 1,2,3,4 或 5,则使用内置字体。
imagettftext(resource $image , float $size , float $angle , int $x , int $y , int $color , string $fontfile , string $text):用来数学任意文字(中文)。需要指定字体路径(ttf文件:默认是Windows/fonts/)
输出画布资源
1)输出为图片文件;以图片文件形式保存到本地文件夹
2)输出为网页图片:以图片展示给HTML(用户):服务器需要告知服务器当前内容是图片(修改响应头)
Image+图片格式:返回值为bool
imagejpeg(resource $image [, string $filename [, int $quality ]]):保存成jpg格式图片,quality 为可选项,范围从 0(最差质量,文件更小)到 100(最佳质量,文件最大)。默认为 IJG 默认的质量值(大约 75)。
imagepng(resource $image [, string $filename ]):保存成png格式图片
imagegif(resource $image [, string $filename ]):保存GIF格式图片
如果图片只是提供了图片资源,不指定保存文件位置,系统认为是输出给浏览器;如果指定了保存位置,系统认为是保存到本地(第二个参数)。
细节1:如果图片输出或者保存出错,浏览器看到的永远是告诉你图片错了,但是绝对不会告知错误原因在哪,需要关闭header图片输出,再看问题。
细节2:如果图片输出之后没有成功,但是关闭header之后也看不到错误:最大的可能是图片输出之前输出了别的额外的内容(喜欢输出pre),应该查看网页源码,看看图片输出之前是否有任何输出:尤其是空格空行。
销毁画布资源
从内存中将画布资源清理掉,释放内存。
imagedestory(resource $image)
获取图片信息
1)获取画布尺寸:imagesx(resource $image),imagesy(resource $image)
2)获取图片尺寸:getimagesize(string $filename [, array &$imageinfo ])
验证码的实现
验证码(CAPTCHA),全自动区分计算机和人类的图灵测试的缩写。由计算机生成并评判,但是必须只有人类才能解答。
图片验证码:计算机将拿到的验证码存放到图片中,然后用户看到然后识别,然后提交给服务器,服务器再根据用户提交的和服务器之前生成的进行比较。
1)实现验证码图片展示
a.生成图片资源:背景色设定
b.生成文字
c.输出图片给浏览器
d.关闭资源
2)实现验证码文字的随机变换:有一串文字可以随机选择
a.制作目标字符串集:从哪里选内容
b.如何随机从字符串中取出对应的汉字:含在在utf-8字符集中一个字占用3个字节,英文字母只占一个字节。
c.随机取出字符
d.将取到的字符放在图片指定位置
3)实现验证码文字的颜色的随机变化
4)实现验证码背景或干扰噪点:增加一些额外不影响用户看,但是会产生模糊效果的内容,(点或者线):imagestring/imageline/imagesetpixel
imagesetpixel — 画一个单一像素
改变文字大小和位置以及其他可变信息
5)实现点击刷新验证码功能:实现验证码在浏览器显示的功能
a.创建一个表单文件,里面有一个img标签能够显示图片
b.实现点击更换验证码。让HTML重新请求PHP脚本,产生一张新的图片。因此需要增加一个点击事件:img的src是否重新发起请求,取决于浏览器;浏览器是否重新发起请求,取决于src是否改变。如何让其点击一次变换一次。
缩略图的实现
1)制作图片缩略图的原理:
缩略图:将原图得到一个较小的图(尺寸上)
缩略图原理:将原图打开,然后放到另一个较小的图片资源中,最后进行保存即可。
2)实现固定宽高的缩略图
a.得到一张原图资源
b.得到一个缩略图资源
c.实现图片采样复制:GD提供了函数:imagecopyresampled(resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h)
d.保存缩略图
e.销毁所有资源:原图和缩略图
3)实现等比例缩放的固定宽或高的缩略图
优点:图片不会变形
缺点:缩略图有些部分需要进行额外填充(白色填充:补白)
1、计算缩略图宽高比和原图宽高比
2、如果缩略图宽高比大于原图宽高比,将缩略图中用原图的高尽可能填满:缩略图的高是完整的,宽度不够(补白);如果缩略图的宽高比小于原图宽高比,将缩略图中用原图的宽尽可能填满:缩略图宽是完整的,高度不够(补白)
3、将图片放到缩略图中间
水印图
水印图:watermark,在某个图片上增加一个透明的印记(马赛克)
水印图用途:版权操作
1)制作图片水印图的原理
水印图制作原理:将一个带有明显标志的图片放到另外一张需要处理的图片之上。
2)实现固定位置的水印图:左上角
a.获取原图资源(放上水印图)
b.获取水印图资源
c.合并图片(把图片合到目标图上)
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 透明。
d.保存输出
e.清除资源
3)实现可选9个位置的水印图:封装制作水印图的函数
a.创建一个制作水印图的函数结构:制作水印图需要提供哪些条件?原图资源,水印图资源,位置选择?9个 透明度,保存位置路径
b.结果是希望产生水印图,但是可能产生成功,返回文件保存名字。但是如果产生失败,返回false,但是还需要告知外界原因:通过引用传参解决
c.水印图前提:原图和对应的水印图都存在
d.判定保存路径是否存在
e.打开原图和水印图资源
1)想办法确定用什么函数来打开图片资源,通过图片的MIME类型:获取图片信息
2)通过MIME类型得到要打开图片的函数:先设定一个数组进行匹配,匹配成功,自动构造创建函数(保存函数)失败则提示错误
3)匹配数据
4)组合函数名字:打开原图资源函数,打开水印图函数,保存水印图函数
f.合并图片资源:产生水印,位置需要计算
1)计算水印提在原图中的位置
2)合并图片资源
g.保存水印图片和销毁资源
实现代码:
<?php
//制作水印图制作函数
/*
*@param1 string $src_image,原图路径
*@param2 string $wat_image,水印图路径
*@param3 string $path,水印图存储路径
*@param4 string $error,记录错误信息的变量
*@param5 int $position = 1,水印图加载位置:1代表左上角以此类推9代表右下角
*@param6 int $pct = 20,透明度,默认20
*/
function watermark($src_image,$wat_image,$path,&$error,$position = 1,$pct = 20){
//验证原图和水印图都存在
if(!is_file($src_image)){
$error = '原图不存在!';
return false;
}
if(!is_file($wat_image)){
$error = '水印图不存在!';
return false;
}
//判定路径保存是否存在
if(!is_dir($path)){
$error = '保存位置不正确!';
return false;
}
//获取图片信息
$src_info = getimagesize($src_image);
$wat_info = getimagesize($wat_image);
//定义一组数据:用来产生对应图片
$allow=array(
'image/jpeg' => 'jpeg',
'image/jpg' => 'jpeg',
'image/gif' => 'gif',
'image/png' => 'png',
'image/pjpeg' => 'pjpeg',
'image/jpeg' => 'jpeg'
);
//匹配数据
if(!array_key_exists($src_info['mime'],$allow)){
$error = '当前文件资源不允许制作水印图';
return false;
}
if(!array_key_exists($wat_info['mime'],$allow)){
$error = '当前水印图不允许做资源使用!';
return false;
}
//组合函数
$src_open = 'imagecreatefrom'.$allow[$src_info['mime']];
$wat_open = 'imagecreatefrom'.$allow[$wat_info['mime']];
$src_save = 'image'.$allow[$src_info['mime']];
//打开资源
$src = $src_open($src_image);
$wat = $wat_open($wat_image);
//计算水印图在原图中的位置
$start_x = $start_y = 0;
switch($position){
case 1: //左上角
break;
case 2: //上中间
$start_x = ceil(($src_info[0] - $wat_info[0]) / 2);
break;
case 3: //右上
$start_x = $src_info[0] - $wat_info[0];
break;
case 4: //中左
$start_y = ceil(($src_info[1] - $wat_info[1]) / 2);
break;
case 5: //正中
$start_x = ceil(($src_info[0] - $wat_info[0]) / 2);
$start_y = ceil(($src_info[1] - $wat_info[1]) / 2);
break;
case 6: //中右
$start_x = $src_info[0] - $wat_info[0];
$start_y = ceil(($src_info[1] - $wat_info[1]) / 2);
break;
case 7: //下左
$start_y = $src_info[1] - $wat_info[1];
break;
case 8: //下中
$start_x = ceil(($src_info[0] - $wat_info[0]) / 2);
$start_y = $src_info[1] - $wat_info[1];
break;
case 9: //下右
$start_x = $src_info[0] - $wat_info[0];
$start_y = $src_info[1] - $wat_info[1];
break;
default:
$error = '位置信息错误!(请选择数字1-9)';
return false;
}
//合并图片资源
if(imagecopymerge($src,$wat,$start_x,$start_y,0,0,$wat_info[0],$wat_info[1],$pct)){
//成功 保存图片
//header('Content-type:'.$src_info['mime']);
$filename = 'watermark_'.trim(strrchr($src_image,'/'),'/');
//echo $filename;exit;
$src_save($src,$path.'/'.$filename);
//销毁资源
imagedestroy($src);
imagedestroy($wat);
return $filename;
}else{
//失败
$error = '水印图制作(合并)失败!';
return false;
}
}
//调用函数
$res = watermark('../uploads/315177.jpg','water.jpg',__DIR__,$error,10);
if($res){
echo $res;
}
else{
echo $error;
}