标题使用PHP和GD进行图形处理
日期:    作者:爱好者   来源:php之家
文章打印自:
访问文章完全地址:
头部广告
使用PHP和GD进行图形处理
因为越来越多的web 站点开始结合数据库在他们的部分设计中我们能够使用在数据库中采集的数据来 

显示统计结果。今天有很多的web 站点都有意使用某些民意测验或投票应用。在表格中显示数据是一件事
 

但是 创建一个数据的图形则就是另外一回事了。当然
我们可以使用表格将可用的条状图形接在一起显示 

但是对于线形图或饼状图又如何做呢
PHP 具有一系列的图形函数这些函数允许我们创建图形让我们看 

一看这些函数对于使用和创建一些图形有什么好处。 



  然而要紧记
在PHP中的图形函数要求你的系统安装了GD图形库。你可以在www.boutell.com/gd/找到 

还可以得到一些关于在你的系统上如何安装的一些指导。 



  注意
我写这篇文章时是在Red Hat Linux 6.2机器上然后是在Windows 2000机器上结束它的 。在Red

Hat我运行的是PHP和MySQL的最新版本
但是在Windows上我不得不回到MySQL 3.21.29和PHP 3.0.11版本上 

因为它有我要处理的所有的东西
-- SQL和PHP的运行都不需要作修改。在这里让我们不要将整个事情放在交 

叉平台上
好吗 



  为了保持数据简单
并且允许我们集中注意力在创建图形上我使用了一个小的假定的数据集 -- 一个 

国际公司今年前六个月的销售指标。我根据的是一个办事处位于伦敦和另一个在亚特兰大。 





         Month 1  Month 2  Month 3  Month 4  Month 5  Month 6

伦敦      325      345      400      390      370      320

亚特兰大  300      280      270      300      350      410

前六个月的销售指标



  然后我将数据输入到一个MySQL数据库中。我在下面包括了一个数据的卸出
 



# MySQL dump 7.1

#

# Host: localhost    Database: graphing

#--------------------------------------------------------

# Server version    3.22.32



#

# Table structure for table 'sales'

#

CREATE TABLE sales (

g_id int(11) DEFAULT '0' NOT NULL auto_increment,

g_month tinyint(4) DEFAULT '0' NOT NULL,

g_team tinytext NOT NULL,

g_num int(11) DEFAULT '0' NOT NULL,

PRIMARY KEY (g_id)

);



#

# Dumping data for table 'sales'

#



INSERT INTO sales VALUES (1,1,'London',325);

INSERT INTO sales VALUES (2,1,'Atlanta',300);

INSERT INTO sales VALUES (3,2,'London',345);

INSERT INTO sales VALUES (4,2,'Atlanta',280);

INSERT INTO sales VALUES (5,3,'London',400);

INSERT INTO sales VALUES (6,3,'Atlanta',270);

INSERT INTO sales VALUES (7,4,'London',390);

INSERT INTO sales VALUES (8,4,'Atlanta',300);

INSERT INTO sales VALUES (9,5,'London',370);

INSERT INTO sales VALUES (10,5,'Atlanta',350);

INSERT INTO sales VALUES (11,6,'London',320);

INSERT INTO sales VALUES (12,6,'Atlanta',410);



  我的数据库叫做graphing,包含数据的表叫做sales。我将月份当做一个整数存在 g_month字段中。 



  在我们开始绘图之前,先学一些基础知识,看一下PHP是如何创建一个图像。我们需要做的第一件事就 

是告诉浏览器它正在得到一个图像和所得到图像的类型: 



<?php 



Header( "Content-type: image/gif"); 



?> 



  即然浏览器知道它正在获取一个GIF 图像了
我们可以开始创建图形了。首先我们需要创建一个将用来 

绘图的空白的画布。ImageCreate函数可以做到这一点。ImageCreate将返回一个图像的标识符
并且需要告 

诉函数用象素计算的画布有多大
x(宽度)与y(高度)。 



<?php 



$image
= imagecreate(200,200); 



?> 



  现在我们得到了一个200像素乘200像素的可用来绘图的空白画布。下一步是创建将要用在图像中的一些 

颜色。为了做到这一点我们需要使用ImageColorAllocate函数
还有颜色的RGB值。ImageColorAllocate 将 

返回一个我们刚创建的颜色标识。我们将在画布上绘图时使用颜色标识。ImageColorAllocate的工作方式是 

我们需要为所处理的每一个图像分配一个颜色
-- 所以如果我们创建3个GIF并且在每一个上面使用红色我 

们应该分配红色3次
一次为一个GIF。我将分配一个名为$maroon的颜色给定红色值为100绿色为0 和 

兰色为0。同时我将同样创建白色。 



<?php 



$maroon
= ImageColorAllocate($image,100,0,0); 

$white
= ImageColorAllocate($image,255,255,255); 



?> 



  即然我们已经得到了颜色
就可以画点什么了。第一件事情要叫的就是将画布白色涂成白色。函数

ImageFilledRectangle将在画布上画一个矩形
并且用指定的颜色进行填充。 



<?php 



    ImageFilledRectangle
($image,0,0,200,200,$white); 



?> 



  告诉ImageFilledRectangle的第一件事就是
同样用于所有的图像函数哪一个图像是我们正在处理的

所以传给它$image标识。然后它需要知道x和y坐标来开始画矩形
0,0 -- 左上角和结束矩形的坐标 200,

200
-- 画布的右下角。最后告诉它的事情就是在矩形内填充的颜色这个例子为$maroon。现在我们可以 

开始在白色背景上绘图了。 



<?php 



ImageRectangle
($image,10,10,190,190,$maroon); 

ImageFilledRectangle
($image,50,50,150,150,$maroon); 



?> 



  ImageRectangle工作完全与ImageFilledRectangle同样的方式
除了它不使用颜色填充矩形以外。一旦 

我们画完了
就可以输出图形了 -- 



<?php 



ImageGIF
($image); 



?> 



  然后清除我们存在内存中的图像。 



<?php 



ImageDestroy
($image); 



?> 



  这就是我们得到的
 



 



  然而
它还不是一个要求的图形。 



 
(未完待续
使用PHP和GD进行图形处理
线形图形
  为了开始我们可以创建一个空的200x200像素的画布并填充为灰色。在这上面可以绘制我们的线段。
我们可以为每个办公室分配一个颜色红色代表伦敦兰色代表亚特兰大。

  现在可以开始取出数据并把它画出来了。需要牢记的一件重要的事就是在画线的时候ImageLine 要求
我们告诉它开始处的x和y坐标还有线的结束坐标。现在如果从一个数据库中抓出数据将一次只能得到一组
坐标。所以可以或者将数据存储在数组中或使用一个临时变量来保存前一组坐标。我选择了使用数组。

  除了将要绘制的实际坐标之外还需要知道可达到的最大值(图形的顶部)还有信息列的数目(沿着x轴要
画的点的个数)。所以在与数据库连接之后从数据库中选出了MAX(g_num) 值并将其保存起来为后面使用。
然后选出所以g_team等于'London'的所有记录并得到返回的记录行数所以我们将知道有多少要处理的数
据列数。从前面的表格中你可以看到我们将处理6个月或列数据并且最大值为410。

<?php

$columns = 6;
$max = 410;

?>

  x值总是最容易处理的 -- 它的范围从0到图像的宽度此处为200。我们将在0处理开始画线并希望在200
结束所以在以$x=0开始之后将需要增加$x值直到$columns-1次此处为5以达到200 -- 这样我们要画
6次最后一次将在200处。记住这点以后我们可以创建一个名为$xincrement的变量并赋给它200除以
($columns-1)的值。然后将给出$x一个开始值0 并且在每一次循环的底部当从结果集中抓取记录行时
们可以给$x增加$xincement。

<?php

$xincrement = bcdiv(200,$columns-1,0);

?>

  bcdiv用第二个参数除以第一个参数并且返回根据第三个参数所指定的小数位数的值。为了使用BCMath
函数你需要在Unix下将其编译到PHP中但是Windows版本已经将其编译进去了。README.BCMATH在PHP源代
码的根目录中它将解释在哪和如何做。

  y值将与$max数值成比例所以我们所能做的就是用$max来除g_num得到比例的小数值然后乘以200 --
图像的高度。

<?php

$y = bcmul(bcdiv($salesRow[0],$max,2),200,2);

?>

  $salesRow[0]是当前行的g_num值除上$max并且结果定为小数部分为2位。然后使用bcmul将结果与200
相乘。

  然后可以做的就是在整个数组中循环使用当前元素作为线的开始当前元素+1作为线的结束。因为最
后一个元素将永远不会是一行的开始我们必需将循环减1所以将当小于或等于$columns-1 时循环改为小
于$columns-1时循环。

  让我们看一下迄今为止的代码

<?php

// 发送头信息和创建初始的空白画布
Header( "Content-type: image/gif");
$image = imagecreate(200,200);
// 分配一些颜色
$red = ImageColorAllocate($image,255,0,0);
$blue = ImageColorAllocate($image,0,0,255);
$white = ImageColorAllocate($image,255,255,255);
$grey = ImageColorAllocate($image,200,200,200);
// 创建一个初始的灰色矩形用于绘图
ImageFilledRectangle($image,0,0,200,200,$grey);
// 连接mysql服务器并选择数据库
$connect = mysql_connect("","root","");
mysql_select_db("graphing",$connect);
// 找到结果集中的最大数值
$sql = "SELECT MAX(g_num) FROM sales";
$maxResult = mysql_query($sql,$connect);
$max = mysql_result($maxResult,0,0);
// 得到伦敦的结果集
$sql = "SELECT g_num FROM sales WHERE g_team='London' ORDER BY g_month";
$salesResult = mysql_query($sql,$connect);
// 找到返回多少列,就是'columns'的数值
$columns = mysql_num_rows($salesResult);
// $x每次增加多少量?
$xincrement = bcdiv(200,$columns-1,0);
$x=0;
// $i 将记录行的数值
$i=0;
// 在我们所有的数据行中循环
while($salesRow=mysql_fetch_array($salesResult)) {
// 象上面所讨论地计算y的坐标值
$y = bcmul(bcdiv($salesRow[0],$max,2),200,2);
// 在$points数组中增加值
$points[$i][0] = $x;
$points[$i][1] = $y;
// 增加$x的值用$xincrement
$x+=$xincrement;
// 增加 $i
$i++;
}
// 现在我们在$points数组中循环,此时$i小于$columns-1
for($i=0;$i<$columns-1;$i++) {
// 我们传递 $points[$I][0] 作为第一个x坐标,$points[$I][1] 为第一个y坐标
// $points[$I+1][0], $points[$I+1][1] 将是下一个x,y坐标集
ImageLine($image,$points[$i][0],$points[$i][1],$points[$i+1][0],
$points[$i+1][1],$red);
}
// 输出GIF给浏览器并且释放内存
ImageGIF($image);
ImageDestroy($image);

?>

  这样将给出我们如下的结果
<img src="http://www.phpstar.com/pic/2000090702.gif">
  它既不正确也很气人。问题在于我们是按传统的x和y坐标方法处理的这种方法是从左下角向外发散的。
Image函数的坐标系统是从左上角发散的所以这时我们的x位置是正确的我们的y位置弄反了。

  我们需要做的就是修改确定y位置的代码以便按相反的方式工作 -- 改变行

<?php

ImageLine($image,$points[$i][0],$points[$i][1],$points[$i+1][0],$points[$i+1][1],$red);

?>

  变成读取

<?php

ImageLine($image,$points[$i][0],200-$points[$i][1],$points[$i+1][0],200-$points[$i+1][1],$red);

?>

  我们将得到图形
<img src="http://www.phpstar.com/pic/2000090703.gif">
  现在我们需要做的是加入一条线它是将亚特兰大的数据进行了图形化。

<?php

$sql = "SELECT g_num FROM sales WHERE g_team='Atlanta' ORDER BY g_month";
$salesResult = mysql_query($sql,$connect);
$columns = mysql_num_rows($salesResult);
$xincrement = bcdiv(200,$columns-1,0);
$x=0;
$i=0;
while($salesRow=mysql_fetch_array($salesResult)) {
$y = bcmul(bcdiv($salesRow[0],$max,2),200,2);
$points[$i][0] = $x;
$points[$i][1] = $y;
$x+=$xincrement;
$i++;
}
for($i=0;$i<$columns-1;$i++) {
ImageLine($image,$points[$i][0],200-$points[$i][1],$points[$i+1][0],200-$points[$i+1][1],$blue);
}

?>
<img src="http://www.phpstar.com/pic/2000090704.gif">
我们用在这个例子中的数据是静态的在以后的部分我们将看一下如何处理动态数据并且看一下在图
表中增加一些轴线和标签。

  译者注

  本文中的例子我已经在php 3.0.16下使用旧版的gd库测试成功。对于高版本的php4.0以上版本由于不再支持gif文件所以我将Imagegif改成了ImagePNG函数执行后成功。而且对于Header输出的MIME类型可以仍然使用image/gif格式说明。如果大家有什么建议欢迎来信。对于php 4.0.2版本与其使用的gd库均可从http://www.mm4.de/处下载。不过这个网站上则是全的文件包而不是独立的动态库。还有一点要说明的是这里我所说的版本全部是windows下的。至于linux则可以直接在编译时设定即可。
责任编辑:semirock