最近(很久之前的最近)在弄硬件,買了一塊彩屏,需要字庫,所以就把很久以前會的知識拿出來溫習了一遍。果然好多都記憶模糊了。網上的代碼我看過,很多都有問題,這里我帖出來的是我自己寫的代碼,沒有問題。
HZK16字庫是符合GB2312標准的16×16點陣字庫,HZK16的GB2312-80支持的漢字有6763個,符號682個。其中一級漢字有 3755個,按聲序排列,二級漢字有3008個,按偏旁部首排列。
我們在一些應用場合根本用不到這么多漢字字模,所以在應用時就可以只提取部分字體作為己用。
HZK16字庫里的16×16漢字一共需要256個點來顯示,也就是說需要32個字節才能達到顯示一個普通漢字的目的。
我們知道一個GB2312漢字是由兩個字節編碼的,范圍為0xA1A1~0xFEFE。A1-A9為符號區,B0-F7為漢字區。每一個區有94個字符(注意:這只是編碼的許可范圍,不一定都有字型對應,比如符號區就有很多編碼空白區域)。
下面以漢字"我"為例,介紹如何在HZK16文件中找到它對應的32個字節的字模數據。前面說到一個漢字占兩個字節,這兩個中前一個字節為該漢字的區號,后一個字節為該字的位號。其中,每個區記錄94個漢字,位號為該字在該區中的位置。所以要找到"我"在hzk16庫中的位置就必須得到它的區碼和位碼。
區碼:漢字的第一個字節-0xA0 (因為漢字編碼是從0xA0區開始的, 所以文件最前面就是從0xA0區開始, 要算出相對區碼)
位碼:漢字的第二個字節-0xA0
這樣我們就可以得到漢字在HZK16中的絕對偏移位置:
offset=(94*(區碼-1)+(位碼-1))*32
注解:
- 區碼減1是因為數組是以0為開始而區號位號是以1為開始的
- (94*(區號-1)+位號-1)是一個漢字字模占用的字節數
- 最后乘以32是因為漢字庫文應從該位置起的32字節信息記錄該字的字模信息(前面提到一個漢字要有32個字節顯示)
我畫的圖示:
●●●●●●●●●●●●●●●● → 0x04,0x80 ●●●●●●●●●●●●●●●● → 0x0E,0xA0 ●●●●●●●●●●●●●●●● → 0x78,0x90 ●●●●●●●●●●●●●●●● → 0x08,0x90 ●●●●●●●●●●●●●●●● → 0x08,0x84 ●●●●●●●●●●●●●●●● → 0xFF,0xFE ●●●●●●●●●●●●●●●● → 0x08,0x80 ●●●●●●●●●●●●●●●● → 0x08,0x90 ●●●●●●●●●●●●●●●● → 0x0A,0x90 ●●●●●●●●●●●●●●●● → 0x0C,0x60 ●●●●●●●●●●●●●●●● → 0x18,0x40 ●●●●●●●●●●●●●●●● → 0x68,0xA0 ●●●●●●●●●●●●●●●● → 0x09,0x20 ●●●●●●●●●●●●●●●● → 0x0A,0x14 ●●●●●●●●●●●●●●●● → 0x28,0x14 ●●●●●●●●●●●●●●●● → 0x10,0x0C
所以,'我'在HZK16 16*16點陣字庫的存放的序列為:
(一行一行地保存,共16行,每行2個字節, 共32個字節)
04 80 0E A0 78 90 08 90 08 84 FF FE 08 80 08 90 0A 90 0C 60 18 40 68 A0 09 20 0A 14 28 14 10 0C
就像下面這樣:
以下是我自己寫的示例程序, 可以自己修改成其它的數據格式.(很簡單, 所以沒寫注釋)。
示例源代碼
版本1
#include <stdio.h> int main(void) { FILE* fphzk = NULL; int i, j, k, offset; int flag; unsigned char buffer[32]; unsigned char word[3] = "我"; unsigned char key[8] = { 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 }; fphzk = fopen("hzk16", "rb"); if(fphzk == NULL){ fprintf(stderr, "error hzk16\n"); return 1; } offset = (94*(unsigned int)(word[0]-0xa0-1)+(word[1]-0xa0-1))*32; fseek(fphzk, offset, SEEK_SET); fread(buffer, 1, 32, fphzk); for(k=0; k<32; k++){ printf("%02X ", buffer[k]); } for(k=0; k<16; k++){ for(j=0; j<2; j++){ for(i=0; i<8; i++){ flag = buffer[k*2+j]&key[i]; printf("%s", flag?"●":"○"); } } printf("\n"); } fclose(fphzk); fphzk = NULL; return 0; }
版本2
#include <stdio.h> #include <stdlib.h> int main(void) { FILE* fphzk = NULL; int i, j, k, offset; int flag; unsigned char buffer[32]; unsigned char word[5]; unsigned char key[8] = { 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 }; fphzk = fopen("hzk16", "rb"); if(fphzk == NULL){ fprintf(stderr, "error hzk16\n"); return 1; } while(1){ printf("輸入要生成字模的漢字(多個):"); for(;;){ fgets((char*)word, 3, stdin); if(*word == '\n') break; offset = (94*(unsigned int)(word[0]-0xa0-1)+(word[1]-0xa0-1))*32; fseek(fphzk, offset, SEEK_SET); fread(buffer, 1, 32, fphzk); for(k=0; k<16; k++){ for(j=0; j<2; j++){ for(i=0; i<8; i++){ flag = buffer[k*2+j]&key[i]; printf("%s", flag?"●":"○"); } } printf("\n"); } printf("uchar code key[32] = {"); for(k=0; k<31; k++){ printf("0x%02X,", buffer[k]); } printf("0x%02X};\n", buffer[31]); printf("\n"); } } fclose(fphzk); fphzk = NULL; return 0; }
轉自:https://blog.twofei.com/embedded/hzk.html