早在遥远的DOS时代,点阵汉字库为计算机处理汉字起到了关键作用。当时的显示器在图形模式下的分辨率只有640x480甚至320x200,显示汉字直接使用点阵字库在屏幕上打点就可以了。如今的电脑屏幕甚至手机、电视屏幕都已经进入视网膜高清屏时代,字体也早使用了矢量化技术。其实在工控机等嵌入式设备领域点阵字库依旧用途广泛。除此之外,前辈们苦心整理的这些HZK12、HZK16、HZK24汉字点阵字库还有什么用途吗?本文我们就尝试用twaver的3d技术来继续发挥这些点阵字库的余热。

字库

网上可以轻松搜索到hzk12、hzk16、hzk24、hzk32等各规格的点阵字库文件。以最简单常用的汉字集合gb2312为例,6763个汉字,对12的点阵字库来说,只有不到200k。但是12的点阵有点太粗糙了,视觉上已经很难接受,甚至无法辨认。16的显示效果略好,文件在260k左右。32点阵的汉字尺寸会达到几兆,一个汉字点阵=32x32=1024个点,无论用3d还是2d来处理,量都有点大。所以这里选择16的字库做例子。另外一般24的点阵字库主要用于打印,其方向是反的,程序处理时需要注意循环方向。

现在也有软件可以自动生成点阵的汉字库,指定机器上的字库和分辨率然后处理即可。如果对点阵字库不满意,您可以自己生成一个。对于16的点阵来说,能显示清楚就不错了,字体样式美观性就谈不上了,所以重新生成也没什么意义。这些字库中的文字点阵已经是优化处理成最好的显示效果了。

要在js中处理这些点阵数据,直接用二进制文件太麻烦,最好是处理成js的格式,例如数组、json等。首先要熟悉一下字库的结构。

hzk16二进制点阵文件包含了GB2312中定义的汉字。GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。GB2312 将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09 区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。每个汉字由16x16个点定义,也就是每个汉字2x16=32个字节。所以,知道了一个汉字的区位码,就能算出汉字点阵的绝对偏移位置。下面代码显示了如何从点阵字节序列中获得一个汉字的点阵字节数据:

//汉字点阵数据在字库文件中的偏移:
//偏移 = ((区码-1) * 94 + 位码) * 一个点阵字模占用的字节数
//区位码都是从1开始,所以别忘记减1。
var offset = ((code1 -1) * 94 + (code2-1)) * 32;
为了让上面代码能工作,就要准备一个包含点阵字库每个字节的数组给js,便于处理。这里用java写了几句代码,转换hzk16文件,然后另存为一个js认识的数据文件(一个数组变量)。
import java.io.*;

public class Main {
public static void main(String[] args) {
String type = "16";
try {
StringBuilder result = new StringBuilder();
result.append("var hzk" + type + "=[\n\t");
FileInputStream stream = new FileInputStream("C:/twaver/hzk" + type);
int c;
while ((c = stream.read()) != -1) {
result.append(c + ",");
}
stream.close();
result.append("\n];"); DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("C:/twaver/hzk" + type + ".js")));
out.writeBytes(result.toString());
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行上面java代码,即可读取c:\twaver\hzk16点阵文件并生成一个c:\twaver\hzk16.js的js文件,中间包含了每一个字节的数组:

var hzk16=[
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0//....此处省略一万字...
];

有了点阵数据,就可以继续上面的代码,循环读取一个汉字的点阵信息了。假设我们有一个区位码为4000的汉字要显示:

var code=4000;
var code1=parseInt(code/100);
var code2=(code % 100) ;
//offset=(94*(区码-1)+(位码-1))*32
var offset=((code1-1)*94+(code2-1))*32;
var FontSize=16; for(var row=0; row<FontSize;row++){
var rowMask1=hzk16[offset+row*2];
var rowMask2=hzk16[offset+row*2+1]; var rowMask=rowMask1 << 8 | rowMask2; for(var column=0; column<FontSize; column++){
var position=FontSize-column-1;
var m=Math.pow(2, position);
var flag=rowMask & m;
flag=flag>>position;
//这个点显示还是不显示,这个flag说了算。继续处理显示...
updateNode(nodes[row*FontSize+column], flag);
}
}

有了点阵信息,接下来就可以用twaver的强大3d场景来显示了。

显示

先用最简单的:我们用一个16x16的立方体矩阵来显示一个点阵汉字。然后把这256个立方体记下来:

function createNodes(){
var nodes=[];
for(var i=0;i<16;i++){
for(var j=0;j<16;j++){
nodes.push(createNode(box, i, j));
}
}
return nodes;
}

接下来在沙盘上显示汉字。通过点阵控制每一个点,有打点的位置,其立方体修改图片、变色、高亮、位置拉高;否则保持原位不动。继续上面程序的updateNode函数:

function updateNode(node, flag){
var height= flag ? 20 : 2;
var pic=flag ? 'test.png' : 'test2.png';
node.setStyle('m.texture.image', pic);
//等等其他效果变化...

为了让效果更生动,我们使用twaver提供的内置动画:让立方体慢慢变色、变高。这里大家刚好也可以再熟悉一下twaver的动画技术:

var animateRotate=new twaver.Animate({
from: oldHeight,
to: height,
//变化速度由近到远,产生“波浪”效果
dur: (node.getClient('row')+node.getClient('column'))*80,
easing: 'easeBothStrong',
onUpdate: function (value) {
//动画高度、动画颜色
node.setHeight(value);
node.setPositionY(value/2-1);
var percent=parseInt(255*(value-2)/(20-2));
var red=percent.toString(16);
if(red.length==1){
red='0'+red;
}
var color='#'+red+'AA00'; node.s({
'm.color': color,
'm.ambient': color,
});
}
});
//启动动画
animateRotate.play();

转码

还有一个问题,就是如何获得一个汉字的区位码?毕竟display([4034, 4098, 2093, 4233])这样的代码没有display('赛瓦软件')更方便。于是要研究一下js中如何直接获得字符的区位码。

现在的操作系统基本上都是用unicode这些国际通用格式。而unicode和gbk/gb2312这些本土国标中的字符编码基本没有什么对应关系。一般操作系统都会有api可以获得转换,但在js里面,这意味着我们只能自行准备一张对应表来转换了。

其实想想也不麻烦:我们准备一个字符串,字符序列按gb2312中汉字的顺序进行排列。然后给一个汉字,我们就看它在字符串中出现的位置。这个位置也就是其区位码偏移,然后就可以算出区码和位码了。

根据这个思路,找到了大牛秋水无痕在2002年9月17日的一篇博文:,其中介绍了这个思路,并提供了一份文字表。在下载时需要注意,最好重新创建一个新文件并把文字表重新复制保存,避免文件本身编码差异造成乱码或无法转码的情况。

根据博文思路,根据需求重新写了一下读取区位码的函数:

function getGBCodes(str){
var i,c,p,q,result=[];
for(i=0;i<str.length;i++){
if(str.charCodeAt(i)>=0x4e00){
var p=strGB.indexOf(str.charAt(i));
if(p>=0){
q=p%94;
p=(p-q)/94;
var code1=0xB0+p-0xA0;
var code2=0xA1+q-0xA0;
var code=code1*100+code2;
result.push(code);
}
}else{
result.push(0);
}
}
return result;
}

给任意字符串,遍历每个字符,算出其区码和位码,组合成4位数区位码放入数组中返回。注意这里简化起见,只包含了gb2312中的常用汉字,特殊字符等均未处理。

最后,显示个字符串得瑟一下:

var box = new mono.DataBox();
var nodes=initNodes();
var codes=getGBCodes('赛瓦软件');
var index=0; function init() {
var camera = new mono.PerspectiveCamera(30, 1.5, 10, 10000);
camera.setPosition(50,200,500); var network= new mono.Network3D(box, camera, myCanvas);
var interaction = new mono.DefaultInteraction(network);
network.setInteractions([new mono.SelectionInteraction(network), interaction]);
mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight'); var pointLight = new mono.PointLight(0xFFFFFF,1);
pointLight.setPosition(100,1000,-1000);
box.add(pointLight);
var pointLight = new mono.PointLight(0xFFFFFF,1);
pointLight.setPosition(-1000,-100,0);
box.add(pointLight);
box.add(new mono.AmbientLight(0x888888)); setInterval(function(){
displayWord(codes[index]);
index=index==codes.length ? 0 : index+1;
}, 2000);
}

最后看视频效果:

http://v.youku.com/v_show/id_XOTMzNjMxMjM2.html

其他

其实在3d中处理汉字还是比较麻烦的。汉字字符多形状复杂,对于英文字库来说还行,但对于汉字库来说,如果要将其矢量信息转到json中供3d使用则数据量太大,很难实现(做特定的若干个汉字处理倒是可行)。一般处理方法只能是将汉字渲染在图片上进行显示。这样的不足是汉字结果是扁平的一张图片,没有模型信息和3d效果。用点阵字库,虽然略显粗糙,但是可以换来完全的模型化的字符信息和显示效果,充分利用3d的各种效果。而增加的js数据量也不大(几百k)。这也为大家提供了一种3d中处理汉字的一种思路。

如需要本文相关代码和资料请发邮件或留言。谢谢!

当点阵字库遇到3D的更多相关文章

  1. 使用opencv调用24*24点阵字库和8*16ASCII字库在图片显示文字数字

    课程实验:编程读汉字点阵字库,把自己的名字和学号叠加到图片的右下位置. 主要步骤分为三部分 第一部分:读取图片(文件读取) 第二部分:读取文字并从字库中提取相应的编码(字库的存储原理) 第三部分:将相 ...

  2. ASCII字符点阵字库的制作和使用

    转自:http://blog.csdn.net/exbob/article/details/6532772 开发环境: Win7,Eclipse,MinGW 1.生成ASCII字符文件 ASCII编码 ...

  3. GBK点阵显示字库的制作和使用

    转自:http://blog.csdn.net/exbob/article/details/6539643 GBK编码共收录汉字21003个.符号883个,并提供1894个造字码位,简.繁体字融于一库 ...

  4. C Tips:显示点阵汉字的小样例

    非常简陋的一段小程序,演示怎样显示点阵字库.有时间的时候再详解. #include <stdio.h> #include <stdlib.h> struct HzkInfoSt ...

  5. Delphi2010生成GB2312字库乱码问题

    用Delphi2010做一个点阵字库软件,字库生成部分是从一个用Delphi2007做旧的程序里扣出来的.点阵字库软件完成后生成GB2312字库在LED控制卡上显示为乱码.知道Delphi版本高于20 ...

  6. truetype技术和矢量字库的技术原理及实现(转)

    源:truetype技术和矢量字库的技术原理及实现 广泛汉字矢量字库(HZKSLxxJ)格式             在矢量字库中,每个汉字都是以128   X   128点阵制成矢量数据.每个汉字  ...

  7. [自制操作系统] 图形界面&VBE工具&MMIO显存&图形库/字库

    本文记录了在JOS(或在任意OS)上实现图形界面的方法与一些图形库的实现. 本文中支持的新特性: 支持基本图形显示 支持中英文显示(中英文点阵字库) 相关:VBE VESA MMIO 点阵字库 Git ...

  8. 在SDL中显示GBK点阵汉字

    大家注意到没有,RA2的中文版本使用的是GBK点阵字库,这样做有一个好处:不管玩家是用的简体还是繁体都能识别显示的文字. GBK的意思大概是“国家标准汉字扩展字符集”吧,记不清了.但它的确是个好东东, ...

  9. 【STM32H7教程】第52章 STM32H7的LTDC应用之点阵字体和字符编码(重要)

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第52章       STM32H7的LTDC应用之点阵字体和 ...

随机推荐

  1. webpy学习笔记之中的一个

    这几天在学习webpy框架,之前学过一段时间,后来各种转移框架,导致没有学透彻,都是皮毛,各种打印hello world! 汗! 如今将webpy的学习过程和思路写下来,便于复习和总结. 资料主要是w ...

  2. SpringMVC_1

    //@SessionAttributes(value={"user"},types={String.class}) @Controller public class SpringM ...

  3. YTU 2625: B 构造函数和析构函数

    2625: B 构造函数和析构函数 时间限制: 1 Sec  内存限制: 128 MB 提交: 772  解决: 513 题目描述 在建立类对象时系统自动该类的构造函数完成对象的初始化工作, 当类对象 ...

  4. 关于flask的错误:ImportError: cannot import name 'Flask'

    刚开始接触flask,新创建后不能运行,报错如下图: 导致该错误有两种可能,没安装flask:文件名为flask. 可尝试如下两种方法解决: 方法一:若没安装过flask,则进入cmd,输入pip i ...

  5. RDA 互斥锁的使用

    在多线程下,在同一时间内,可能有多个线程在操作.如果没有同步机制,那么很难保证每个线程操作的正确性. 1.互斥锁概念: 互斥锁提供一个可以在同一时间,只让一个线程访问临界资源的的操作接口.互斥锁(Mu ...

  6. maven中的三种工程,以及在idea中构建父子工程。

    1.pom工程:用在父级工程或聚合工程中.用来做jar包的版本控制.主要是定义POM文件,将后续各个子模块公用的jar包等统一提出来,类似一个抽象父类 2.war工程:将会打包成war,发布在服务器上 ...

  7. linux下解压zip文件时,文件名乱码的解决(转载)

    转自:http://blog.sina.com.cn/s/blog_6261f8690101c1gx.html windows下的zip文件,在linux下解压时,经常会出现文件名乱码的情况. 主要原 ...

  8. VIDIOC_S_INPUT 作用 (转载)

    转载:http://blog.csdn.net/kickxxx/article/details/7088658 G_INPUT和S_INPUT用来查询和选则当前的input 一个video设备节点可能 ...

  9. Flask-SQLAlchemy - 不使用外键连表查询。记得常回来看我

    前言 相比于 Django 的 ORM ,SQLAlchemy "不依靠外键进行跨表联查" 的解决方案就比较多. 没啥好说的,只能怪自己学艺不精..  _(:з」∠)_ 解决办法 ...

  10. jQuery——表单应用(3)

    HTML: <!--表单-多行文本框应用-滚动条高度变化--> <!DOCTYPE html> <html> <head> <meta chars ...