昨天写完几篇文章后觉得意犹未尽,我想想了,既然字库文件是二进制文件,完全可以转化为十六进制,存储在数组中,这样在寻找字符时就不用操作文件了,直接在内存中获取。

经过一番调研,证明这个思路是对的,是具有可行性的,同时也具有很强的实践意义的。(此为胡扯,不可相信)

这次写的代码全部使用C语言标准库中与文件有关的函数,所涉及的函数均以“f”开头,做到了平台无关性,为跨平台打下基础,具有很强的移植性。不过由于时间、精力、金钱、能力、水平关系,没有在vc6.0、vs2008、MiniGW、Dev c++下一一测试。

无特别说明,文中说的“ASCII字库”是指ASC16文件,完整给出了0~255的字符。“汉字字库”是指HZK16,包含了GB2312编码中的字符。

啥也别说,直接上代码,完整的代码如下:

#include <stdio.h>

//#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字节为单位,逐一读取该文件的中数据。读取完整的字库文件条件为:

for (i = 0; i < len; i += 16)

但是ASCII中只有区区96个可打印的字符,因此为节省空间起见,就将那么字符存储起来,条件为:

for (i = 0x20*16; i < len/2; i+=16)

至于为什么,前面强调了“实践性”,当然是实践得到的。由于ASC16包含了0~255个,一半即为0~127,可打印字符从0x20处开始,即0x20是第一个可打印的字符——虽然它是空格。有了循环条件,就可以合理地读取,保存到文件中了。使用fseek定位某个字符的偏移,使用fread读取该偏移处的16个字符。之后再使用fprintf写入另一文件中。当然可以每次读取一个字节,写入一个字节,也可以读取32个字节,写入32个字节。至于

fprintf(fp_c, "/* %d 0x%x ' %c ' *//n", i/16, i/16, i/16);

主要是打印这个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 <stdio.h>
#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放到前面,是因为这样更能直观表示我们对面的屏幕的坐标,比如

display_font(1, 0, incode);

就表明了在第1行,第0列显示incode数组的字符。

经过修改后的代码比较整洁,效果与前面的一致,虽然没有了文件的操作,但是占用内存空间比较大,这个代码编译得到的可执行文件大小有271KB,算比较大的了。在操作文件及占用空间之间如何选择,就仁者见仁,智者见智了。

(实践证明,本研究符合当初的设计,经过一段时间的使用,达到预期目标,在生产实践中具有很强的指导意义及教育意义。为将来进一步研究打下牢固的基础。)

至此,近来的研究暂时告一段落,以后搞些什么,再说吧。

点阵字体显示系列补记:将字库文件转换成数组形式相关推荐

  1. 点阵字体显示系列补记2:关于24点阵汉字显示程序及其修改版本

    自从写完16点阵后,由于没啥事做,就继续看看24点阵是如何显示的.这种规格的点阵是使用UCDOS(虽然下载了,但用不了)中的汉字字库.又千辛万苦找到ASCII码的24点阵,再修改前面的程序,生成24点 ...

  2. 点阵字体显示系列之二:汉字显示

    http://blog.csdn.net/subfate/article/details/6444582 免责声明: 本文是作者在研究过程中的一篇文章,本着互联网共享.自由(free,应该不是&quo ...

  3. linux点阵ascii像素字体,点阵字体显示系列之一:ASCII码字库的显示 | 迟思堂工作室...

    起因: 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它 ...

  4. 点阵字体显示系列之三:使用ncurses显示汉字

    ncurses这个库,最早听说应该是当年刚接触Linux的时候,当时,我们宿舍就一个人在鼓捣Linux,他是我们后来的班长,如今在ZLG混,也不知混得怎么样了.我也不知道哪条神经线路出现故障了,竟然傻 ...

  5. 点阵字体显示系列之一:ASCII码字库的显示

    起因: 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它 ...

  6. linux点阵字符显示字体颜色,点阵字体显示系列之一:ASCII码字库的显示

    起因: 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它 ...

  7. linux点阵ascii像素字体,点阵字体显示系列之一:ASCII码字库的显示

    起因: 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它 ...

  8. 【C/C++时间系列】字符串通过strptime函数转换成struct tm

    字符串可以通过strptime函数转换成分解的时间struct tm.关于struct tm的介绍可看 [C/C++时间系列]struct tm 通过strftime转换成字符串 . [strptim ...

  9. 实用系列1 —— 视频中的语音转换成文字

    实用系列1 -- 视频中的语音转换成文字python版本 背景说明 疫情原因,家里的老师亲戚需要对着电脑上网课,晋升为十八线小主播- 备课的内容来源都是当地教育局的公开课,为了学习公开课的上课方法,只 ...

最新文章

  1. 用于3D摄像头的VCSEL技术
  2. CSS中一些语法规范和代码风格
  3. MindCon | 5天啦,你有领取MSG城市专属徽章吗?
  4. 窗口最小化之后没有图标
  5. 一个高效的内存池实现
  6. saltstack 管理mysql_saltstack自动化运维系列④之saltstack的命令返回结果mysql数据库写入...
  7. mcq 队列_MCQ | 基础知识 免费和开源软件| 套装3
  8. Gulp,grunt,seajs/require和browserify/webpack的区别
  9. 插入图像标签(HTML)
  10. Linux下SPI Flash-W25Q64驱动调试
  11. 学以致用-掷双骰儿(craps)游戏的直方图(概率分布)数据分析
  12. [硬件]_ELVE_STLINK下载出现nternal command error问题
  13. 听说看了这篇文章就彻底搞懂了什么是OPC(上)
  14. 图像加密--chua's chaos and baker's transformation
  15. ZYNQ PS使用中遇到问题
  16. 信息系统项目管理师必背核心考点(四)UML类与类之间的关系
  17. 基于EMC的共模干扰与差模干扰以及抑制方法
  18. 练习:试炼自然常数e
  19. html的盒子随页面动,JavaScript实现跟随鼠标移动的盒子
  20. 拍手游戏Python

热门文章

  1. Visual Studio .NET已检测到指定的Web服务器运行的不是ASP.NET 1.1 版...的解决办法
  2. 46个不可不知的生活小常识
  3. 支付宝披露小微商户降费进展:半年减免近50亿
  4. 知乎首次举办上星晚会 定档除夕前夜
  5. 极兔速递完成17.35亿美元融资?回应:不实消息
  6. 自动驾驶,不要再杀人了
  7. 特斯拉维权车主发声:方式会变,维权不会变,绝不妥协!
  8. 华为P50系列即将发布:麒麟9000E/9000处理器有戏?
  9. 谷歌将推出新版Pixel 4a 5G:搭载骁龙765G处理器 售价下降至3200元
  10. 微信又上线了新功能,聊天再也不会发错群了?