点阵字库的原理及与矢量字库的差别

点阵字库的生产原理
所有的汉字或者英文都是下面的原理,由左至右,每8个点占用一个字节,最后不足8个字节的占用一个字节,而且从最高位向最低位排列。
生成的字库说明:(以12×12例子)
一个汉字占用字节数:12÷8=1····4也就是占用了2×12=24个字节。
编码排序a0a0→a0fe a1a0→a2fe依次排列。
以12×12字库的“我”为例:“我”的编码为ced2,所以在汉字排在ceh-aoh=2eh区的d2h-a0h=32h个。所以在12×12字库的起始位置就是[{fe-a0}*2eh+32h]*24=104976开始的24个字节就是我的点阵模。
其他的类推即可。
英文点阵也是如此推理。
在dos程序中使用点阵字库的方法
首先需要理解的是点阵字库是一个数据文件,在这个数据文件里面保存了所有文字的点阵数据。至于什么是点阵,我想我不讲大家都知道 的,使用过文曲星之类的电子辞典吧,那个的液晶显示器上面显示的汉子就能够明显的看出点阵的痕迹。在 pc 机上也是如此,文字也是由点阵来组成了,不同的是,pc机显示器的显示分辨率更高,高到了我们肉眼无法区分的地步,因此点阵的痕迹也就不那么明显了。
点阵、矩阵、位图这三个概念在本质上是有联系的,从某种程度上来讲,这三个就是同义词。点阵从本质上讲就是单色位图,他使用一个比特来表示一个点,如果这 个比特为0,表示某个位置没有点,如果为1表示某个位置有点。矩阵和位图有着密不可分的联系,矩阵其实是位图的数学抽象,是一个二维的阵列。位图就是这种 二维的阵列,这个阵列中的 (x,y) 位置上的数据代表的就是对原始图形进行采样量化后的颜色值。但是,另一方面,我们要面对的问题是,计算机中数据的存放都是一维的,线性的。因此,我们需要 将二维的数据线性化到一维里面去。通常的做法就是将二维数据按行顺序的存放,这样就线性化到了一维。
那么点阵字的数据存放细节到底是怎么样的呢。其实也十分的简单,举个例子最能说明问题。比如说 16*16 的点阵,也就是说每一行有16个点,由于一个点使用一个比特来表示,如果这个比特的值为1,则表示这个位置有点,如果这个比特的值为0,则表示这个位置没 有点,那么一行也就需要16个比特,而8个比特就是一个字节,也就是说,这个点阵中,一行的数据需要两个字节来存放。第一行的前八个点的数据存放在点阵数 据的第一个字节里面,第一行的后面八个点的数据存放在点阵数据的第二个字节里面,第二行的前八个点的数据存放在点阵数据的第三个字节里面,…,然后后 面的就以此类推了。这样我们可以计算出存放一个点阵总共需要32个字节。看看下面这个图形化的例子:
可以看出这是一个汉字的点阵,当然文本的方式效果不是很好。根据上面的原则,我们可以写出这个点阵的点阵数 据:0x40,0x08,0x37,0xfc,0x10,0x08,…, 当然写这个确实很麻烦所以我不再继续下去。我这样做,也只是为了向你说明,在点阵字库中,每一个点阵的数据就是按照这种方式存放的。
当然也存在着不规则的点阵,这里说的不规则,指的是点阵的宽度不是8的倍数,比如 12*12 的点阵,那么这样的点阵数据又是如何存放的呢?其实也很简单,每一行的前面8个点存放在一个字节里面,每一行的剩下的4点就使用一个字节来存放,也就是说 剩下的4个点将占用一个字节的高4位,而这个字节的低4位没有使用,全部都默认的为零。这样做当然显得有点浪费,不过却能够便于我们进行存放和寻址。对于 其他不规则的点阵,也是按照这个原则进行处理的。这样我们可以得出一个 m*n 的点阵所占用的字节数为 (m+7)/8*n.
在明白了以上所讲的以后,我们可以写出一个显示一个任意大小的点阵字模的函数,这个函数的功能是输出一个宽度为w,高度为h的字模到屏幕的 (x,y) 坐标出,文字的颜色为 color,文字的点阵数据为 pdata 所指:
/*输出字模的函数*/
void _draw_model(char *pdata, int w, int h, int x, int y, int color)
{
int i; /* 控制行 */
int j; /* 控制一行中的8个点 */
int k; /* 一行中的第几个8个点了 */
int nc; /* 到点阵数据的第几个字节了 */
int cols; /* 控制列 */
byte static mask[8]={128, 64, 32, 16, 8, 4, 2, 1}; /* 位屏蔽字 */
w = (w + 7) / 8 * 8; /* 重新计算w */
nc = 0;
for (i=0; i
{
cols = 0;
for (k=0; k
{
for (j=0; j_hz_buf_size * ((ch0 - 1) * 94 + ch1 - 1);
fseek(fp, offset, seek_set); /* 进行寻址 */
fread(fontbuf, 1, (w + 7) / 8 * h, fp); /* 读入点阵数据 */
_draw_model(fontbuf, w, h, x, y, color); /* 绘制字模 */
}
以上介绍完了中文点阵字库的原理,当然还有英文点阵字库了。英文点阵字库中单个点阵字模数据的存放方式与中文是一模一样的,也就是对我们所写的 _draw_model 函数同样可以使用到英文字库中。唯一不同的是对点阵字库的寻址上。英文使用的就是 ascii 码,其码值是0到127,寻址公式为:
英文点阵数据在英文点阵字库中的偏移 = 英文的ascii码 * 一个英文字模占用的字节数
可以看到,区分中英文的关键就是,一个字符是 ascii 码还是扩展 ascii 码,如果是 ascii 码,其范围是0到127,这样是使用的英文字库,如果是扩展 ascii 码,则与其后的另一个扩展 ascii 码组成汉字内码,使用中文字库进行显示。只要正确区分 ascii 码的类型并进行分别的处理,也就能实现中英文字符串的混合输出了。
点阵字库和矢量字库的差别
我们都只知道,各种字符在电脑屏幕上都是以一些点来表示的,因此也叫点阵。最早的字库就是直接把这些点存储起来,就是点阵字库。常见的汉字点阵字库有 16x16, 24x24 等。点阵字库也有很多种,主要区别在于其中存储编码的方式不同。点阵字库的最大缺点就是它是固定分辨率的,也就是每种字库都有固定的大小尺寸,在原始尺寸下使用,效果很好,但如果将其放大或缩小使用,效果就很糟糕了,就会出现我们通常说的锯齿现象。因为需要的字体大小组合有无数种,我们也不可能为每种大小都定义一个点阵字库。于是就出现了矢量字库。
矢量字库
矢量字库是把每个字符的笔划分解成各种直线和曲线,然后记下这些直线和曲线的参数,在显示的时候,再根据具体的尺寸大小,画出这些线条,就还原了原来的字符。它的好处就是可以随意放大缩小而不失真。而且所需存储量和字符大小无关。矢量字库有很多种,区别在于他们采用的不同数学模型来描述组成字符的线条。常见的矢量字库有 type1字库和truetype字库。
在点阵字库中,每个字符由一个位图表示,并把它用一个称为字符掩膜的矩阵来表示,其中的每个元素都是一位二进制数,如果该位为1表示字符的笔画经过此位,该像素置为字符颜色;如果该位为0,表示字符的笔画不经过此位,该像素置为背景颜色。点阵字符的显示分为两步:首先从字库中将它的位图检索出来,然后将检索到的位图写到帧缓冲器中。
在实际应用中,同一个字符有多种字体(如宋体、楷体等),每种字体又有多种大小型号,因此字库的存储空间十分庞大。为了减少存储空间,一般采用压缩技术。
矢量字符记录字符的笔画信息而不是整个位图,具有存储空间小,美观、变换方便等优点。例如:在autocad中使用图形实体-形(shape)-来定义矢量字符,其中,采用了直线和圆弧作为基本的笔画来对矢量字符进行描述。 对于字符的旋转、放大、缩小等几何变换,点阵字符需要对其位图中的每个象素进行变换,而矢量字符则只需要对其几何图素进行变换就可以了,例如:对直线笔画的两个端点进行变换,对圆弧的起点、终点、半径和圆心进行变换等等。
矢量字符的显示也分为两步。首先从字库中将它的字符信息。然后取出端点坐标,对其进行适当的几何变换,再根据各端点的标志显示出字符。
轮廓字形法是当今国际上最流行的一种字符表示方法,其压缩比大,且能保证字符质量。轮廓字形法采用直线、b样条/bezier曲线的集合来描述一个字符的轮廓线。轮廓线构成一个或若干个封闭的平面区域。轮廓线定义加上一些指示横宽、竖宽、基点、基线等等控制信息就构成了字符的压缩数据。
如何使用windows的系统字库生成点阵字库?
我的程序现在只能预览一个汉字的不同字体的点阵表达。
界面很简单: 一个输出点阵大小的选择列表(8x8,16x16,24x24等),一个系统中已有的字体名称列表,一个预览按钮,一块画图显示区域。
得到字体列表的方法:(作者称这一段是用来取回系统的字体,然后添加到下拉框中)
//取字体名称列表的回调函数,使用前要声明一下该方法
int callback myenumfontproc(enumlogfontex* lpelf,newtextmetricex* lpntm,dword nfonttype,long lparam)
{
cfontpeekerdlg* pwnd=(cfontpeekerdlg*) lparam;
if(pwnd)
{
if( pwnd->m_combo_sfont.findstring(0, lpelf->elflogfont.lffacename) m_combo_sfont.addstring(lpelf->elflogfont.lffacename);
return 1;
}
return 0;
}
//说明:cfontpeekerdlg 是我的dialog的类名, m_combo_sfont是列表名称下拉combobox关联的control变量
//调用的地方 (******问题1:下面那个&lf怎么得到呢……)
{
::enumfontfamiliesex((hdc) dc,&lf, (fontenumproc)myenumfontproc,(lparam) this,0);
m_combo_sfont.setcursel(0);
}
字体预览:
如果点阵大小选择16,显示的时候就画出16x16个方格。自定义一个类cmystatic继承自cstatic,用来画图。在cmystatic的onpaint()函数中计算并显示。
取得字体:
常用的方法:用createfont创建字体,把字textout再用getpixel()取点存入数组。 缺点:必须把字textout出来,能在屏幕上看见,不爽。
我的方法,用这个函数:getglyphoutline(),可以得到一个字的轮廓矢量或者位图。可以不用textout到屏幕,直接取得字模信息
函数原型如下:
dword getglyphoutline(
hdc hdc, //画图设备句柄
uint uchar, //将要读取的字符/汉字
uint uformat, //返回数据的格式(字的外形轮廓还是字的位图)
lpglyphmetrics lpgm, // glyphmetrics结构地址,输出参数
dword cbbuffer, //输出数据缓冲区的大小
lpvoid lpvbuffer, //输出数据缓冲区的地址
const mat2 *lpmat2 //转置矩阵的地址
);
说明:
uchar字符需要判断是否是汉字还是英文字符。中文占2个字节长度。
lpgm是输出函数,调用getglyphoutline()是无须给lpgm 赋值。
lpmat2如果不需要转置,将 em11.value=1; em22.value=1; 即可。
cbbuffer缓冲区的大小,可以先通过调用getglyphoutline(……lpgm, 0, null, mat); 来取得,然后动态分配lpvbuffer,再一次调用getglyphoutline,将信息存到lpvbuffer. 使用完毕后再释放lpvbuffer.
程序示例:(***问题2:用这段程序,我获取的字符点阵总都是一样的,不管什么字……)
……前面部分省略……
glyphmetrics glyph;
mat2 m2;
memset(&m2, 0, sizeof(mat2));
m2.em11.value = 1;
m2.em22.value = 1;
//取得buffer的大小
dword cbbuf = dc.getglyphoutline( nchar, ggo_bitmap, &glyph, 0l, null, &m2);
byte* pbuf=null;
//返回gdi_error表示失败。
if( cbbuf != gdi_error )
{
pbuf = new byte[cbbuf];
//输出位图ggo_bitmap 的信息。输出信息4字节(dword)对齐
dc.getglyphoutline( nchar, ggo_bitmap, &glyph, cbbuf, pbuf, &m2);
}
else
{
if(m_pfont!=null)
delete m_pfont;
return;
}
编程中遇到问题:
一开始,getglyphoutline总是返回-1,getlasterror显示是无法完成的功能,后来发现是因为调用之前没有给hdc设置font.
后来能取得pbuf信息后,又开始郁闷,因为不太明白bitmap的结果是按什么排列的。后来跟踪汉字一来调试(这个字简单),注意到了glyph.gmblackboxx 其实就是输出位图的宽度,glyph.gmblackboxy就是高度。如果gmblackboxx=15,glyph.gmblackboxy=2,表示输出的pbuf中有这些信息:位图有2行信息,每一行使用15 bit来存储信息。
例如:我读取一:glyph.gmblackboxx = 0x0e,glyph.gmblackboxy=0x2; pbuf长度cbbuf=8 字节
pbuf信息: 00 08 00 00 ff fc 00 00
字符宽度 0x0e=14 则 第一行信息为: 0000 0000 0000 100 (只取到前14位)
第二行根据4字节对齐的规则,从0xff开始 1111 1111 1111 110
看出一字了吗?呵呵
直到他的存储之后就可以动手解析输出的信息了。
我定义了一个宏#define bit(n) (1《(n)) 用来比较每一个位信息时使用
后来又遇到了一个问题,就是小头和大头的问题了。在我的机器上是little endian的形式,如果我用
unsigned long *lptr = (unsigned long*)pbuf;
//j from 0 to 15
if( *lptr & bit(j) )
{
//这时候如果想用j来表示写1的位数,就错了
}
因为从字节数组中转化成unsigned long型的时候,数值已经经过转化了,像上例中,实际上是0x0800 在同bit(j)比较。
不多说了,比较之前转化一下就可以了if( htonl(*lptr) & bit(j) )
unicode中文点阵字库的生成与使用
点阵字库包含两部分信息。首先是点阵字库文件头信息,它包含点阵字库文字的字号、多少位表示一个像素,英文字母与符号的size、起始和结束unicode编码、在文件中的起始偏移,汉字的size、起始和结束unicode编码、在文件中的起始偏移。然后是真实的点阵数据,即一段段二进制串,每一串表示一个字母、符号或汉字的点阵信息。
要生成点阵字库必须有文字图形的,我的方法是使用ttf字体。ttf字体的显示采用的是sdl_ttf库,这是开源图形库sdl的一个扩展库,它使用的是libfreetype以读取和绘制ttf字体。
它提供了一个函数,通过传入一个unicode编码便能输出相应的文字的带有alpha通道的位图。那么我们可以扫描这个位图以得到相应文字的点阵信息。由于带有alpha通道,我们可以在点阵信息中也加入权值,使得点阵字库也有反走样效果。我采用两位来表示一个点,这样会有三级灰度(还有一个表示透明)。
点阵字库的显示首先需要将文件头信息读取出来,然后根据unicode编码判断在哪个区间内,然后用unicode编码减去此区间的起始unicode编码,算出相对偏移,并加上此区间的文件起始偏移得到文件的绝对偏移,然后读出相应位数的数据,最后通过扫描这段二进制串,在屏幕的相应位置输出点阵字型。
显示点阵字体需要频繁读取文件,因此最好做一个固定大小的缓存,采用lru置换算法维护此缓存,以减少磁盘读取。
标准点阵字库芯片
标准点阵字库芯片的特点:
1.内涵全国信标委授权的标准点阵字型数据、
2.支持国标字符集gb2312(6,763汉字),gb18030(27,484汉字)。
3.支持多种点阵字型,包括11×12点,15×16点,24×24点,32×32点。
4.免除了字库烧录和测试工序,并节省了2%以上的烧录损耗。
5.价格相当于空白flash价格
标准点阵字库芯片的种类和应用
标准点阵汉字字库芯片
1 概述
gt23l24m1w是一款内含24x24点阵的汉字库芯片,支持gb18030国标汉字(含有国家信标委合法授权)及ascii字符,排列格式为横置横排,用户通过字符内码,利用本手册提供的方法计算出该字符点阵在芯片中的地址,可从该地址连续读出字符点阵信息。
1.1 芯片特点
● 数据总线:
spi 串行总线接口
plii 精简地址并行总线接口
● 点阵排列方式:字节横置横排
● 访问速度:
spi 时钟频率:20mhz(max.)
plii 访问速度:130ns(max.)@3.3v
● 工作电压:2.7v~3.6v
● 电流:
工作电流:12ma
待机电流:10ua
● 封装:so20w
● 尺寸(so20w):12.80mmx10.30mm
● 工作温度:-20℃~85℃(spi 模式下);-10℃~85℃(plii 模式下)
1.2 字库内容
字型样张
2 引脚描述与接口连接
2.1 引脚名称
2.2 spi 接口引脚描述
串行数据输出(so):该信号用来把数据从芯片串行输出,数据在时钟的下降沿移出。
串行数据输入(si):该信号用来把数据从串行输入芯片,数据在时钟的上升沿移入。
串行时钟输入(sclk):数据在时钟上升沿移入,在下降沿移出。
片选输入(cs#):所有串行数据传输开始于ce#下降沿,ce#在传输期间必须保持为低电平,在两条
指令之间保持为高电平。
总线挂起输入(hold#):
2.3 spi 接口与主机接口电路示意图
spi 与主机接口电路连接可以参考下图(#hold管脚建议接 2k 电阻 3.3v 拉高)。
若是采用系统电压为 5v的,则需要进行电平转换匹配连接 gt23 芯片,可以参考下图(#hold 管脚建议接 2k 电阻 3.3v 拉高)。
2.4 plii 接口引脚描述
2.5 plii 接口与主机接口电路示意图
spi/plii_sel(管脚内部有 100k 上拉电阻)接地,字库芯片选择 plii 接口模式,与主机接口电路连接可以参考下图。
2.6 plii 总线接口寻址说明
在 plii 总线模式下,芯片内部有 3个地址寄存器,主机需要把要读取数据的地址写入这 3个地址寄存器,然后再从数据寄存器中读出数据。主机每读一次数据寄存器,芯片内部的地址寄存器会自动增一,从而使主机只写一次首地址,就可以连续读取数据。
3 字库调用方法
3.1 汉字点阵排列格式
每个汉字在芯片中是以汉字点阵字模的形式存储的,每个点用一个二进制位表示,存 1的点,当显示
时可以在屏幕上显示亮点,存 0的点,则在屏幕上不显示。点阵排列格式为横置横排:即一个字节的高位
表示左面的点,低位表示右面的点(如果用户按 word mode读取点阵数据,请注意高低字节的顺序),排
满一行的点后再排下一行。这样把点阵信息用来直接在显示器上按上述规则显示,则将出现对应的汉字。
3.1.1 24x24点汉字排列格式
24x24 点汉字的信息需要 72个字节(byte 0 – byte 71)来表示。该 24x24 点汉字的点阵数据是横置横排的,其具体排列结构如下图:
命名规则:
最大字符集及字数
s:gb2312 6,763汉字
m:gb18030 27,484汉字
t:gb12345 6,866汉字
big5 5,401 / 13,060汉字
u:unicode v3.0 27,484汉字

【技术篇F01】什么是汽车级电阻,都有哪些标准?
百信与华为携手推出百信AI科研云平台
四方光电:搭建完善的气体传感器技术平台,自主解决核心关键部件
STM32输出PWM
华为P10评测:对比华为P9、华为mate9,华为P10可谓是集万千宠爱于一身啊!
点阵字库的原理及与矢量字库的差别
UPS电池是什么?
电子芯闻早报:ARM推新芯片,骁龙820真来了
多点触摸屏是什么意思_多点触摸屏原理
揭开了动力电池的神秘面纱
电路基础知识分享之如何接好CAN的地?
设计模式行为型:中介模式
联通百度携手 混改方向引三大猜想
MODBUS转PROFIBUS网关YT-PB-03将仪表接入PROFIBUS的配制方法
余承东:最快今年秋天,最晚明年春天,华为自己的OS将可能面市
小米手表Color参数曝光内置420mAh电池支持GPS和GLONASS卫星定位
断路器的限流等级
苹果13pro人民币价格和开售时间
PD 3.1标准的发布成为USB PD快充技术上的重大更新
达实智能中标光明生命科学大数据中心项目计算平台