一、字模提取原理
无非就是从字库文件中读取出字模数据。
以常用的HZK16字库文件为例:该字库文件是符合GB2312国家标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有 3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。
一个字节为8bit,用一个bit位来表示点阵中的一个点的话,16×16点阵需要16*16/8 = 32个字节才能达到显示一个普通汉字的目的。
GBK码也称为区位码,在字库文件中分为94个区。GB2312汉字都是由2字节组成的,第一个字节则是区码,第二个字节则是位码。
HZK16字库文件
汉字区码和位码的起始偏移量都为0xA1(不同的字库偏移量可能不同),故有如下计算公式:
偏移量 = (94*(区码-0xA1)+(位码-0xA1))*32; |
ASC16字库文件
在ASC16字库文件中,没有区位的说法,其偏移量就是ASCII码值。由于是ASCII字符,只占1个字节,其宽度只有8。故一个ASCII字符占用16*8/8=16个字节数据。故有如下公式:
偏移量 = ASCII码值*16; |
二、图示
汉字 "强" (0x7CBF)
ASCII值 "2" (0x32)
三、示例代码
1. 汉字 HZK16 字模提取 16*16
#include<stdio.h> #include <string.h> void Bytes_Read_from_HZK( unsigned char *s, char * chs) { FILE *fp; unsigned long offset; int ret = 0; int i = 0; int j = 0; int k = 0; unsigned char key[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //offset = ((s[0] - 0xb0) * 94 + (s[1] - 0xa1)) * 32; //根据内码找出汉字在HZK中的偏移位置,不同的字库可能偏移位置不同 offset = (94*(unsigned int)(s[0]-0xA1)+(s[1]-0xA1))*32; if ((fp = fopen("HZK16", "rb+")) == NULL) return; //打开字库文件 fseek(fp, offset, SEEK_SET); //文件指针偏移到要找的汉字处 ret = fread(chs, 32, 1, fp); //读取该汉字32个字节的字模数据 printf("ret = %d\n",ret); for(k=0; k<16; k++) { for(j=0; j<2; j++) { for(i=0; i<8; i++) { int flag = chs[k*2+j]&key[i]; printf("%s", flag?"● ":"○ ");//将单个字节每个bit位的状态显示出来 } } printf("\n"); } fclose(fp); } int main(int argc,char *argv[]) { char s[2]={0xC7,0xBF};//强 char chs[32]={0}; char table1[16]={0}; char table2[16]={0}; // memset(chs,0,32); int i = 0; int k = 0; int j = 0; Bytes_Read_from_HZK( s, chs ); for(i = 0; i<32; i++) { if( i % 2 == 0 ) table1[j++] = chs[i]; //由于LED扫描方式的需要,故对数据分组进行处理,调换排列顺序并取反 else table2[k++] = chs[i]; } for(i = 0; i<16 ;i++) { printf("0x%02X,", (unsigned char)(~table1[i])); //数据取反 } printf("\n"); for(i = 0; i<16 ;i++) { printf("0x%02X,", (unsigned char)(~table2[i])); } printf("\n"); return 0; } |
2. 数字、字母 ASC16 字模提取 16*8
#include<stdio.h> #include <string.h> void Bytes_Read_from_HZK( unsigned char *s, char * chs) { FILE *fp; unsigned long offset; int ret = 0; int i = 0; int j = 0; int k = 0; unsigned char key[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; offset = (*s) * 16; //找出在字库中的偏移位置 if ((fp = fopen("ASC16", "r+")) == NULL) { printf("open fail!!\n"); return; //打开字库文件 } fseek(fp, offset, SEEK_SET); //文件指针偏移到要找的字符处 ret = fread(chs, 16, 1, fp); //读取该字符的字模 printf("ret = %d\n",ret); for(k=0; k<16; k++) { for(i=0; i<8; i++) { int flag = chs[k]&key[i]; printf("%s", flag?"● ":"○ "); } printf("\n"); } fclose(fp); } int main(int argc,char *argv[]) { char s[1]={0x32};//数字 "2" char chs[16]={0}; int i = 0; int k = 0; int j = 0; Bytes_Read_from_HZK(s, chs); for(i = 0; i<16; i++) { printf("0x%02X,", (unsigned char)(~chs[i])); } printf("\n"); return 0; } |