当点阵字库遇到3D
早在遥远的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的更多相关文章
- 使用opencv调用24*24点阵字库和8*16ASCII字库在图片显示文字数字
课程实验:编程读汉字点阵字库,把自己的名字和学号叠加到图片的右下位置. 主要步骤分为三部分 第一部分:读取图片(文件读取) 第二部分:读取文字并从字库中提取相应的编码(字库的存储原理) 第三部分:将相 ...
- ASCII字符点阵字库的制作和使用
转自:http://blog.csdn.net/exbob/article/details/6532772 开发环境: Win7,Eclipse,MinGW 1.生成ASCII字符文件 ASCII编码 ...
- GBK点阵显示字库的制作和使用
转自:http://blog.csdn.net/exbob/article/details/6539643 GBK编码共收录汉字21003个.符号883个,并提供1894个造字码位,简.繁体字融于一库 ...
- C Tips:显示点阵汉字的小样例
非常简陋的一段小程序,演示怎样显示点阵字库.有时间的时候再详解. #include <stdio.h> #include <stdlib.h> struct HzkInfoSt ...
- Delphi2010生成GB2312字库乱码问题
用Delphi2010做一个点阵字库软件,字库生成部分是从一个用Delphi2007做旧的程序里扣出来的.点阵字库软件完成后生成GB2312字库在LED控制卡上显示为乱码.知道Delphi版本高于20 ...
- truetype技术和矢量字库的技术原理及实现(转)
源:truetype技术和矢量字库的技术原理及实现 广泛汉字矢量字库(HZKSLxxJ)格式 在矢量字库中,每个汉字都是以128 X 128点阵制成矢量数据.每个汉字 ...
- [自制操作系统] 图形界面&VBE工具&MMIO显存&图形库/字库
本文记录了在JOS(或在任意OS)上实现图形界面的方法与一些图形库的实现. 本文中支持的新特性: 支持基本图形显示 支持中英文显示(中英文点阵字库) 相关:VBE VESA MMIO 点阵字库 Git ...
- 在SDL中显示GBK点阵汉字
大家注意到没有,RA2的中文版本使用的是GBK点阵字库,这样做有一个好处:不管玩家是用的简体还是繁体都能识别显示的文字. GBK的意思大概是“国家标准汉字扩展字符集”吧,记不清了.但它的确是个好东东, ...
- 【STM32H7教程】第52章 STM32H7的LTDC应用之点阵字体和字符编码(重要)
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第52章 STM32H7的LTDC应用之点阵字体和 ...
随机推荐
- OSX:不同OSX版本号的标记可能不兼容
现象: 依据測试,中文OS X 10.9和中文10.10的文件标记彼此不兼容. 也就是说.比方在10.9中的颜色标记,在10.10DP2中不能删除,但能够加入/删除10.10自己的颜色标记,反之亦然. ...
- 解决Hibernate4执行update操作,不更新数据的问题
后台封装java对象,使用hibernate4再带的update,执行不更新数据,不报错. 下面贴出解决方法: 失败的方法 hibernate自带update代码:(失效) Session sessi ...
- YTU 2690: 用双重循环实现小九九
2690: 用双重循环实现小九九 时间限制: 1 Sec 内存限制: 128 MB 提交: 848 解决: 573 题目描述 小九九是我们小时候常背的的乘法算术法则,现在用双重循环来实现小九九 1 ...
- the odb manual
http://www.codesynthesis.com/products/odb/doc/manual.xhtml#18.4
- bzoj2132
最小割 套路最小割... 盗一波图 来自GXZ神犇 对于这样的图,我们要么割ai,bj,要么割bi,aj,要么割ai,ci+cj,aj,要么割bi,ci+cj,bj,然后这样建图跑最小割就行了 但这不 ...
- redirect和forward 的区别
1.从地址栏显示来说 forward 是服务器请求资源,服务器直接访问目标地址url,把那个url的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容从哪里来的,所以他的地 ...
- JavaScript代码优化新工具UglifyJS
jQuery 1.5 发布的时候 john resig 大神说所用的代码优化程序从Google Closure切换到UglifyJS,新工具的压缩效果非常令人满意. UglifyJS 是一个服务端no ...
- 关于mysql的索引原理与慢查询优化
大多情况下我们都知道加索引能提高查询效率,但是应该如何加索引呢?索引的顺序如何呢? 大家看一下下面的sql语句(在没有看下面的优化的方法之前)应该如何优化加索引以及优化sql语句: 1.select ...
- Python 常用算法记录
一.递归 汉诺塔算法:把A柱的盘子,移动到C柱上,最少需要移动几次,大盘子只能在小盘子下面 1.当盘子的个数为n时,移动的次数应等于2^n – 1 2.描述盘子从A到C: (1)如果A只有一个圆盘,可 ...
- bzoj 1619: [Usaco2008 Nov]Guarding the Farm 保卫牧场【bfs】
不是严格小于是小于等于啊!!!!!不是严格小于是小于等于啊!!!!!不是严格小于是小于等于啊!!!!! 是我看不懂人话还是翻译不说人话= = 把所有格子按值排个序,bfs扩展打标记即可 #includ ...