PHP之图形处理
PHP 的图形处理,主要功能集中在 PHP 的图形处理函数。
需要先掌握一些要点。什么叫图片,怎么显示图片。
所谓的图片,其实也是一种文件,只是内容不是我们肉眼直接可见的。如果我们用记事本打开一张图片,只会看到一片乱码。其实这些乱码,只是相对我来说是乱码。对于可以读写它的程序来说,一点都不乱。如果我们知道一种图片的格式,我们就可以自己生成一张图片。就像我们最早的时候,制作的记事本留言本一样。
把一些特殊格式的数据,保存到一个文件,就可以生成一张图片。反之,我们如果用 PHP 直接输出这些内容,浏览器也会认为这是一张图片。
我们先来证实一下这一点,同学们先准备好一张图片。建议小一点的, JPG 格式就可以了。然后我们使用 PHP 读取这张图片,就像普通文件一样读取。
$file = "1.jpg";
$fp = fopen($file, "rb");
$data = fread( $fp, filesize($file));
fclose($fp);
echo $data;
?>
相信对于同学们来说,这个代码没有什么问题吧。
打开文件,读取内容(所有字节),关闭文件,输出内容。
有没有同学试一下,这个代码运行后会输出什么,截个图上来看一下。
也许有同学会奇怪吧,怎么是乱码。
因为浏览器默认,认为我们的 PHP 输出是文本。即使是乱码,我们需要告诉浏览器,这是一张图片。这个需要用 header 函数,发送头信息,告诉浏览器,当前输出的内容,是格片格式。
Header("Content-type: image/jpeg");
这是 JPG 格式图片使用的头信息,内容类型:图片/jpeg,需要加在 echo 之前。
$file = "1.jpg";
$fp = fopen($file, "rb");
$data = fread( $fp, filesize($file));
fclose($fp);
Header("Content-type: image/jpeg");
echo $data;
?>
同学们再试一下。
这个代码证明了一点:即使输出的是乱码,只要浏览器知道它是什么内容;它就能正确显示。
相对的,如果我们把读出来的内容,保存到另一个文件,就可以复制这张图片。
在这里,可能会有一些同学会有一些误解。认为,这里还是一个网页。各位同学可以试一下,在打开的网页空白处,点一下鼠标右键,查看源文件,会发现,没有这个选项。即使有,也是灰的。这是因为,这个不是一个页面,浏览器已经认为,我们这个 PHP 程序,是一张图片了。
平时我们使用 PHP 进行任何形式的输出时,浏览器认为这是一个 HTML 网页,才能看到源代码。
如果我们输出的是图片内容,要能正确显示,就必须告诉浏览器,本次输出,别把我当成网页,而是当成图片。也就是说,我们的 php 程序,是一张图片。如果要想在别的网页使用这张图片,需要像平时一样
把这个 PHP 程序,当成一张图片来对待,而不能直接在这个程序写上。
这样是不对的,这样只会导致一个结果。
这是不可能显示得出来的。
所以,使用 PHP 处理图片的程序,一定是单项功能的 PHP 程序。除非你不输出这张图片,而只是把它保存起来。
$file = "1.jpg";
$fp = fopen($file, "rb");
$data = fread( $fp, filesize($file));
fclose($fp);
$fp = fopen("2.jpg", "wb");
fwrite($fp, $data);
fclose($fp);
?>
如果代码是这么写,就是另一回事,没有错。把图片保存到另一个地方,然后输出 HTML 调用这张图片。要直接输出图片的 PHP 程序,一定不可能含有别的输出,没有用。只能单纯的输出图片的内容,就是那堆乱码。
好了,读取图片,输出图片都没有问题了。
文件的内容是特殊格式,我们看都看不懂,怎么处理它呢?
PHP 提供了专门的图形处理函数。
图形处理函数库,有一个专用的名字,叫 GD库。
这个函数库并不是 PHP 自带的。需要在安装 PHP 的时候,在 php.ini 里设置加载。
库文件名叫 php_gd2.dll。PHP 的安装包里就有,在 ext 目录下。如果哪位同学的 php.ini 里还没加载 GD库,请现在打开它。
这样,PHP 才有图形处理函数可用。
当前 PHP 自带的 GD 库版本是 2.0.28。PHP 4 带的是 gd 2.0,PHP 3 时代是 gd 1.6。
为什么要提这个呢?
因为 gd 2.0 的时候,因为 GIF 图片的版权问题。PHP 做为免费开源的语言,无法向 GIF 的版权商提供版权费,所以只能暂停对 GIF 图片的支持。PHP 5 以后,GIF 版权到期, 我们的 PHP 才重新支持 gif 图片。
好了,我们打开 PHP 手册,看一下 Image 图像函数。
函数很多,但是,大致上可以分成四类:创建,绘画,设置,输出。
如果要创建一张图片,可以使用 imagecreate 函数。从函数名就可以看得出来了,创建图像。从手册上,可以看得到语法格式。
返回图像资源 imagecreate(宽度 , 高度)
宽度和高度以像素为单位。
还有另一个函数,imagecreatetruecolor 新建一个真彩色图像,支持更多颜色。
创建类的函数,都会返回一个图片资源,有点类似于 fopen 函数的返回。资源型的数据,内部含有一个可读写指针,,让我们可以对图片进行编辑操作。
我们先来试试创建一张图片,先用 imagecreate 函数好了。
为了能看到这张图片,我们需要输出。但是我们的经验告诉我们,资源型的内容不能直接输出。
图片形函数,给我们提供了一些函数,分别是:
imagejpeg 以 JPG 格式输出
imagegif 以 GIF 格式输出
imagepng 以 PNG 格式输出
函数格式是一样的。
imagejpeg( 图像资源 , [保存路径])
如果需要保存这张图片,就在第二个参数写上文件名就可以了。如果只是希望直接输出,第二个参数不写就行。
我们现在先直接输出这张图像。
Header("Content-type: image/JPEG");
$img =imagecreate(100, 100);
imagejpeg($img);
创建一张 100*100 的图像,然后用 JPG 格式输出它。要记得告诉浏览器,这是图片。
运行的结果是什么样的呢?有哪位同学截个图上来看看。
是的,会输出一张黑色的图片。因为我们并没有在上面画任何内容,也没告诉它应该用什么颜色。
我们先来简单一点的操作,先在上面涂点颜色。这个需要使用 imagecolorallocate 函数。
函数功能是:为一幅图像分配颜色
函数格式是
imagecolorallocate(图像资源, 红色,绿色,蓝色)
三元色,分别用 0 到 255 的数字表示。0是最暗,255是最亮。如果需要白色,三色都是 255 就可以了,黑色就是三色 0,如果只要红色,就是 255 0 0。
header("Content-type: image/jpeg");
$img =imagecreate(100, 100);
imagecolorallocate($img, 255,0,0);
imagejpeg($img);
我就填上个纯红好了。同学们可以自己试试,分别给红绿蓝设置一些数值,看看结果如何。这个配色,需要一些知识了。同学们也可以直接在各种画图工具里得到这个颜色。
右下角的 红绿蓝 值就可以直接用。很多软件都有类似的调色板,很容易可以得到各种颜色值。
这里有一点要注意。
imagecolorallocate 函数,只有第一次使用的时候,会给图像填上背景色,重新使用,并不会改变背景色。
header("Content-type: image/jpeg");
$img =imagecreate(100, 100);
imagecolorallocate($img, 255,0,0);
imagecolorallocate($img, 0, 0, 255);
imagejpeg($img);
这个代码,并不会输出预期的蓝色。但是,并不表示函数没有用。函数依然有效,只是这个颜色没有被使用而已。我们可以用这个颜色,做其他用途,比如写字。
我们来试试,在图像上面写点字。
PHP 给我们提供的函数里面,有两个函数可以用于在图像上写字,分别是 imagestring 和 imagestringup。
imagestring 是横向写字
imagestringup 是纵向写字
如果用 imagestringup 写的话,我就们看字就得扭着脖子看了。好吧,先用 imagestring。
imagestring 函数原型
imagestring(图像资源, 字体, 开始X坐标,开始Y坐标, 要写的字, 颜色)
PHP 自带的字体只有5种,需要用数字1到5表示。
我们来试一下吧。
header("Content-type: image/jpeg");
$img =imagecreate(100, 100);
imagecolorallocate($img, 255,0,0);
$color = imagecolorallocate($img, 0, 0, 255);
imagestring($img, 4, 0,0, 'abcdef', $color);
imagejpeg($img);
你大爷的,好刺眼,我换白底好一点。
有没有哪个同学试试写个中文?结果会让人很失望。
因为 PHP 自带的字体,弱爆了,跟本无法正常显示中文。怎么办呢?
自定义字体。
image 函数,给我们提供了另一个函数,可以使用自定义字体来写字。严格来说是“画字”。需要一个带点阵格式的字体文件,而且要支持中文的,最常见的就是 ttf 类型的字体了。如果做过平面设计的同学,对这个一定不陌生,没做过的同学,也不要紧。我们可以在我们的系统里面,挖几个出来用用。系统自带的字体文件,在 C:\windows\fonts 目录,我们可以在里面找一个支持中文的字体。WIN 系统自带的字体,大多数都支持中文,我挑一个微软雅黑。回到我们的 PHP。
要使用这个字体文件来画字,需要用 imagettftext 函数。
imagettftext 函数原型
imagettftext (图像资源, 字体大小, 字体方向, 开始X坐标, 开始Y坐, 字体颜色, 字体文件, 要写的字 )
我的娘哦,好多参数。估计各位同学也是第一次用这么多参数的函数吧。
//创建图片,并设置白底
$img =imagecreate(100, 100);
imagecolorallocate($img, 255,255,255);
//准备一个颜色,
$color = imagecolorallocate($img, 0, 0, 255);
//准备一个字体文件
$font = "msyhbd.ttf";
//图像资源, 字体大小, 字体方向, 开始X坐标, 开始Y坐, 字体颜色, 字体文件, 要写的字
imagettftext($img, 14, 0, 20, 20, $color, $font, "中文支持");
//JPG格式输出图像
imagejpeg($img);
这个图像文件,如果路径不在当前目录下,要告诉 PHP 在哪里。
比如 $font = "./font/msyhbd.ttf";
或者 $font = "C:\\windows\\fonts\\msyhbd.ttf";
必须让 PHP 找得到这个字体文件
imagettftext($img, 14, 180, 150, 150, $color, $font, "中文支持");
字体方向 180度,结果就成这样子。另外,中文在这里必须是 utf8 编码。这个很容易做到,把 PHP 文件转换成 utf8 编码就可以了。使用 gbk 编码的同学,可以给字体转换一下编码。
$text = iconv("gbk", "utf-8", "中文支持");
只要有足够的字体,我们可以让 PHP 输出任意样式
$font = "FZKANGFW.TTF";
$text = iconv("gbk", "utf-8", "中文支持");
imagettftext($img, 20, 0, 150, 150, $color, $font, $text);
这个效果,配合预定变量 $_SERVER 可以做到一个效果。
$_SERVER['REMOTE_ADDR']
这个服务器变量,可以得到来访者的 IP 地址。网上的各种带 IP 显示的图片,就是这么做出来的。不就是在图片上写几个字么。
好了。然后我们来学习一下。在上面画线条。
画图函数很多。
imagedashedline - 画一虚线
imagedestroy - 销毁一图像
imageellipse - 画一个椭圆
imagefill - 区域填充
imagefilledarc - 画一椭圆弧且填充
imagefilledellipse - 画一椭圆并填充
imagefilledpolygon - 画一多边形并填充
imagefilledrectangle - 画一矩形并填充
画线是 imageline,其他画图函数,同学们可以自行参考手册。
看来看去,不外乎原理就是:在图像资源上,用什么颜色,从哪个坐标开始,画什么。
imageline函数原型
( 图像资料, 开始X坐标, 开始Y坐标, 结束X坐标, 结束Y坐标, 颜色 )
在数学中,我们知道XY坐标可以确定平面上的一个点,两个点可以决定一个线段。
//创建图片,并设置白底
$img =imagecreate(300, 300);
imagecolorallocate($img, 200,200,200);
//准备一个颜色,
$color = imagecolorallocate($img, 0, 0, 255);
//用这个颜色画一条线
imageline($img, 0,150, 300,150, $color);
//JPG格式输出图像
imagejpeg($img);
我的图像是 300*300 的大小。从0,150 就是最左边,中间位置,到最右边,中间位置。
如果要画一张网格的话,你就慢慢算座标,然后重复画就可以了。
for($i=0; $i
$y = $i*50;
imageline($img, 0,$y, 300,$y, $color);
}
竖线什么的,就不多说了。
还有其他各种线条,形状,各位同学可以跟据手册的说明,自行练习。
很多时候,我们图片是现成的。我们要做的只是缩小,裁剪大小。
图片是现成的,我们需要把图片加载进来,跟据图片的不同类型,我们需要不同的函数来加载。
imagecreatefromjpeg 创建一张图像,来自JPG文件
imagecreatefromgif GIF
imagecreatefrompng PNG
imagecreatefromwbmp WBMP
imagecreatefromxbm XBM
图片是什么类型,就用什么函数来载入。这些函数,都属于创建类函数。之前,我们使用写字,画线,都属于绘画类函数。这样区分,就不觉得函数多了。很多函数其实是重复的,只是针对于不同的类型。所有的操作,都是针对于画布,在画布上画什么。
其实 PHP 并不能缩小一张图片,那只是一种思路上的技巧。用的是图像复制函数imagecopymerge。
可以把图像的一部份,复制到另一张图像上面,同类的还有另一个函数imagecopyresampled。都是复制图像的一部份,复制到另一张图像上面。这意味着,这样的操作,需要两个图像。一个是原图,一个是新生成的图。
原图,我们可以用 imagefrom 系列函数加载进来。新图,我们可以自己创建。然后再使用图像复制函数,从原图复制到新图。
如果复制的只是其中的一个区域,那就是 裁剪功能。如果复制是整个图像大小,新图的大小和原图大小不同,就是改变图片大小,也就是缩略图,或者放大图。
$image = "1.jpg";
//读取图片大小
list($width, $height) = getimagesize($image);
//加载图片
$bimg = imagecreatefromjpeg($image);
//新建图片,大小是原图的一半
$simg =imagecreatetruecolor($width * 0.5, $height * 0.5);
//在原图上,把原图的全部,缩小一半,复制过来
imagecopyresampled($simg, $bimg, 0,0, 0,0, $width*0.5, $height*0.5, $width, $height );
//JPG格式输出小图像
imagejpeg($simg);
应该有同学发现了,这里使用的是 imagecreatetruecolor 创建新图像。真彩图像,而不是 imagecreate。同学们可以试一下,用 imagecreate 是什么结果。
复制图像,我选择了 imagecopyresampled 函数,复制并调整大小。同类函数还有 imagecopyresized。
imagecopyresized
imagecopyresampled
这两个函数都是复制并调整大小图像。同学们可以自己测试它们的区别。由于参数太多,我这里帮你们做一个注释。
新图, 原图,
新图起点X,新图起点Y,
原图起点X,原图起点Y,
新图宽度,新图高度,
原图宽度,原图高度
两个一组,一起看就行了。
//加载图片
$bimg = imagecreatefromjpeg($image);
//新建图片,大小是原图的一半
$simg =imagecreatetruecolor($width * 0.5, $height * 0.5);
//在原图上,把原图的全部,缩小一半,复制过来
imagecopyresampled($simg, $bimg, 0,0, $width*0.5, $height*0.5, $width, $height, $width, $height );
这个代码的意思是
$simg, $bimg, //新图,原图
0,0, //从新图的 0*0 开始画
$width*0.5, $height*0.5, //从原图的中心点取样
$width, $height, //新图和原图等大小。
$width, $height //到原图的最右下角坐标结束
由于创建的图像只有原图的一半,这个代码,会使得最终图片只显示原图中心点开始。右下角的内容。也就是 1/4 原图的内容,就是所谓的裁剪。
这些函数的参数太多,不太容易看,计算各个采样坐标,需要更细心。
水印图的原理也是一样的。加载两张图,创建两个图像对象。然后把水印图,复制到原图上。面。其实都只是一个思路的技巧而已。
图形函数就讲到这里。
我先来总结一下这一课的要点。
1、一定要先创建图像,加载创建或自己创建。
2、只能在图像上面绘画,线条,形状
3、文字只能用 UTF8 编码,要显示中文需要中文字体
4、图像本身不能直接调整,只能在复制的过程中调整。
5、如果要直接输出图像,这个程序不能输出其他多余的东西
6、一个直接输出图像的程序,要把它看成图片来调用。
图像函数。分为几类:
创建类:imagecreate、imagecreatefromjpeg
设置类:imagecolorallocate、getimagesize
绘制类:imagecopyresampled、imageline、imagettftext
输出类:imagejpeg、imagepng
其中绘制类的函数最多,函数格式也很相似,都是:
在图像的XX坐标,绘制XX东西
复制操作的函数,坐标往往有8个之多。
原图起点坐标,原图宽高, 这就四个了;
新图起点坐标,新图宽高, 这里又四个;
再加上原图,新图。有十来个参数。
所以,一般图像处理的过程,往往调试好一个程序之后,都不愿意再回头重新改了。封装成自定义函数吧。
比如缩略图函数。
function size_img($img, $width, $height) {
中间你就处理吧。
}
这样提供一个图片,指定输出的大小,就可以生成缩略图了。至少用起来方便多了。