前言:最近有個關於泰國文字識別並打印的項目。之前對泰文的瞭解只聽過“薩瓦迪卡”-_-!!,所以前兩天在學習泰文的排版規範及unicode編碼,瞭解之後開始學習文字點陣打印的原理及代碼編寫。今天學習了漢字16*16點陣字庫的使用。
這裏首先感謝陪她去流浪大佬的文章(這個大佬的id一聽就是有女朋友的,羨慕o.o),文章簡介明瞭、通俗易懂,代碼講解也非常的詳細。
原理:
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個字節顯示)
圖示:
“我”的點陣輸出如下圖所示:
所以,“我”在HZK16*16點陣字庫的存放序列爲(一行一行地保存,共16行,每行2個字節,共32個字節):
程序輸出應該這樣:
源代碼實例:
版本1
#include <stdio.h>
int main(void)
{
FILE* fd = 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 };
fd = fopen("hzk16", "rb");
if (fd == NULL)
{
fprintf(stderr, "error hzk16\n");
return 1;
}
offset = (94 * (unsigned int)(word[0] - 0xa0 - 1) + (word[1] - 0xa0 - 1)) * 32;
fseek(fd, offset, SEEK_SET);
fread(buffer, 1, 32, fd);
for (k = 0; k<32; k++){
printf("%02X ", buffer[k]);
}
printf("\n");
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(fd);
fd = 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;
}
版本3
#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[2] = {0xCE, 0xD2}; // 改成你的轉碼後的漢字編碼
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<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");
}
for(k=0; k<31; k++){
printf("0x%02X,", buffer[k]);
}
printf("\n");
fclose(fphzk);
fphzk = NULL;
return 0;
}
各種字庫下載地址:http://pan.baidu.com/share/link?shareid=2514580636&uk=320828865