在 PHP 中用描点法“绘制”中文

中文

作者:LuciferStar 来源:超越PHP

前言:
现在,越来越多的人喜欢上网了,越来越多的人拥有了自己的个人主页。随着各种自动化软件工具的出现,制作网页越来越简单。但,由于特效随处可得,创新的东西,越来越少。说不定,哪天,你会发现某个网站上的计数器和自己的一模一样。网页越做越老练。网页上的东西,也越来越多,越来越丰富。
设问:

在网页上,如果我要添加一个计数器:
以前,那就去空间提供商那里要个链接,或其他地方去复制个地址,但这一些,总归是别人做的,好不好,你是没有太多的发言权的,只能一个一个地找。
在网页上,我要将一些信息发布出去:
假如信息是文本,做一个新页面,加个链接;
是数据,做一个新页面,加个链接:
可要是这些数据经常更新,甚至,每小时、每分钟,都可能会改变,你是否愿意守在电脑前,不停修改、上传呢?(咱可不是商业网站,没有人愿意为你而烧钱。)
而留言板、聊天室、论坛,这些,决不是单靠HTML和JAVASCRIPT就能搞定的。
为了实现更多的自动控制,可以使用CGI(Common Gateway Interface)程序来实现这些功能。

软件需求:
PHP:GD Library
配置支持PHP的服务器。我用OmniHTTPd Professional

对于计数器和实时数据统计、发布,我们可以用图片来完成。在图片中输出文字。
在PHP中,要创建一个图片,并在上面显示点内容,基本步骤如下:

<?php
//http头,告诉浏览器,这是一个GIF图片
header ("Content-type: image/gif");
// 要画画,先要有花布不是?创建一个400×300调色板图像
$im = imagecreate (400, 300);
$black = imagecolorallocate ($im, 0, 0, 0);
// 默认黑色背景。
//(默认,是指第一个定义的颜色。如果在此行代码前面定义了另一个颜色,那么,最先定义的那个,就是默认背景颜色。)
$red = imagecolorallocate ($im, 255, 0, 0);
//红色。如果这两行交换,你会发现背景是红色,文字是黑色。
$string="1234567890";
// 要绘制的字符
imagestring ($im,12,10,10,$string,$red);
//在(10,10)开始绘制字符串
imagepng ($im);
// 以png格式输出,也可以用imagejpeg($im);或magegif($im);但后者,如果GD版本高于1.6,就不能用了。
imagedestroy ($im);
// 结束,清除所有占用的内存资源
?>

上面示例,在400×300的图片上,自点(10,10)开始,绘制12磅的"1234567890"。你有没有注意到这张图片的大小是:251字节!你也可以试试其他的输出格式。
图片的大小,与图片中非背景象素点数有关,跟输出多少象素无关。

然而,有一个问题。
你可以用imagestring()输出如下的信息:
imagestring($im,1,0,0,"abcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()_+{}|:"<>?[]';,./",$red);
可是,你无法正确输出中文!!!
imagestring($im,1,0,0,"啊",$red);
你看到的,决不是中文!!而是乱码。
PHP默认的字符集是UTF-8,而简体中文是GB2312。

如何解决?!
为了解决这个问题,你可以让PHP加载扩展模块php_iconv.dll(UNIT下的后缀名是.SO),不过,有时候,可能不能正常工作。本来,我要把一段测试代码放上来,可这次,怎么弄都没有成功。为了避免错误,我还是不把它们放上来了。
但,最致命的,如果你的空间服务商关闭了该扩展模块,或者,甚至禁止了加载模块的DL()函数,那,你就只能跟中文BYE-BYE了。
还好,还有其他办法。
可以通过字符映射,将预先转换好的码表中字符输出来。但,你需要一张码表!
或者,手工绘制每一个中文的每一个点!感觉怎么样?!

好,来吧,我们一起来画字!

画字,首先要知道怎么画。
初中的简单函数,学过吧?要画出函数的图形,做过吧?算出某点的坐标,然后连接两相邻点。这种方法,叫描点法。
我们要做的,是尽量多地将点算出来,然后在相应坐标显示出来。
你是否听说过点阵打印机、点阵汉字?
在输出汉字时,它们是用一个个点来表示的。

在某个坐标上显示一个某种颜色的点的函数是:
int imagesetpixel ( resource image, int x, int y, int color)
假定我要在坐标(100,100)处显示一个白色的点,那么,只需如下代码:

<?php
header ("Content-type: image/gif");
$image = imagecreate (400, 300);
$black = imagecolorallocate ($image, 0, 0, 0);
$white = imagecolorallocate ($image, 255, 255, 255); // 定义白色
imagesetpixel ( $image, 100, 100, $white);
imagepng ($image);
imagedestroy ($image);
?>

也就是说,我们只要获取某个汉字的所有点的信息,我们就能够通过这个函数,输出那个汉字。

在文件chs16.fon里,保存的,是国标区位码表(国家标准信息交换用汉字编码基本字符集GB-2312)。它是汉字的点阵字库。(WIN98系统中,此文件在c:windowscommand下。如果你要把它放在UNIX系统下使用,请注意大小写。如果没有,你可以在文末找到链接。)
它是MSDOS时代的,但,好东西,还是应该拿出来一用的。

从chs16.fon里,我们可以读取汉字的点阵数据。每个汉字,都是由16×16个点构成的。笔划走过的地方,点的值为1,否则为0;每个点占用一个位,每8个点构成一个字节。那么,一个汉字,就需要(16×16÷8=32)字节。

下面这个实例,是为了说明字符点阵的表示方法。
这里,定义了一个8×8的矩阵,显示了一个字母C,白色的方块用0表示,黑色方块用1表示,那么,这八行图形的代码分别是:


二进制表示
十六进制表示

0
00000000
0x00

1
00111110
0x3E

2
01110000
0xE0

3
01110000
0xE0

4
01110000
0xE0

5
01110000
0xE0

6
00111110
0x3E

7
00000000
0x00

要输出这些点的话,就需要先画第一行,然后第二行、第三行……到最后一行。
用一个循环:
for($hang=0;$hang<8;$hang++)
在每一行中,有八个格子,需要分别绘制,从第一个,然后第二个、第三个……到最后一个。
用一个循环:
for($gezi=0;$gezi<8;$gezi++)
两个循环联列:
for($hang=0;$hang<8;$hang++)
for($gezi=0;$gezi<8;$gezi++)
{ //在这里,我们就能输出点了。
imagesetpixel ( $image, $gezi, $hang, $color);
}

但,我们如何知道到哪里去读某个汉字的点阵数据呢?

一般的字符,比如ASCII码,是用数字0--127(即二进制00000000到01111111)来表示,而中文,则是用两个高位为1的字节(100000000 100000000)表示。如: 半角字符"A",机内码为 (01000001)(它实际上是ASCII码值)。
下面,让我们打开"字符映射表"看看吧。如果你为了节省磁盘,没有安装,那就装一下,不大。如果不会安装,那你就接下去看我乱侃吧。
在字符映射表里,字体选择"楷体_GB2312",点击"特殊符号",这时,你可以看到国标区位码表,从字符(10110000 10100001)开始,一直到(10011111 11111111)。
全角字符"A",机内码为:(10100011 11000001)(它实际是两个高位为1的ASCII码)。
中文"啊"的机内码,是(10110000 10100001);
在GB-2312字符集中,"啊"在表中位置是第16区第1位,这个坐标(16,1),用二进制表示,就是(00010000,00000001)。这,就是"啊"的区位码。
请看:

中文字符: 啊
机内码: (10110000 10100001)
区位码: (00010000,00000001)
相差: (10100000,10100000)

所以,
区位码与机内码的换算公式为 【区位码】+(10100000 10100000)=【机内码】。即:
区位码0 + (10100000) = 机内码0;
区位码1 + (10100000) = 机内码1;
这样的话,点阵数据,就可以通过汉字"机内码"-> "区位码"进行索引、查找。

前面已经讲了一个汉字,在表中要占用32字节,所以,我们定义了一个含有32个元素的数组:
$buffer=array(0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0);
用来保存从字库读出的32个字节数据。

接下来的问题,某一个字符,到底保存在文件的什么位置呢?

由于一个汉字用了32个字节,而GB-2312区位码表表有94行、94列,那么,只要知道该字符在表中是第几个,再乘以32就行了。
所以定义偏移量:
$offset=(94*($qh-1)+($wh-1))*32;
$qh表示区(qu)、$wh表示位(wei);减1,是因为PHP从0开始计数。
位置找到,就只需要用fseek()函数定到码表的这个位置,然后读32字节到$buffer就行了。
另外,由于中文是由两个字节组成,而前面给出的点阵示例是8位,一个字节,所以,画点的代码要修改一下:
for($hang=0;$hang<16;$hang++)
for($j=0;$j<2;$j++) //因为是两个字节,所以插入一个循环
for($gezi=0;$gezi<8;$gezi++)
{
imagesetpixel ( $image, $gezi +8*$j, $hang , $color);
}

好,我们开始编程吧!

/*************************************
* 文件名:'draw1.0.inc.php
** 中文显示点阵输出 version 1.0
** 只提供简单的操作:输出默认大小的纯中文字符串到图片的坐标(0,0)上
** 更多功能,请见下一版本。
*
****************************************/
function draw($image,$string,$color)
{
$fp=fopen("chs16.fon","rb");//二进制方式读点阵字库chs16.fon
if (!feof($fp))//如果文件指针到了文件末尾,退出,不要忘记关闭文件
{
while($string)//当字符串不为0
{
$qh=ord(substr($string,0,1))-0xa0;
$wh=ord(substr($string,1,2))-0xa0;
/* 这两行代码,其实是获取一个中文的机内码。
substr($string,0,1);是从$string中获取第一个字节,然后,通过ord();将这个字符转换为整数。(由于PHP不支持无符号整数,所以没有这一步转换的话,你就只能得到一个0。)在转换为整数之后,就能进行计算了。机内码减去0xa0(10100000),就得到了区位码。
substr($string,1,2);是获取$string中的第二个字节。*/
$offset=(94*($qh-1)+($wh-1))*32;
/*得到了汉字的区位值后,就开始计算偏移量了。*/
fseek($fp,$offset,SEEK_SET);
/*在字库文件$fp中,将文件指针定位到偏移量。*/
$buffer=preg_split('//', fread($fp,32), -1, PREG_SPLIT_NO_EMPTY);
/* fread($fp,32);是从$fp中读取32个字节数据,然后通过preg_split();分配到数组$buffer中。preg_split();是一个支持正则表达的函数。关于正则表达式,我正在学习中。为什么这样用,我也不知道。PHP手册里有本实例。*/
for($i=0;$i<16;$i++) //点阵的行数:16 列数也应该是16
for($j=0;$j<2;$j++) //因为是两个字节,那么,就要一个一个地画了
for($k=0;$k<8;$k++) //每个字节,都有8个点的数据
if(((ord($buffer[$i*2+$j])>>(7-$k))&0x01))//如果这个点的值为1,输出;否则,没有
{
imagesetpixel($image,$x+8*$j+$k, $i, $color);
}
$string=substr($string,2); //中文由两个字节表示,所以,输出一个汉字后,就要去掉两个字节。
$x=24; //一个汉字输出结束,空开一点,给下一个汉字。因为这个汉字是16×16点,那么,$x的值设为16,就够了。但,太挤了不是?
}
}
fclose($fp);
}
下面,我给出一个测试实例:

<?php
header ("Content-type: image/gif");
include 'draw1.0.inc.php';
$im = imagecreate (400, 300);
$black = imagecolorallocate ($im, 0, 0, 0);
$string="中文";
drawer($im,$string);
imagepng ($im);
imagedestroy ($im);
?>

对于这个函数,我们还可以进行扩充,以实现不同的效果。

时间: 2024-10-12 00:21:22

在 PHP 中用描点法“绘制”中文的相关文章

ios-iOS textViewDidChange 中用attributedText 导致输入中文的问题

问题描述 iOS textViewDidChange 中用attributedText 导致输入中文的问题 -(void)textViewDidChange:(UITextView *)textView{ NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:_contentTxtView.text]; [str addAttribute:NSForegroundColorAttrib

线程-Android中用canvas如何绘制动态图?请大神速回,在线等!!

问题描述 Android中用canvas如何绘制动态图?请大神速回,在线等!! public class MyView extends View { private Paint paint; private int roundColor, roundProgressColor; private float roundWidth; private int style; private int process = 1; private Canvas mcanvas; private RectF ov

AutoCad绘制点和样条曲线

4.5.1 点的绘制与设置 1. 点的绘制 在AutoCAD中点对象(Point)大概是最简单的图形对象,用户只需指定其坐标即可.虽然绘制简单,但AutoCAD仍提供了多种绘制方式: 单点法(Single Point):调用一次命令只绘制一个点 (1) 多点法(Multiple Point):调用一次命令可绘制多个点 (2) 定数等分法(Divide):将指定的对象等分为指定的段数,并用点进行标记. (3) 定距等分法(Measure):将指定的对象按指定的距离等分,并用点进行标记. 其中定数等

教你用SKETCH绘制一枚精美的锤子论坛图标

  工具:Sketch 3.3.2 首先,先画一个水箱 新建圆角矩形.调透明度,然后调大小. 水箱的角,我是直接添加描点绘制的. 接下来就是添加水箱的边,和凹面绘制.先看一下所有样式. 因为这个水箱的边内外有两个切面,所以描边一共有三层. 第一层.第二层分别是线性渐变. 第一层比第二层短,这是因为第二层才是水箱边的内切面. 这是第三层,这里我使用了环形渐变,因为水箱角的上部_外切面也是高光的. 接下来是水箱凹面. 这里使用了两个样式,径向渐变+内阴影. 同样的,外阴影也两个. 红阴影 黑阴影 接

一文详解如何用 python 做中文分词

打算绘制中文词云图?那你得先学会如何做中文文本分词.跟着我们的教程,一步步用 Python 来动手实践吧.   需求 在此前发布的文章<从零开始教你用 Python 做词云>一文中,我们介绍了英文文本的词云制作方法.大家玩儿得可还高兴? 文中提过,选择英文文本作为示例,是因为处理起来最简单.但是很快就有读者尝试用中文文本做词云了.按照前文的方法,你成功了吗? 估计是不成功的.因为这里面缺了一个重要的步骤. 观察你的英文文本.你会发现英文单词之间采用空格作为强制分隔符. 例如: Yes Mini

VB.NET实现DirectDraw9 (2) 动画

关键字: VB.NET DirectX DirectDraw 9 作者:董含君转载请注明来自 http://blog.csdn.net/a11s ===========日记================发现最近比较懒惰,代码稍微长那么一点,就不想看了.还是看书比较好.考虑做游戏,但是目前所学的知识还不够.革命尚未成功,同志们仍需努力啊===========End 日记============= 今天是完成全屏幕动画,1024x768,外加多层绘制(鼠标位置就不值得一提了) 先回想一下我们平时是

Flash MX 2004新特性实例学习二

    实例三.Customizing Context Menu 一.涉及特性 这个实例反映了Flash MX 2004在编程方面的重大改进.其中包括了as文件的应用,系统的_global.$clipboard变量的使用,ContextMenu(menufun) 函数的调用,ContextMenuItem()函数的调用,已经MovieClip.prototype.menu变量的使用.通过这几个函数和变量的操作,就可以轻松地操作Flash Player中的菜单了. 二.制作过程 1.新建一个Act

FLASH创意设计教程:试读-“都市恋爱”

教程|设计 1.3 基础效果制作 1.3.1帧动画 1. 都市恋爱 在充满诗意的黄昏,都市的大厦闪烁着灯光,逐渐的灯光隐灭,留下了"LOVE"恋爱的音符--这个创意来源于网络,看到过一个大学生宿舍灯光求爱的图片,所以想到了这个效果. 效果展示 其中一帧画面如图1.3.1所示(完整效果参见光盘中的"\第一部分\第三章\都市恋爱.swf") 点击这里下载源文件 效果讲解 在Flash中,朋友们可以通过改变连续排列的帧内容来实现动画.创建动画序列有两种方法.逐帧动画和渐变

用FLASH AS实现鼠标画圆的效果

鼠标 在FLASH或PHOTOSHOP中能够很轻松的画出一个圆或者椭圆,怎样做一个作品,让用户可以直接在里面拖动鼠标画出一个圆或者椭圆来呢?下面是BreakDS用AS实现这个效果的讲解-- 预览: 一.基本定义:虽然说不说大家都清楚,但是我还是想讲一下,以免一些人忘得差不多了-- 圆:平面上到定点距离等于定长的点的轨迹.椭圆:平面上到两定点距离和等于定长(定长大于两定点间距离)的点的轨迹. 二.问题描述:画圆和椭圆,使用AS. 三.问题分析: 1.圆呵呵,大多数人看到后肯定想:哼-这不简单,不就