點陣字庫的顯示原理



 在嵌入式開發中,經常會用到字庫。字庫分為 矢量字庫點陣字庫,毋庸置疑,矢量字庫的顯示效果是最好的,但是點陣字庫是免費的。所以在很多場合,點陣字庫仍然是產品開發的首選。

   點陣從本質上講就是單色位圖,它使用一個比特來表示一個點如果這個比特為0,表示某個位置沒有點,如果為1表示某個位置有點矩陣和位圖有着密不可分的聯系,矩陣其實是位圖的數學抽象,是一個二維的陣列。位圖就是這種二維的陣列,這個陣列中的(x,y)位置上的數據代表的就是對原始圖形進行采樣量化后的顏色值。但是,另一方面,我們要面對的問題是,計算機中數據的存放都是一維的,線性的。因此,我們需要將二維的數據線性化到一維里面去。通常的做法就是將二維數據按行順序的存放,這樣就線性化到了一維。

    那么點陣字的數據存放細節到底是怎么樣的呢。其實也十分的簡單,舉個例子最能說明問題。比如說 16*16 的點陣,也就是說每一行有16個點,由於一個點使用一個比特來表示,如果這個比特的值為1,則表示這個位置有點,如果這個比特的值為0,則表示這個位置沒有點,那么一行也就需要16個比特,而8個比特就是一個字節,也就是說,這個點陣中,一行的數據需要兩個字節來存放。

    第一行的前八個點的數據存放在點陣數據的第一個字節里面,第一行的后面八個點的數據存放在點陣數據的第二個字節里面,第二行的前八個點的數據存放在點陣數據的第三個字節里面...,然后后面的就以此類推了。這樣我們可以計算出存放一個點陣總共需要32個字節(2*16)。看看下面這個圖形化的例子:

               | |1| | | | | | | | | | |1| | | |
               | | |1|1| |1|1|1|1|1|1|1|1|1| | |
               | | | |1| | | | | | | | |1| | | |
               |1| | | | | |1| | | | | |1| | | |
               | |1|1| | | |1| | | | | |1| | | |
               | | |1| | | |1| | | | |1| | | | |
               | | | | |1| | |1| | | |1| | | | |
               | | | |1| | | |1| | |1| | | | | |
               | | |1| | | | | |1| |1| | | | | |
               |1|1|1| | | | | | |1| | | | | | |
               | | |1| | | | | |1| |1| | | | | |
               | | |1| | | | |1| | | |1| | | | |
               | | |1| | | |1| | | | | |1| | | |
               | | |1| | |1| | | | | | |1|1|1| |
               | | | | |1| | | | | | | | |1| | |
               | | | | | | | | | | | | | | | | |

 

    可以看出這是一個“漢”字的點陣,當然文本的方式效果不是很好。根據上面的原則,我們可以寫出這個點陣的點陣數據:0x40,0x08,0x37,0xfc,0x10,0x08,..., 當然寫這個確實很麻煩所以我不再繼續下去。我這樣做,也只是為了向你說明,在點陣字庫中,每一個點陣的數據就是按照這種方式存放的。

    當然也存在着不規則的點陣,這里說的不規則,指的是點陣的寬度不是8的倍數,比如 12*12 的點陣,那么這樣的點陣數據又是如何存放的呢?其實也很簡單,每一行的前面8個點存放在一個字節里面,每一行的剩下的4點就使用一個字節來存放,也就是說剩下的4個點將占用一個字節的高4位,而這個字節的低4位沒有使用,全部都默認的為零。這樣做當然顯得有點浪費,不過卻能夠便於我們進行存放和尋址。對於其他不規則的點陣,也是按照這個原則進行處理的。這樣我們可以得出一個 m*n 的點陣所占用的字節數為 (m+7)/8*n。

    在明白了以上所講的以后,我們可以寫出一個顯示一個任意大小的點陣字模的函數,這個函數的功能是輸出一個寬度為w,高度為h的字模到屏幕的 (x,y) 坐標出,文字的顏色為 color,文字的點陣數據為 pdata,直接指向一個字模的第一個字節。

 


void _draw_model(char *pdata, int w, int h, int x, int y, int color)
{
    int     i;   
    int     j;   
    int     k;   
    int     nc;  
    int     cols;
    w = (w + 7) / 8 * 8;
    nc = 0;

    for (i=0; i<h; i++)
    {
        cols = 0; 
        for (k=0; k<w 8;="" k++)
        {
            for (j=0; j<8; j++)
            {
                if (pdata[nc]& (0x80 >> j))  //提取對應位
                    putpixel(x+cols, y+i, color);
                cols++;
            }
            nc++;
        }
    }
}

    接下來的問題就是如何在漢字字庫中尋址某個漢字的點陣數據了。要解決這個問題,首先需要了解漢字在計算機中是如何表示的。在計算機中英文可以使用 ASCII 碼來表示,而漢字使用的是擴展ASCII 碼,並且使用兩個擴展 ASCII 碼來表示一個漢字。一個ASCII 碼使用一個字節表示,所謂擴展ASCII 碼,也就是 ASCII 碼的最高位是1的 ASCII 碼,簡單的說就是碼值大於等於 128 的 ASCII 碼。一個漢字由兩個擴展 ASCII 碼組成,第一個擴展 ASCII 碼用來存放區碼,第二個擴展 ASCII 碼用來存放位碼。在 GB2312-80 標准中,將所有的漢字分為94個區,每個區有94個位可以存放94個漢字,形成了人們常說的區位碼,這樣總共就有 94*94=8836 個漢字。在點陣字庫中,漢字點陣數據就是按照這個區位的順序來存放的,也就是最先存放的是第一個區的漢字點陣數據,在每一個區中又是按照位的順序來存放的。在漢字的內碼中,漢字區位碼的存放是在擴展 ASCII 基礎上存放的,並且將區碼和位碼都加上了32,然后存放在兩個擴展 ASCII 碼中。具體的說就是:
    第一個擴展ASCII碼 = 128 + 32 + 漢字區碼
    第二個擴展ASCII嗎 = 128 + 32 + 漢字位碼
    如果用char hz[2]來表示一個漢字,那么我可以計算出這個漢字的區位碼為:
    區碼 = hz[0] - 128 - 32 = hz[0] - 160
    位碼 = hz[1] - 128 - 32 = hz[1] - 160。

    這樣,我們可以根據區位碼在文件中進行尋址了,尋址公式如下:
    漢字點陣數據在字庫文件中的偏移 = ((區碼-1) * 94 + 位碼 - 1) * 一個點陣字模占用的字節數
在尋址以后,即可讀取漢字的點陣數據到緩沖區進行顯示了。以下是實現代碼:

   


void _draw_hz(char hz[2], FILE *fp, int x, int y, int w, int h, int color)
{
    char fontbuf[128];  
    int ch0 = (BYTE)hz[0]-0xA0;
    int ch1 = (BYTE)hz[1]-0xA0;

   
    long offset = (long)pf->_hz_buf_size * ((ch0 - 1) * 94 + ch1 - 1);

    fseek(fp, offset, SEEK_SET);             
    fread(fontbuf, 1, (w + 7) / 8 * h, fp);  
    _draw_model(fontbuf, w, h, x, y, color);
}

    以上介紹完了中文點陣字庫的原理,當然還有英文點陣字庫了。英文點陣字庫中單個點陣字模數據的存放方式與中文是一模一樣的,也就是對我們所寫的 _draw_model 函數同樣可以使用到英文字庫中。唯一不同的是對點陣字庫的尋址上。英文使用的就是 ASCII 碼,其碼值是0到127,尋址公式為:
    英文點陣數據在英文點陣字庫中的偏移 = 英文的ASCII碼 * 一個英文字模占用的字節數

轉自:http://blog.chinaunix.net/uid-20622737-id-1912938.html


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com