點陣縱向取模以及放大算法

點陣縱向取模以及放大算法

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 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章