點陣縱向取模以及放大算法
http://blog.csdn.net/sddsighhz/article/details/39290703
這兩天在調打印,在網上找各種提取字模相關的算法,但是一般字模取出來後的數據都是橫向的,在打印字上打出來旋轉了90°,沒辦法,只好轉換一下了。
先說一下取字模數據的算法(本人C寫的不多,只能算初級,見笑了):
下面一段摘自網上:
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.區碼減1是因爲數組是以0爲開始而區號位號是以1爲開始的
2.(94*(區號-1)+位號-1)是一個漢字字模佔用的字節數
3.最後乘以32是因爲漢字庫文應從該位置起的32字節信息記錄該字的字模信息(前面提到一個漢字要有32個字節顯示)
//--------------漢字字模的數據結構----------------//
[cpp] view plain copy
typedef struct typFNT_GB16
{
signed char Index[2]; //漢字內碼索引
char Msk[32]; //點陣碼數據
}
[cpp] view plain copy
void getCharLattice(char (*prt),char *buffer)
{
int fh;
long pos; /* Position of file pointer */
long location;
long qh,wh;
fh = open( "/usr/lib/X11/fonts/HZK16", O_RDONLY );
// 漢字的區號
qh=prt[0]-0xa0;
// 漢字的位號
wh=prt[1]-0xa0;
// location=(94*(qh-1)+(wh-1))*一個點陣字模的字節數。
location=(94*(qh-1)+(wh-1))*32;
// 移動指針到location
pos = lseek( fh, location, SEEK_SET);
// 讀數據
read( fh, buffer, 32);
char tmp[16][2];
memcpy(tmp,buffer,32);
transverse_modulus(tmp,buffer);
close( fh );
}
字庫中的字模數據是橫向取模左高位,數據排列:從左到右、從上到下。
我這邊用作打印需要縱向取模,下面是我自己寫的一個轉換算法。聊以備忘
[cpp] view plain copy
char shift_value(char org,int index)
{
org = (org & (0x1 << index)) >> index;
return org;
}
void transverse_modulus(char org[16][2],char *re)
{
char tmp[2][16];
int j=0,n=0,column = 0;
for(;j<2;j++)
{
int i=0,index = 0;
for(;i<16;i++)
{
if(i%2 != 0)
{
n = 1;
}
else
{
n = 0;
}
tmp[j][i] = (shift_value(org[(1-n)*8][column],7-index)<<0) | \
(shift_value(org[(1-n)*8+1][column],7-index)<<1) | \
(shift_value(org[(1-n)*8+2][column],7-index)<<2) | \
(shift_value(org[(1-n)*8+3][column],7-index)<<3) | \
(shift_value(org[(1-n)*8+4][column],7-index)<<4) | \
(shift_value(org[(1-n)*8+5][column],7-index)<<5) | \
(shift_value(org[(1-n)*8+6][column],7-index)<<6) | \
(shift_value(org[(1-n)*8+7][column],7-index)<<7);
if(i%2 != 0)
index ++;
}
column++;
}
memcpy(re,tmp,32);
}
因爲16*16打印出來字體很小,所以放大成32*32。下面也是自己寫的一個放大函數
[cpp] view plain copy
void zoom8(char font8,char *date)
{
int m=0,n=0;
char high,low;
high = (font8 & 0xf0) >> 4;
low = (font8 & 0x0f);
char tmp[2];
memset(tmp,0,2);
int j=0;
for(;m<4;m++)
{
if((high >> m) & 0x1)
{
tmp[0] |= (1 << j);
tmp[0] |= (1 << (j+1));
}
else
{
tmp[0] &= (~(1 << j));
tmp[0] &= (~(1 << (j+1)));
}
j += 2;
}
j=0;
for(;n<4;n++)
{
if((low >> n) & 0x1)
{
tmp[1] |= (1 << j);
tmp[1] |= (1 << (j+1));
}
else
{
tmp[1] &= ~(1 << j);
tmp[1] &= ~(1 << (j+1));
}
j += 2;
}
memcpy(date,tmp,2);
}
//將16*16的數組轉換後拷貝到font32中
void zoom16_to_font32(char *font16,char *font32)
{
char zoomout[32][4];
char zoom[2];
int j=0,i=0,t;
for(;j<32;j++)
{
int n = j%2;
zoom8(font16[j],zoom);
memcpy(zoomout[i]+n*2,zoom ,2);
if(n != 0)
{
memcpy(zoomout[i+1],zoomout[i],4);
i += 2;
}
}
memcpy(font32,zoomout,128);
}
這個放大的原理是將16*16的點陣,當作32*32的,那麼就相當於原來的一個點變成了4個點。上面的代碼是將一行2個字節變成了2行4個字節,這樣放大後的打印效果就比16*16的好很多了。
但是我這裏還有一個問題,就是字母和數字等字符應該如何去提取字模呢?漢字是2個字節,但是字符只有一個字節,在字庫中的位置應該如何計算呢?
HZK16讀取英文數字等字符還沒找到解決方法,不過有人給了一個解決方法,就是字符用ASC16字庫來獲取點陣數據,我試過,是可以實現的。至於讀取方式需要修改前面的讀取代碼:
[cpp] view plain copy
void getCharLattice(char (*prt),char *buffer)
{
int fh;
long pos; /* Position of file pointer */
long location;
long qh,wh;
if(prt[1] & 0xff)
{
fh = open( "/usr/lib/X11/fonts/HZK16", O_RDONLY );
// 漢字的區號
qh=prt[0]-0xa0;
// 漢字的位號
wh=prt[1]-0xa0;
// location=(94*(qh-1)+(wh-1))*一個點陣字模的字節數。
location=(94*(qh-1)+(wh-1))*32;
// 移動指針到location
pos = lseek( fh, location, SEEK_SET);
// 讀數據
read( fh, buffer, 32);
char tmp[16][2];
memcpy(tmp,buffer,32);
transverse_modulus32(tmp,buffer);
}
else
{
((fh=open("/usr/lib/X11/fonts/ASC16",O_RDONLY))< 0) {
printf("Can not open ASC16\r\n");
}
location=prt[0]*16;
lseek(fh,location,SEEK_SET);
read(fh,buffer,16);
char tmp[32];
memcpy(tmp,buffer,16);
transverse_modulus16(tmp,buffer);
}
close( fh );
}
---------------------
原文:https://blog.csdn.net/huabiaochen/article/details/78806373
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!