點(diǎn)陣字庫的生產(chǎn)原理
所有的漢字或者英文都是下面的原理,由左至右,每8個(gè)點(diǎn)占用一個(gè)字節(jié),最后不足8個(gè)字節(jié)的占用一個(gè)字節(jié),而且從最高位向最低位排列。
生成的字庫說明:(以12×12例子)
一個(gè)漢字占用字節(jié)數(shù):12÷8=1····4也就是占用了2×12=24個(gè)字節(jié)。
編碼排序A0A0→A0FE A1A0→A2FE依次排列。
以12×12字庫的“我”為例:“我”的編碼為CED2,所以在漢字排在CEH-AOH=2EH區(qū)的D2H-A0H=32H個(gè)。所以在12×12字庫的起始位置就是[{FE-A0}*2EH+32H]*24=104976開始的24個(gè)字節(jié)就是我的點(diǎn)陣模。
其他的類推即可。
英文點(diǎn)陣也是如此推理。
在DOS程序中使用點(diǎn)陣字庫的方法
首先需要理解的是點(diǎn)陣字庫是一個(gè)數(shù)據(jù)文件,在這個(gè)數(shù)據(jù)文件里面保存了所有文字的點(diǎn)陣數(shù)據(jù)。至于什么是點(diǎn)陣,我想我不講大家都知道 的,使用過"文曲星"之類的電子辭典吧,那個(gè)的液晶顯示器上面顯示的漢子就能夠明顯的看出"點(diǎn)陣"的痕跡。在 PC 機(jī)上也是如此,文字也是由點(diǎn)陣來組成了,不同的是,PC機(jī)顯示器的顯示分辨率更高,高到了我們?nèi)庋蹮o法區(qū)分的地步,因此"點(diǎn)陣"的痕跡也就不那么明顯了。
點(diǎn)陣、矩陣、位圖這三個(gè)概念在本質(zhì)上是有聯(lián)系的,從某種程度上來講,這三個(gè)就是同義詞。點(diǎn)陣從本質(zhì)上講就是單色位圖,他使用一個(gè)比特來表示一個(gè)點(diǎn),如果這 個(gè)比特為0,表示某個(gè)位置沒有點(diǎn),如果為1表示某個(gè)位置有點(diǎn)。矩陣和位圖有著密不可分的聯(lián)系,矩陣其實(shí)是位圖的數(shù)學(xué)抽象,是一個(gè)二維的陣列。位圖就是這種 二維的陣列,這個(gè)陣列中的 (x,y) 位置上的數(shù)據(jù)代表的就是對(duì)原始圖形進(jìn)行采樣量化后的顏色值。但是,另一方面,我們要面對(duì)的問題是,計(jì)算機(jī)中數(shù)據(jù)的存放都是一維的,線性的。因此,我們需要 將二維的數(shù)據(jù)線性化到一維里面去。通常的做法就是將二維數(shù)據(jù)按行順序的存放,這樣就線性化到了一維。
那么點(diǎn)陣字的數(shù)據(jù)存放細(xì)節(jié)到底是怎么樣的呢。其實(shí)也十分的簡(jiǎn)單,舉個(gè)例子最能說明問題。比如說 16*16 的點(diǎn)陣,也就是說每一行有16個(gè)點(diǎn),由于一個(gè)點(diǎn)使用一個(gè)比特來表示,如果這個(gè)比特的值為1,則表示這個(gè)位置有點(diǎn),如果這個(gè)比特的值為0,則表示這個(gè)位置沒 有點(diǎn),那么一行也就需要16個(gè)比特,而8個(gè)比特就是一個(gè)字節(jié),也就是說,這個(gè)點(diǎn)陣中,一行的數(shù)據(jù)需要兩個(gè)字節(jié)來存放。第一行的前八個(gè)點(diǎn)的數(shù)據(jù)存放在點(diǎn)陣數(shù) 據(jù)的第一個(gè)字節(jié)里面,第一行的后面八個(gè)點(diǎn)的數(shù)據(jù)存放在點(diǎn)陣數(shù)據(jù)的第二個(gè)字節(jié)里面,第二行的前八個(gè)點(diǎn)的數(shù)據(jù)存放在點(diǎn)陣數(shù)據(jù)的第三個(gè)字節(jié)里面,…,然后后 面的就以此類推了。這樣我們可以計(jì)算出存放一個(gè)點(diǎn)陣總共需要32個(gè)字節(jié)??纯聪旅孢@個(gè)圖形化的例子:
可以看出這是一個(gè)"漢"字的點(diǎn)陣,當(dāng)然文本的方式效果不是很好。根據(jù)上面的原則,我們可以寫出這個(gè)點(diǎn)陣的點(diǎn)陣數(shù) 據(jù):0x40,0x08,0x37,0xfc,0x10,0x08,…, 當(dāng)然寫這個(gè)確實(shí)很麻煩所以我不再繼續(xù)下去。我這樣做,也只是為了向你說明,在點(diǎn)陣字庫中,每一個(gè)點(diǎn)陣的數(shù)據(jù)就是按照這種方式存放的。
當(dāng)然也存在著不規(guī)則的點(diǎn)陣,這里說的不規(guī)則,指的是點(diǎn)陣的寬度不是8的倍數(shù),比如 12*12 的點(diǎn)陣,那么這樣的點(diǎn)陣數(shù)據(jù)又是如何存放的呢?其實(shí)也很簡(jiǎn)單,每一行的前面8個(gè)點(diǎn)存放在一個(gè)字節(jié)里面,每一行的剩下的4點(diǎn)就使用一個(gè)字節(jié)來存放,也就是說 剩下的4個(gè)點(diǎn)將占用一個(gè)字節(jié)的高4位,而這個(gè)字節(jié)的低4位沒有使用,全部都默認(rèn)的為零。這樣做當(dāng)然顯得有點(diǎn)浪費(fèi),不過卻能夠便于我們進(jìn)行存放和尋址。對(duì)于 其他不規(guī)則的點(diǎn)陣,也是按照這個(gè)原則進(jìn)行處理的。這樣我們可以得出一個(gè) m*n 的點(diǎn)陣所占用的字節(jié)數(shù)為 (m+7)/8*n.
在明白了以上所講的以后,我們可以寫出一個(gè)顯示一個(gè)任意大小的點(diǎn)陣字模的函數(shù),這個(gè)函數(shù)的功能是輸出一個(gè)寬度為w,高度為h的字模到屏幕的 (x,y) 坐標(biāo)出,文字的顏色為 color,文字的點(diǎn)陣數(shù)據(jù)為 pdata 所指:
/*輸出字模的函數(shù)*/
void _draw_model(char *pdata, int w, int h, int x, int y, int color)
{
int i; /* 控制行 */
int j; /* 控制一行中的8個(gè)點(diǎn) */
int k; /* 一行中的第幾個(gè)"8個(gè)點(diǎn)"了 */
int nc; /* 到點(diǎn)陣數(shù)據(jù)的第幾個(gè)字節(jié)了 */
int cols; /* 控制列 */
BYTE static mask[8]={128, 64, 32, 16, 8, 4, 2, 1}; /* 位屏蔽字 */
w = (w + 7) / 8 * 8; /* 重新計(jì)算w */
nc = 0;
for (i=0; i
{
cols = 0;
for (k=0; k
{
for (j=0; j<8; j++)
{
if (pdata[nc]&mask[j])
putpixel(x+cols, y+i, color);
cols++;
}
nc++;
}
}
}
代碼很簡(jiǎn)單,不用怎么講解就能看懂,代碼可能不是最優(yōu)化的,但是應(yīng)該是最易讀懂的。其中的 putpixel 函數(shù),使用的是TC提供的 Graphics 中的畫點(diǎn)函數(shù)。使用這個(gè)函數(shù)就可以完成點(diǎn)陣任意大小的點(diǎn)陣字模的輸出。
接下來的問題就是如何在漢子庫中尋址某個(gè)漢子的點(diǎn)陣數(shù)據(jù)了。要解決這個(gè)問題,首先需要了解漢字在計(jì)算機(jī)中是如何表示的。在計(jì)算機(jī)中英文可以使用 ASCII 碼來表示,而漢字使用的是擴(kuò)展 ASCII 碼,并且使用兩個(gè)擴(kuò)展 ASCII 碼來表示一個(gè)漢字。一個(gè) ASCII 碼使用一個(gè)字節(jié)表示,所謂擴(kuò)展 ASCII 碼,也就是 ASCII 碼的最高位是1的 ASCII 碼,簡(jiǎn)單的說就是碼值大于等于 128 的 ASCII 碼。一個(gè)漢字由兩個(gè)擴(kuò)展 ASCII 碼組成,第一個(gè)擴(kuò)展 ASCII 碼用來存放區(qū)碼,第二個(gè)擴(kuò)展 ASCII 碼用來存放位碼。在 GB2312-80 標(biāo)準(zhǔn)中,將所有的漢字分為94個(gè)區(qū),每個(gè)區(qū)有94個(gè)位可以存放94個(gè)漢字,形成了人們常說的區(qū)位碼,這樣總共就有 94*94=8836 個(gè)漢字。在點(diǎn)陣字庫中,漢字點(diǎn)陣數(shù)據(jù)就是按照這個(gè)區(qū)位的順序來存放的,也就是最先存放的是第一個(gè)區(qū)的漢字點(diǎn)陣數(shù)據(jù),在每一個(gè)區(qū)中有是按照位的順序來存放 的。在漢字的內(nèi)碼中,漢字區(qū)位碼的存放實(shí)在擴(kuò)展 ASCII 基礎(chǔ)上存放的,并且將區(qū)碼和位碼都加上了32,然后存放在兩個(gè)擴(kuò)展 ASCII 碼中。具體的說就是:
第一個(gè)擴(kuò)展ASCII碼 = 128+32 + 漢字區(qū)碼
第二個(gè)擴(kuò)展ASCII嗎 = 128+32 + 漢字位碼
如果用char hz[2]來表示一個(gè)漢字,那么我可以計(jì)算出這個(gè)漢字的區(qū)位碼為:
區(qū)碼 = hz[0] - 128 - 32 = hz[0] - 160
位碼 = hz[1] - 128 - 32 = hz[1] - 160.
這樣,我們可以根據(jù)區(qū)位碼在文件中進(jìn)行殉職了,尋址公式如下:
漢字點(diǎn)陣數(shù)據(jù)在字庫文件中的偏移 = ((區(qū)碼-1) * 94 + 位碼) * 一個(gè)點(diǎn)陣字模占用的字節(jié)數(shù)
在尋址以后,即可讀取漢字的點(diǎn)陣數(shù)據(jù)到緩沖區(qū)進(jìn)行顯示了。以下是實(shí)現(xiàn)代碼:
/* 輸出一個(gè)漢字的函數(shù) */
void _draw_hz(char hz[2], FILE *fp, int x, int y, int w, int h, int color)
{
char fontbuf[128]; /* 足夠大的緩沖區(qū),也可以動(dòng)態(tài)分配 */
int ch0 = (BYTE)hz[0]-0xA0; /* 區(qū)碼 */
int ch1 = (BYTE)hz[1]-0xA0; /* 位碼 */
/* 計(jì)算偏移 */
long offset = (long)pf->_hz_buf_size * ((ch0 - 1) * 94 + ch1 - 1);
fseek(fp, offset, SEEK_SET); /* 進(jìn)行尋址 */
fread(fontbuf, 1, (w + 7) / 8 * h, fp); /* 讀入點(diǎn)陣數(shù)據(jù) */
_draw_model(fontbuf, w, h, x, y, color); /* 繪制字模 */
}
以上介紹完了中文點(diǎn)陣字庫的原理,當(dāng)然還有英文點(diǎn)陣字庫了。英文點(diǎn)陣字庫中單個(gè)點(diǎn)陣字模數(shù)據(jù)的存放方式與中文是一模一樣的,也就是對(duì)我們所寫的 _draw_model 函數(shù)同樣可以使用到英文字庫中。唯一不同的是對(duì)點(diǎn)陣字庫的尋址上。英文使用的就是 ASCII 碼,其碼值是0到127,尋址公式為:
英文點(diǎn)陣數(shù)據(jù)在英文點(diǎn)陣字庫中的偏移 = 英文的ASCII碼 * 一個(gè)英文字模占用的字節(jié)數(shù)
可以看到,區(qū)分中英文的關(guān)鍵就是,一個(gè)字符是 ASCII 碼還是擴(kuò)展 ASCII 碼,如果是 ASCII 碼,其范圍是0到127,這樣是使用的英文字庫,如果是擴(kuò)展 ASCII 碼,則與其后的另一個(gè)擴(kuò)展 ASCII 碼組成漢字內(nèi)碼,使用中文字庫進(jìn)行顯示。只要正確區(qū)分 ASCII 碼的類型并進(jìn)行分別的處理,也就能實(shí)現(xiàn)中英文字符串的混合輸出了。
點(diǎn)陣字庫和矢量字庫的差別
我們都只知道,各種字符在電腦屏幕上都是以一些點(diǎn)來表示的,因此也叫點(diǎn)陣。最早的字庫就是直接把這些點(diǎn)存儲(chǔ)起來,就是點(diǎn)陣字庫。常見的漢字點(diǎn)陣字庫有 16x16, 24x24 等。點(diǎn)陣字庫也有很多種,主要區(qū)別在于其中存儲(chǔ)編碼的方式不同。點(diǎn)陣字庫的最大缺點(diǎn)就是它是固定分辨率的,也就是每種字庫都有固定的大小尺寸,在原始尺寸下使用,效果很好,但如果將其放大或縮小使用,效果就很糟糕了,就會(huì)出現(xiàn)我們通常說的鋸齒現(xiàn)象。因?yàn)樾枰淖煮w大小組合有無數(shù)種,我們也不可能為每種大小都定義一個(gè)點(diǎn)陣字庫。于是就出現(xiàn)了矢量字庫。
矢量字庫
矢量字庫是把每個(gè)字符的筆劃分解成各種直線和曲線,然后記下這些直線和曲線的參數(shù),在顯示的時(shí)候,再根據(jù)具體的尺寸大小,畫出這些線條,就還原了原來的字符。它的好處就是可以隨意放大縮小而不失真。而且所需存儲(chǔ)量和字符大小無關(guān)。矢量字庫有很多種,區(qū)別在于他們采用的不同數(shù)學(xué)模型來描述組成字符的線條。常見的矢量字庫有 Type1字庫和Truetype字庫。
在點(diǎn)陣字庫中,每個(gè)字符由一個(gè)位圖表示,并把它用一個(gè)稱為字符掩膜的矩陣來表示,其中的每個(gè)元素都是一位二進(jìn)制數(shù),如果該位為1表示字符的筆畫經(jīng)過此位,該像素置為字符顏色;如果該位為0,表示字符的筆畫不經(jīng)過此位,該像素置為背景顏色。點(diǎn)陣字符的顯示分為兩步:首先從字庫中將它的位圖檢索出來,然后將檢索到的位圖寫到幀緩沖器中。
在實(shí)際應(yīng)用中,同一個(gè)字符有多種字體(如宋體、楷體等),每種字體又有多種大小型號(hào),因此字庫的存儲(chǔ)空間十分龐大。為了減少存儲(chǔ)空間,一般采用壓縮技術(shù)。
矢量字符記錄字符的筆畫信息而不是整個(gè)位圖,具有存儲(chǔ)空間小,美觀、變換方便等優(yōu)點(diǎn)。例如:在AutoCAD中使用圖形實(shí)體-形(Shape)-來定義矢量字符,其中,采用了直線和圓弧作為基本的筆畫來對(duì)矢量字符進(jìn)行描述。 對(duì)于字符的旋轉(zhuǎn)、放大、縮小等幾何變換,點(diǎn)陣字符需要對(duì)其位圖中的每個(gè)象素進(jìn)行變換,而矢量字符則只需要對(duì)其幾何圖素進(jìn)行變換就可以了,例如:對(duì)直線筆畫的兩個(gè)端點(diǎn)進(jìn)行變換,對(duì)圓弧的起點(diǎn)、終點(diǎn)、半徑和圓心進(jìn)行變換等等。
矢量字符的顯示也分為兩步。首先從字庫中將它的字符信息。然后取出端點(diǎn)坐標(biāo),對(duì)其進(jìn)行適當(dāng)?shù)膸缀巫儞Q,再根據(jù)各端點(diǎn)的標(biāo)志顯示出字符。
輪廓字形法是當(dāng)今國(guó)際上最流行的一種字符表示方法,其壓縮比大,且能保證字符質(zhì)量。輪廓字形法采用直線、B樣條/Bezier曲線的集合來描述一個(gè)字符的輪廓線。輪廓線構(gòu)成一個(gè)或若干個(gè)封閉的平面區(qū)域。輪廓線定義加上一些指示橫寬、豎寬、基點(diǎn)、基線等等控制信息就構(gòu)成了字符的壓縮數(shù)據(jù)。
如何使用Windows的系統(tǒng)字庫生成點(diǎn)陣字庫?
我的程序現(xiàn)在只能預(yù)覽一個(gè)漢字的不同字體的點(diǎn)陣表達(dá)。
界面很簡(jiǎn)單: 一個(gè)輸出點(diǎn)陣大小的選擇列表(8x8,16x16,24x24等),一個(gè)系統(tǒng)中已有的字體名稱列表,一個(gè)預(yù)覽按鈕,一塊畫圖顯示區(qū)域。
得到字體列表的方法:(作者稱這一段是用來取回系統(tǒng)的字體,然后添加到下拉框中)
//取字體名稱列表的回調(diào)函數(shù),使用前要聲明一下該方法
int CALLBACK MyEnumFontProc(ENUMLOGFONTEX* lpelf,NEWTEXTMETRICEX* lpntm,DWORD nFontType,long lParam)
{
CFontPeekerDlg* pWnd=(CFontPeekerDlg*) lParam;
if(pWnd)
{
if( pWnd->m_combo_sfont.FindString(0, lpelf->elfLogFont.lfFaceName) <0 )
pWnd->m_combo_sfont.AddString(lpelf->elfLogFont.lfFaceName);
return 1;
}
return 0;
}
//說明:CFontPeekerDlg 是我的dialog的類名, m_combo_sfont是列表名稱下拉combobox關(guān)聯(lián)的control變量
//調(diào)用的地方 (******問題1:下面那個(gè)&lf怎么得到呢……)
{
::EnumFontFamiliesEx((HDC) dc,&lf, (FONTENUMPROC)MyEnumFontProc,(LPARAM) this,0);
m_combo_sfont.SetCurSel(0);
}
字體預(yù)覽:
如果點(diǎn)陣大小選擇16,顯示的時(shí)候就畫出16x16個(gè)方格。自定義一個(gè)類CMyStatic繼承自CStatic,用來畫圖。在CMyStatic的OnPaint()函數(shù)中計(jì)算并顯示。
取得字體:
常用的方法:用CreateFont創(chuàng)建字體,把字TextOut再用GetPixel()取點(diǎn)存入數(shù)組。 缺點(diǎn):必須把字TextOut出來,能在屏幕上看見,不爽。
我的方法,用這個(gè)函數(shù):GetGlyphOutline(),可以得到一個(gè)字的輪廓矢量或者位圖。可以不用textout到屏幕,直接取得字模信息
函數(shù)原型如下:
DWORD GetGlyphOutline(
HDC hdc, //畫圖設(shè)備句柄
UINT uChar, //將要讀取的字符/漢字
UINT uFormat, //返回?cái)?shù)據(jù)的格式(字的外形輪廓還是字的位圖)
LPGLYPHMETRICS lpgm, // GLYPHMETRICS結(jié)構(gòu)地址,輸出參數(shù)
DWORD cbBuffer, //輸出數(shù)據(jù)緩沖區(qū)的大小
LPVOID lpvBuffer, //輸出數(shù)據(jù)緩沖區(qū)的地址
CONST MAT2 *lpmat2 //轉(zhuǎn)置矩陣的地址
);
說明:
uChar字符需要判斷是否是漢字還是英文字符。中文占2個(gè)字節(jié)長(zhǎng)度。
lpgm是輸出函數(shù),調(diào)用GetGlyphOutline()是無須給lpgm 賦值。
lpmat2如果不需要轉(zhuǎn)置,將 eM11.value=1; eM22.value=1; 即可。
cbBuffer緩沖區(qū)的大小,可以先通過調(diào)用GetGlyphOutline(……lpgm, 0, NULL, mat); 來取得,然后動(dòng)態(tài)分配lpvBuffer,再一次調(diào)用GetGlyphOutline,將信息存到lpvBuffer. 使用完畢后再釋放lpvBuffer.
程序示例:(***問題2:用這段程序,我獲取的字符點(diǎn)陣總都是一樣的,不管什么字……)
……前面部分省略……
GLYPHMETRICS glyph;
MAT2 m2;
memset(&m2, 0, sizeof(MAT2));
m2.eM11.value = 1;
m2.eM22.value = 1;
//取得buffer的大小
DWORD cbBuf = dc.GetGlyphOutline( nChar, GGO_BITMAP, &glyph, 0L, NULL, &m2);
BYTE* pBuf=NULL;
//返回GDI_ERROR表示失敗。
if( cbBuf != GDI_ERROR )
{
pBuf = new BYTE[cbBuf];
//輸出位圖GGO_BITMAP 的信息。輸出信息4字節(jié)(DWORD)對(duì)齊
dc.GetGlyphOutline( nChar, GGO_BITMAP, &glyph, cbBuf, pBuf, &m2);
}
else
{
if(m_pFont!=NULL)
delete m_pFont;
return;
}
編程中遇到問題:
一開始,GetGlyphOutline總是返回-1,getLastError顯示是"無法完成的功能",后來發(fā)現(xiàn)是因?yàn)檎{(diào)用之前沒有給hdc設(shè)置Font.
后來能取得pBuf信息后,又開始郁悶,因?yàn)椴惶靼譩itmap的結(jié)果是按什么排列的。后來跟蹤漢字"一"來調(diào)試(這個(gè)字簡(jiǎn)單),注意到了glyph.gmBlackBoxX 其實(shí)就是輸出位圖的寬度,glyph.gmBlackBoxY就是高度。如果gmBlackBoxX=15,glyph.gmBlackBoxY=2,表示輸出的pBuf中有這些信息:位圖有2行信息,每一行使用15 bit來存儲(chǔ)信息。
例如:我讀取"一":glyph.gmBlackBoxX = 0x0e,glyph.gmBlackBoxY=0x2; pBuf長(zhǎng)度cbBuf=8 字節(jié)
pBuf信息: 00 08 00 00 ff fc 00 00
字符寬度 0x0e=14 則 第一行信息為: 0000 0000 0000 100 (只取到前14位)
第二行根據(jù)4字節(jié)對(duì)齊的規(guī)則,從0xff開始 1111 1111 1111 110
看出"一"字了嗎?呵呵
直到他的存儲(chǔ)之后就可以動(dòng)手解析輸出的信息了。
我定義了一個(gè)宏#define BIT(n) (1《(n)) 用來比較每一個(gè)位信息時(shí)使用
后來又遇到了一個(gè)問題,就是小頭和大頭的問題了。在我的機(jī)器上是little endian的形式,如果我用
unsigned long *lptr = (unsigned long*)pBuf;
//j from 0 to 15
if( *lptr & BIT(j) )
{
//這時(shí)候如果想用j來表示寫1的位數(shù),就錯(cuò)了
}
因?yàn)閺淖止?jié)數(shù)組中轉(zhuǎn)化成unsigned long型的時(shí)候,數(shù)值已經(jīng)經(jīng)過轉(zhuǎn)化了,像上例中,實(shí)際上是0x0800 在同BIT(j)比較。
不多說了,比較之前轉(zhuǎn)化一下就可以了if( htonl(*lptr) & BIT(j) )
Unicode中文點(diǎn)陣字庫的生成與使用
點(diǎn)陣字庫包含兩部分信息。首先是點(diǎn)陣字庫文件頭信息,它包含點(diǎn)陣字庫文字的字號(hào)、多少位表示一個(gè)像素,英文字母與符號(hào)的size、起始和結(jié)束unicode編碼、在文件中的起始偏移,漢字的size、起始和結(jié)束unicode編碼、在文件中的起始偏移。然后是真實(shí)的點(diǎn)陣數(shù)據(jù),即一段段二進(jìn)制串,每一串表示一個(gè)字母、符號(hào)或漢字的點(diǎn)陣信息。
要生成點(diǎn)陣字庫必須有文字圖形的,我的方法是使用ttf字體。ttf字體的顯示采用的是SDL_ttf庫,這是開源圖形庫SDL的一個(gè)擴(kuò)展庫,它使用的是libfreetype以讀取和繪制ttf字體。
它提供了一個(gè)函數(shù),通過傳入一個(gè)Unicode編碼便能輸出相應(yīng)的文字的帶有alpha通道的位圖。那么我們可以掃描這個(gè)位圖以得到相應(yīng)文字的點(diǎn)陣信息。由于帶有alpha通道,我們可以在點(diǎn)陣信息中也加入權(quán)值,使得點(diǎn)陣字庫也有反走樣效果。我采用兩位來表示一個(gè)點(diǎn),這樣會(huì)有三級(jí)灰度(還有一個(gè)表示透明)。
點(diǎn)陣字庫的顯示首先需要將文件頭信息讀取出來,然后根據(jù)unicode編碼判斷在哪個(gè)區(qū)間內(nèi),然后用unicode編碼減去此區(qū)間的起始unicode編碼,算出相對(duì)偏移,并加上此區(qū)間的文件起始偏移得到文件的絕對(duì)偏移,然后讀出相應(yīng)位數(shù)的數(shù)據(jù),最后通過掃描這段二進(jìn)制串,在屏幕的相應(yīng)位置輸出點(diǎn)陣字型。
顯示點(diǎn)陣字體需要頻繁讀取文件,因此最好做一個(gè)固定大小的緩存,采用LRU置換算法維護(hù)此緩存,以減少磁盤讀取。
標(biāo)準(zhǔn)點(diǎn)陣字庫芯片
標(biāo)準(zhǔn)點(diǎn)陣字庫芯片的特點(diǎn):
1.內(nèi)涵全國(guó)信標(biāo)委授權(quán)的標(biāo)準(zhǔn)點(diǎn)陣字型數(shù)據(jù)、
2.支持國(guó)標(biāo)字符集GB2312(6,763漢字),GB18030(27,484漢字)。
3.支持多種點(diǎn)陣字型,包括11×12點(diǎn),15×16點(diǎn),24×24點(diǎn),32×32點(diǎn)。
4.免除了字庫燒錄和測(cè)試工序,并節(jié)省了2%以上的燒錄損耗。
5.價(jià)格相當(dāng)于空白FLASH價(jià)格
標(biāo)準(zhǔn)點(diǎn)陣字庫芯片的種類和應(yīng)用
標(biāo)準(zhǔn)點(diǎn)陣漢字字庫芯片
1 概述
GT23L24M1W是一款內(nèi)含24X24點(diǎn)陣的漢字庫芯片,支持GB18030國(guó)標(biāo)漢字(含有國(guó)家信標(biāo)委合法授權(quán))及ASCII字符,排列格式為橫置橫排,用戶通過字符內(nèi)碼,利用本手冊(cè)提供的方法計(jì)算出該字符點(diǎn)陣在芯片中的地址,可從該地址連續(xù)讀出字符點(diǎn)陣信息。
1.1 芯片特點(diǎn)
● 數(shù)據(jù)總線:
SPI 串行總線接口
PLII 精簡(jiǎn)地址并行總線接口
● 點(diǎn)陣排列方式:字節(jié)橫置橫排
● 訪問速度:
SPI 時(shí)鐘頻率:20MHz(max.)
PLII 訪問速度:130ns(max.)@3.3V
● 工作電壓:2.7V~3.6V
● 電流:
工作電流:12mA
待機(jī)電流:10uA
● 封裝:SO20W
● 尺寸(SO20W):12.80mmX10.30mm
● 工作溫度:-20℃~85℃(SPI 模式下);-10℃~85℃(PLII 模式下)
1.2 字庫內(nèi)容
字型樣張
2 引腳描述與接口連接
2.1 引腳名稱
2.2 SPI 接口引腳描述
串行數(shù)據(jù)輸出(SO):該信號(hào)用來把數(shù)據(jù)從芯片串行輸出,數(shù)據(jù)在時(shí)鐘的下降沿移出。
串行數(shù)據(jù)輸入(SI):該信號(hào)用來把數(shù)據(jù)從串行輸入芯片,數(shù)據(jù)在時(shí)鐘的上升沿移入。
串行時(shí)鐘輸入(SCLK):數(shù)據(jù)在時(shí)鐘上升沿移入,在下降沿移出。
片選輸入(CS#):所有串行數(shù)據(jù)傳輸開始于CE#下降沿,CE#在傳輸期間必須保持為低電平,在兩條
指令之間保持為高電平。
總線掛起輸入(HOLD#):
2.3 SPI 接口與主機(jī)接口電路示意圖
SPI 與主機(jī)接口電路連接可以參考下圖(#HOLD管腳建議接 2K 電阻 3.3V 拉高)。
若是采用系統(tǒng)電壓為 5V的,則需要進(jìn)行電平轉(zhuǎn)換匹配連接 GT23 芯片,可以參考下圖(#HOLD 管腳建議接 2K 電阻 3.3V 拉高)。
2.4 PLII 接口引腳描述
2.5 PLII 接口與主機(jī)接口電路示意圖
SPI/PLII_SEL(管腳內(nèi)部有 100K 上拉電阻)接地,字庫芯片選擇 PLII 接口模式,與主機(jī)接口電路連接可以參考下圖。
2.6 PLII 總線接口尋址說明
在 PLII 總線模式下,芯片內(nèi)部有 3個(gè)地址寄存器,主機(jī)需要把要讀取數(shù)據(jù)的地址寫入這 3個(gè)地址寄存器,然后再?gòu)臄?shù)據(jù)寄存器中讀出數(shù)據(jù)。主機(jī)每讀一次數(shù)據(jù)寄存器,芯片內(nèi)部的地址寄存器會(huì)自動(dòng)增一,從而使主機(jī)只寫一次首地址,就可以連續(xù)讀取數(shù)據(jù)。
3 字庫調(diào)用方法
3.1 漢字點(diǎn)陣排列格式
每個(gè)漢字在芯片中是以漢字點(diǎn)陣字模的形式存儲(chǔ)的,每個(gè)點(diǎn)用一個(gè)二進(jìn)制位表示,存 1的點(diǎn),當(dāng)顯示
時(shí)可以在屏幕上顯示亮點(diǎn),存 0的點(diǎn),則在屏幕上不顯示。點(diǎn)陣排列格式為橫置橫排:即一個(gè)字節(jié)的高位
表示左面的點(diǎn),低位表示右面的點(diǎn)(如果用戶按 word mode讀取點(diǎn)陣數(shù)據(jù),請(qǐng)注意高低字節(jié)的順序),排
滿一行的點(diǎn)后再排下一行。這樣把點(diǎn)陣信息用來直接在顯示器上按上述規(guī)則顯示,則將出現(xiàn)對(duì)應(yīng)的漢字。
3.1.1 24X24點(diǎn)漢字排列格式
24X24 點(diǎn)漢字的信息需要 72個(gè)字節(jié)(BYTE 0 – BYTE 71)來表示。該 24X24 點(diǎn)漢字的點(diǎn)陣數(shù)據(jù)是橫置橫排的,其具體排列結(jié)構(gòu)如下圖:
命名規(guī)則:
最大字符集及字?jǐn)?shù)
S:GB2312 6,763漢字
M:GB18030 27,484漢字
T:GB12345 6,866漢字
BIG5 5,401 / 13,060漢字
U:Unicode V3.0 27,484漢字
-
ASCII
+關(guān)注
關(guān)注
5文章
172瀏覽量
35024 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4290瀏覽量
62342 -
代碼
+關(guān)注
關(guān)注
30文章
4730瀏覽量
68259
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論