点阵字体显示系列补记:将字库文件转换成数组形式
昨天写完几篇文章后觉得意犹未尽,我想想了,既然字库文件是二进制文件,完全可以转化为十六进制,存储在数组中,这样在寻找字符时就不用操作文件了,直接在内存中获取。
经过一番调研,证明这个思路是对的,是具有可行性的,同时也具有很强的实践意义的。(此为胡扯,不可相信)
这次写的代码全部使用C语言标准库中与文件有关的函数,所涉及的函数均以“f”开头,做到了平台无关性,为跨平台打下基础,具有很强的移植性。不过由于时间、精力、金钱、能力、水平关系,没有在vc6.0、vs2008、MiniGW、Dev c++下一一测试。
无特别说明,文中说的“ASCII字库”是指ASC16文件,完整给出了0~255的字符。“汉字字库”是指HZK16,包含了GB2312编码中的字符。
啥也别说,直接上代码,完整的代码如下:
//#define ASCII
#ifdef ASCII /* ascii */
#define ZK "ASC16"
#define OUT_FILE "ascii16.h"
#define ARRAY "ascii16"
#else /* hz */
#define ZK "HZK16"
#define OUT_FILE "hzk16.h"
#define ARRAY "hzk16"
#endif
int main(void)
{
int i;
FILE *fp_c;
FILE *fp;
int len;
unsigned char mat[32] = {0};
fp = fopen(ZK, "rb");
fp_c = fopen(OUT_FILE, "w+");
/* get file size */
fseek(fp, 0, SEEK_END);
len = ftell(fp);
//printf("len: %d/n", len);
fprintf(fp_c, "/******************************************************//n");
fprintf(fp_c, "/* Font file powered by Late Lee *//n");
fprintf(fp_c, "/* http://www.latelee.org *//n");
fprintf(fp_c, "/* %s %s *//n", __DATE__, __TIME__);
fprintf(fp_c, "/******************************************************//n");
fprintf(fp_c, "unsigned char %s[] = /n{/n", ARRAY);
/* for ascii */
#ifdef ASCII
//for (i = 0; i < len; i += 16) /* full */
for (i = 0x20*16; i < len/2; i+=16) /* 96 printable ascii code */
{
fseek(fp,i,SEEK_SET);
fread(mat,16,1,fp);
fprintf(fp_c, "/* %d 0x%x ' %c ' *//n", i/16, i/16, i/16);
fprintf(fp_c,
"0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,/n/n",
mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],mat[12],mat[13],mat[14],mat[15]);
}
#else
for (i = 0; i < len; i += 32)
{
fseek(fp,i,SEEK_SET);
fread(mat,32,1,fp);
fprintf(fp_c,
"0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,/n",
mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],mat[12],mat[13],mat[14],mat[15],
mat[16],mat[17],mat[18],mat[19],mat[20],mat[21],mat[22],mat[23],mat[24],mat[25],mat[26],mat[27],mat[28],mat[29],mat[30],mat[31]);
}
#endif
fprintf(fp_c, "};/n");
fprintf(stdout, "Job done!/n");
return 0;
}
代码毫无算法可言,如果一定要说点什么,步骤大约是这样的:
1、打开字库文件,创建字库数组头文件,使用的函数为fopen。
2、获取字库文件长度大小,使用fseek和ftell函数。
3、由于ASCII字库中ASCII码占16个字节的空间,因此以16字节为单位,逐一读取该文件的中数据。读取完整的字库文件条件为:
但是ASCII中只有区区96个可打印的字符,因此为节省空间起见,就将那么字符存储起来,条件为:
至于为什么,前面强调了“实践性”,当然是实践得到的。由于ASC16包含了0~255个,一半即为0~127,可打印字符从0x20处开始,即0x20是第一个可打印的字符——虽然它是空格。有了循环条件,就可以合理地读取,保存到文件中了。使用fseek定位某个字符的偏移,使用fread读取该偏移处的16个字符。之后再使用fprintf写入另一文件中。当然可以每次读取一个字节,写入一个字节,也可以读取32个字节,写入32个字节。至于
主要是打印这个ASCII的十进制、十六进制以及它本身显示的字符,从后面三个数可以看出,这几个东西其实是一个东西,本质是一样,只不过表现形式不一样而已。
至于汉字字库,一样的道理,只是以32个字节为一单位。
以ASCII为例,下面是生成的ascii16.h文件的部分内容:
/* Font file powered by Late Lee */
/* http://www.latelee.org */
/* May 26 2011 07:08:09 */
/******************************************************/
unsigned char ascii16[] =
{
/* 32 0x20 ' ' */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* 33 0x21 ' ! ' */
0x00,0x00,0x18,0x3c,0x3c,0x3c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
/* 34 0x22 ' " ' */
0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* 35 0x23 ' # ' */
0x00,0x00,0x00,0x6c,0x6c,0xfe,0x6c,0x6c,0x6c,0xfe,0x6c,0x6c,0x00,0x00,0x00,0x00,
/* 36 0x24 ' $ ' */
0x18,0x18,0x7c,0xc6,0xc2,0xc0,0x7c,0x06,0x06,0x86,0xc6,0x7c,0x18,0x18,0x00,0x00,
/* 37 0x25 ' % ' */
0x00,0x00,0x00,0x00,0xc2,0xc6,0x0c,0x18,0x30,0x60,0xc6,0x86,0x00,0x00,0x00,0x00,
/* 省略很多 */
}
上面格式不太整齐,原因在前面的文章已经说了,其实在编辑器中是非常整齐大方的。
研究成果已经出来了,那么要看看它能不能在实践中经受得起考验。
下面是是昨天经过修改后,并使用上面程序生成的英文字库数组及中文字库数组用ncurses来显示的完整代码:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ncurses.h> /* ncurses库头文件 */
#include "ascii16.h"
#include "hzk16.h"
#define ascii_code ascii16
#define hzk_code hzk16
/* for debug */
//#define DEBUG
#ifdef DEBUG
#define debug(fmt, ...) printw(fmt, ##__VA_ARGS__)
#else
#define debug(fmt, ...)
#endif
static void __display_font(int y, int x, unsigned char *mat, char *code)
{
int i, j, k;
for(i=0;i<16;i++) {
for(j=0;j<2;j++)
{
for(k=0;k<8;k++)
{
/* 从高位开始,逐位相与,为1者,输出“*” */
if(mat[i*2+j] & (0x80>>k))
mvprintw(y+i, x+j*8+k, code);
else
mvprintw(y+i, x+j*8+k, " ");
}
}
}
refresh();
}
static void __display_ascii(int y, int x, unsigned char *ascii, char *code)
{
int i, j;
int bits;
for(i=0;i<16;i++) {
bits = ascii[i];
for(j=0;j<8;j++, bits<<=1) {
if (bits & 0x80)
mvprintw(y+i, x+j, code);
else
mvprintw(y+i, x+j, " ");
}
}
refresh();
}
/*
* 打印ASCII,使用96个可打印字符版本的ASCII码数组
* y:屏幕行
* x:屏幕列
* font:ASCII字符串
* note:注意函数中的unsigned char*类型
*/
void display_ascii(int y, int x, unsigned char *font)
{
unsigned char *p_ascii;
int offset;
unsigned char *p = font;
while (*p != 0) {
offset = (*p - 0x20 ) * 16;
//offset = *p * 16;
p_ascii = ascii_code + offset;
//debug("offset: %x %x/n", p_ascii, offset);
__display_ascii(y, x, p_ascii, "*");
x += 10;
p++;
}
}
/*
* 打印汉字,使用HZK16文件
* fp:汉字库文件指针
* y:屏幕行
* x:屏幕列
* font:汉字字符串
* note:注意函数中的unsigned char*类型
*/
void display_hz(FILE *fp, int y, int x, unsigned char *font)
{
unsigned char mat[32]={0};
int qh,wh;
unsigned long offset;
unsigned char *p = font;
while (*p != 0) {
qh = *p - 0xa0;
wh = *(p+1) - 0xa0;
debug("code : %x %x/n", *p, *(p+1));
offset = ( 94*(qh-1) + (wh-1) ) * 32;
debug("qh: %x wh: %x offset: %x/n", qh, wh, offset);
fseek(fp,offset,SEEK_SET);
fread(mat,32,1,fp);
__display_font(y, x, mat, "*");
x += 18;
p+=2; /* 中文字符,移动2个字节 */
}
}
/*
* 打印字符,中英文混合版本,不使用字库文件
* y:屏幕行
* x:屏幕列
* font:字符串
* note:注意函数中的unsigned char*类型
*/
void display_font(int y, int x, unsigned char *font)
{
int qh,wh;
unsigned long offset;
unsigned char *p = font;
unsigned char *p_ascii;
unsigned char *p_hzk;
while (*p != 0) {
qh = *p - 0xa0;
wh = *(p+1) - 0xa0;
if (qh > 0 && wh > 0){
debug("code : %x %x/n", *p, *(p+1));
offset = ( 94*(qh-1) + (wh-1) ) * 32;
debug("qh: %x wh: %x offset: %x/n", qh, wh, offset);
p_hzk = hzk_code + offset;
__display_font(y, x, p_hzk, "*");
x += 18; /* 16或以上 */
p+=2; /* 中文字符,移动2个字节 */
} else {
int offset1;
offset1 = (*p - 0x20 ) * 16;
p_ascii = ascii_code + offset1;
__display_ascii(y, x, p_ascii, "*");
x += 10; /* 8或以上 */
p+=1; /* 英文字符,移动1个字节 */
}
}
}
int main()
{
//unsigned char incode[] = "我Az你个pf"; /* 全部是中文字符,英文为全角状态下输入 */
//unsigned char incode[] = "波神留我看斜阳"; /* 全部中文 */
//unsigned char incode[] = "人生如梦"; /* 全部中文 */
//unsigned char incode[] = "I'm Late Lee"; /* 全部英文 */
unsigned char incode[] = "我AZ你个pf"; /* 中文、英文 */
initscr(); /* init screen */
display_font(1, 0, incode);
//getch(); /*暂停*/
endwin(); /* close it */
return 0;
}
至于代码中为什么将y放到前面,是因为这样更能直观表示我们对面的屏幕的坐标,比如
就表明了在第1行,第0列显示incode数组的字符。
经过修改后的代码比较整洁,效果与前面的一致,虽然没有了文件的操作,但是占用内存空间比较大,这个代码编译得到的可执行文件大小有271KB,算比较大的了。在操作文件及占用空间之间如何选择,就仁者见仁,智者见智了。
(实践证明,本研究符合当初的设计,经过一段时间的使用,达到预期目标,在生产实践中具有很强的指导意义及教育意义。为将来进一步研究打下牢固的基础。)
至此,近来的研究暂时告一段落,以后搞些什么,再说吧。
点阵字体显示系列补记:将字库文件转换成数组形式相关推荐
- 点阵字体显示系列补记2:关于24点阵汉字显示程序及其修改版本
自从写完16点阵后,由于没啥事做,就继续看看24点阵是如何显示的.这种规格的点阵是使用UCDOS(虽然下载了,但用不了)中的汉字字库.又千辛万苦找到ASCII码的24点阵,再修改前面的程序,生成24点 ...
- 点阵字体显示系列之二:汉字显示
http://blog.csdn.net/subfate/article/details/6444582 免责声明: 本文是作者在研究过程中的一篇文章,本着互联网共享.自由(free,应该不是&quo ...
- linux点阵ascii像素字体,点阵字体显示系列之一:ASCII码字库的显示 | 迟思堂工作室...
起因: 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它 ...
- 点阵字体显示系列之三:使用ncurses显示汉字
ncurses这个库,最早听说应该是当年刚接触Linux的时候,当时,我们宿舍就一个人在鼓捣Linux,他是我们后来的班长,如今在ZLG混,也不知混得怎么样了.我也不知道哪条神经线路出现故障了,竟然傻 ...
- 点阵字体显示系列之一:ASCII码字库的显示
起因: 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它 ...
- linux点阵字符显示字体颜色,点阵字体显示系列之一:ASCII码字库的显示
起因: 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它 ...
- linux点阵ascii像素字体,点阵字体显示系列之一:ASCII码字库的显示
起因: 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它 ...
- 【C/C++时间系列】字符串通过strptime函数转换成struct tm
字符串可以通过strptime函数转换成分解的时间struct tm.关于struct tm的介绍可看 [C/C++时间系列]struct tm 通过strftime转换成字符串 . [strptim ...
- 实用系列1 —— 视频中的语音转换成文字
实用系列1 -- 视频中的语音转换成文字python版本 背景说明 疫情原因,家里的老师亲戚需要对着电脑上网课,晋升为十八线小主播- 备课的内容来源都是当地教育局的公开课,为了学习公开课的上课方法,只 ...
最新文章
- 用于3D摄像头的VCSEL技术
- CSS中一些语法规范和代码风格
- MindCon | 5天啦,你有领取MSG城市专属徽章吗?
- 窗口最小化之后没有图标
- 一个高效的内存池实现
- saltstack 管理mysql_saltstack自动化运维系列④之saltstack的命令返回结果mysql数据库写入...
- mcq 队列_MCQ | 基础知识 免费和开源软件| 套装3
- Gulp,grunt,seajs/require和browserify/webpack的区别
- 插入图像标签(HTML)
- Linux下SPI Flash-W25Q64驱动调试
- 学以致用-掷双骰儿(craps)游戏的直方图(概率分布)数据分析
- [硬件]_ELVE_STLINK下载出现nternal command error问题
- 听说看了这篇文章就彻底搞懂了什么是OPC(上)
- 图像加密--chua's chaos and baker's transformation
- ZYNQ PS使用中遇到问题
- 信息系统项目管理师必背核心考点(四)UML类与类之间的关系
- 基于EMC的共模干扰与差模干扰以及抑制方法
- 练习:试炼自然常数e
- html的盒子随页面动,JavaScript实现跟随鼠标移动的盒子
- 拍手游戏Python
热门文章
- Visual Studio .NET已检测到指定的Web服务器运行的不是ASP.NET 1.1 版...的解决办法
- 46个不可不知的生活小常识
- 支付宝披露小微商户降费进展:半年减免近50亿
- 知乎首次举办上星晚会 定档除夕前夜
- 极兔速递完成17.35亿美元融资?回应:不实消息
- 自动驾驶,不要再杀人了
- 特斯拉维权车主发声:方式会变,维权不会变,绝不妥协!
- 华为P50系列即将发布:麒麟9000E/9000处理器有戏?
- 谷歌将推出新版Pixel 4a 5G:搭载骁龙765G处理器 售价下降至3200元
- 微信又上线了新功能,聊天再也不会发错群了?