PHP之图形处理

时间:2022-04-30 19:06:15

图形处理

PHP 的图形处理,主要功能集中在 PHP 的图形处理函数。

需要先掌握一些要点。什么叫图片,怎么显示图片。

所谓的图片,其实也是一种文件,只是内容不是我们肉眼直接可见的。如果我们用记事本打开一张图片,只会看到一片乱码。其实这些乱码,只是相对我来说是乱码。对于可以读写它的程序来说,一点都不乱。如果我们知道一种图片的格式,我们就可以自己生成一张图片。就像我们最早的时候,制作的记事本留言本一样。

把一些特殊格式的数据,保存到一个文件,就可以生成一张图片。反之,我们如果用 PHP 直接输出这些内容,浏览器也会认为这是一张图片。

我们先来证实一下这一点,同学们先准备好一张图片。建议小一点的, JPG 格式就可以了。然后我们使用 PHP 读取这张图片,就像普通文件一样读取。

<?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 之前。

<?PHP

$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 程序,是一张图片。如果要想在别的网页使用这张图片,需要像平时一样 <img 标记来调用这张图片。

<img src="img.php" />

把这个 PHP 程序,当成一张图片来对待,而不能直接在这个程序写上。

<img src="<?PHP 我们刚才的代码 ?>" />

这样是不对的,这样只会导致一个结果。

<img src="一堆乱码" />

这是不可能显示得出来的。

所以,使用 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);

?>

<img src="2.jpg" />

如果代码是这么写,就是另一回事,没有错。把图片保存到另一个地方,然后输出 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 < 6; $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) {

中间你就处理吧。

}

这样提供一个图片,指定输出的大小,就可以生成缩略图了。至少用起来方便多了。