字模c语言,[C/C++]字模的解析(视频)
取模是個(gè)很有意思的事情。單片機(jī)開發(fā)會(huì)用到的取模,常常就是用來(lái)把漢字字模對(duì)應(yīng)的數(shù)組保存到單片機(jī)的flash之中,在顯示的時(shí)候進(jìn)行調(diào)用。而從字到字模之間的轉(zhuǎn)換,常常是通過(guò)一個(gè)“取模軟件”來(lái)實(shí)現(xiàn),根據(jù)輸入的文本,返回相應(yīng)的數(shù)組常量。
而這些字模(點(diǎn)陣字體)的數(shù)據(jù)是從哪里來(lái)的呢?似乎大多數(shù)來(lái)自于Dos時(shí)代,漢字點(diǎn)陣字體則來(lái)源于UCDOS,或是早期的WPS。在沒(méi)有圖形界面的年代,在終端上進(jìn)行字符的顯示,感覺(jué)就是在填充一個(gè)大點(diǎn)陣,這個(gè)大點(diǎn)陣的尺寸,就是屏幕的分辨率,感覺(jué)各個(gè)方位所對(duì)應(yīng)的字符,將其對(duì)應(yīng)的點(diǎn)陣字體“貼”上去。而在網(wǎng)上搜了半天,也就只是找到幾種點(diǎn)陣字體:
font name
width x height
unit length
ASC12
8 x 12
12
ASC16
8 x 16
16
ASC48
24 x 48
144
HZK12
12 x 12
24
HZK14
14 x 14
28
HZK16(宋簡(jiǎn)體)
16 x 16
32
HZK16F(宋繁體)
16 x 16
32
HZK16S(美術(shù)體)
16 x 16
32
HZK24F(仿宋體)
24 x 24
72
HZK24H(黑體)
24 x 24
72
HZK24K(楷體)
24 x 24
72
HZK24S(宋體)
24 x 24
72
HZK32
32 x 32
128
HZK40
40 x 40
200
HZK48
48 x 48
288
其中,ASC開頭的為半角字符,使用ASCII/ANSI編碼排序;HZK開頭的為全角字符,以GB2312編碼進(jìn)行排序。
在簡(jiǎn)體中文windows系統(tǒng)下,中文默認(rèn)的編碼為GBK/CP936,是GB2312/區(qū)位碼的擴(kuò)展。文中提到的字庫(kù)因?yàn)槟甏眠h(yuǎn),所以也都是采用最早的GB2312編碼,算是現(xiàn)在GBK編碼的子集,所以在windows平臺(tái)上的中文,默認(rèn)都是以雙字節(jié)的編碼出現(xiàn)。
而在linux類平臺(tái)下,以u(píng)buntu為例,即便是簡(jiǎn)體中文的語(yǔ)言版本,都使用UTF-8編碼進(jìn)行表達(dá),一般情況下,中文字符采用3個(gè)字節(jié)進(jìn)行表示,是對(duì)unicode編碼的再次轉(zhuǎn)換。這也就是造成windows平臺(tái)的文本文件/音樂(lè)文件的tag,在linux系統(tǒng)下會(huì)出現(xiàn)亂碼的根本原因。因?yàn)槠湮谋揪庉嬈髂J(rèn)都采用UTF-8編碼對(duì)其進(jìn)行解碼。解決方法無(wú)非兩種,一種給linux系統(tǒng)添加GBK字符集,另一種就是轉(zhuǎn)換被解碼對(duì)象的編碼方式。從我個(gè)人的角度出發(fā),更傾向于后者,一方面,我不希望一個(gè)系統(tǒng)里面出現(xiàn)過(guò)多的編碼方式,要確定新建文本其唯一的編碼方式;另一方面,UTF-8本來(lái)就是通用的編碼方式,我們的數(shù)據(jù)庫(kù)、網(wǎng)頁(yè),大多數(shù)都采用標(biāo)準(zhǔn)更為統(tǒng)一的UTF-8編碼進(jìn)行表達(dá)。相信Mac平臺(tái)的中文字符集也是UTF-8。unicode 網(wǎng)羅的世上幾乎所有的字符,其中中文編碼規(guī)則部分和GB2312也沒(méi)有什么直接的換算關(guān)系,完全就是兩套系統(tǒng)。
轉(zhuǎn)碼的工具有很多,畢竟隨著計(jì)算機(jī)國(guó)際化的發(fā)展,這個(gè)問(wèn)題在很早的時(shí)候就出現(xiàn)了。在程序開發(fā)的過(guò)程中,C語(yǔ)言的話可以使用 iconv 庫(kù)(這是一個(gè)標(biāo)準(zhǔn)庫(kù))進(jìn)行轉(zhuǎn)碼。在ruby中,String 類可以直接通過(guò) encoding 方法進(jìn)行轉(zhuǎn)碼。
而其實(shí)需要轉(zhuǎn)碼的,只是中文部分而已,相信在絕大多數(shù)的編碼中,半角英文的部分都是重合的。所以為了保險(xiǎn)起見,請(qǐng)盡量將您的電腦系統(tǒng)的文件名、卷標(biāo)使用英文命名,這樣不管是系統(tǒng)恢復(fù),或是使用其它系統(tǒng)打開的時(shí)候都能正確顯示,而且這樣在終端/命令行中操作也更簡(jiǎn)單,不用老是切換輸入法,tab補(bǔ)全也更快速。
繼續(xù)說(shuō)點(diǎn)陣字庫(kù),在BitmapFont項(xiàng)目中的點(diǎn)陣字庫(kù)文件,部分進(jìn)行了一定調(diào)整,偏移量是統(tǒng)一設(shè)置為0。這些字庫(kù)的原始文件并不是這樣,相信可能是為了節(jié)省空間的考慮,畢竟在這些文件誕生之初,存儲(chǔ)的成本還是比較高。那些本來(lái)就沒(méi)法顯示的字符,比方說(shuō)’\n’換行、’\r’回車都沒(méi)有什么東西好顯示,我對(duì)其缺少的部分用0x00進(jìn)行填充。畢竟現(xiàn)在Arduino都開始用SD卡來(lái)進(jìn)行存儲(chǔ)了,存儲(chǔ)這樣幾k的字庫(kù)文件,根本不在話下。而在原始字庫(kù)文件中,哪怕本身偏移量就是0,它也不是老老實(shí)實(shí)地用0填充,也又不少自定義的字體在里面。比方說(shuō)下圖中的“馬”,出現(xiàn)在一系列象棋的棋子字模中,根據(jù)其字模位置推算出的GB2312編碼中,并沒(méi)有對(duì)應(yīng)的字符。
所以的字庫(kù)中,字體都根據(jù)其編碼順序依次排列,每 unit_length(單位模長(zhǎng)) 個(gè)字節(jié)為一個(gè)單位。而這 unit_length 個(gè)字節(jié)正好可以排列出一個(gè)點(diǎn)陣字體。
unit_length * index = position
單位模長(zhǎng) * 序列號(hào) = 文件位置
在ASC系列字庫(kù)中,序列號(hào) index 就等于其 ASCII 編碼,范圍是 0x00-0x7f
在HZK系列字庫(kù)中,序列號(hào) index 中,設(shè)其 GB2312 編碼為HL,即區(qū)碼位為H,位碼為L(zhǎng),則 index = 94 * (H – 0xa1) + (L – 0xa1)
因?yàn)榘凑誋ZK編碼規(guī)則,每個(gè)字符使用2個(gè)字節(jié)表示,高字節(jié)H表示區(qū)碼,低字節(jié)L標(biāo)志位碼,區(qū)碼和位碼都從0xa1開始計(jì)數(shù)直至0xfe,當(dāng) index 為 0 時(shí),GB2312 編碼 等于 0xa1a1。
根據(jù)這樣的規(guī)則,當(dāng)?shù)弥址?index,就可以計(jì)算出其在文件中的地址,通過(guò)對(duì)文件的隨機(jī)讀取(區(qū)別于順序讀取),就可以很容易的把“模”給“取”出來(lái)。
視頻中,演示的串口發(fā)送中文并在液晶屏上顯示,大概就是這樣的原理。因?yàn)槟J(rèn)發(fā)送的是UTF-8編碼,無(wú)法對(duì)應(yīng)字模的GB2312編碼,所以在上位機(jī)腳本內(nèi)部,將其轉(zhuǎn)化為了GB2312編碼,再進(jìn)行串口發(fā)送。而Arduino下位機(jī)根據(jù),接收到的 GB2312 編碼,計(jì)算相應(yīng)字模在字庫(kù)文件中的位置,打開SD卡上存儲(chǔ)的字庫(kù)文件,找到相應(yīng)位置,讀取對(duì)應(yīng)單位模長(zhǎng)的數(shù)個(gè)字節(jié),并打印到液晶屏上,倒也不是很復(fù)雜。因?yàn)?Arduino 有強(qiáng)大的SD庫(kù),配合我自己的dot-matrix庫(kù)來(lái)驅(qū)動(dòng)液晶屏,所以實(shí)現(xiàn)起來(lái)就很簡(jiǎn)單啦。腳本之所以用 ruby 來(lái)寫,還是因?yàn)槠洳僮鞔诜浅:?jiǎn)單。
這里可以發(fā)現(xiàn)一點(diǎn),就是在一個(gè)中英文混雜的 ASCII 文件中,英文的字節(jié)肯定是小于0x7f(該字節(jié)最高位為0),而中文的兩個(gè)字節(jié)都必然大于0x80(字節(jié)最高位為1),所以在這樣的字節(jié)流里面,依然可以很容易就區(qū)分出哪些是英文半角字符,那些中文全角字符。UTF-8的編碼方式也是使用類似的方法進(jìn)行解碼。
介紹一下 BitmapFont 程序,這是我用 GNU C++,建立的一個(gè)很小的 Makefile 命令行工程。其作用是將收集到的點(diǎn)陣字庫(kù)文件,以hex代碼的方式,重新生成一個(gè)UTF-8編碼的大文本,如果只是需要在程序flash中預(yù)存少量字模,則可以將其中字節(jié)代碼部分直接復(fù)制到程序中。區(qū)別與一般“取摸軟件”,我把所有字模都放在文本中,通過(guò)文本編輯期自帶的查找工具進(jìn)行檢索。現(xiàn)在的文本編輯器,掃描一個(gè)幾十M的純文本,想必也應(yīng)該是很快的。程序中還有一個(gè)HackFont 程序,對(duì)整個(gè)字庫(kù)文件進(jìn)行,翻轉(zhuǎn)、平移、取反等操作以生存新的字庫(kù)文件,因?yàn)橹贿m用于方形的字體,所以在此就不再展開。
如果大家對(duì)程序沒(méi)什么興趣,就想直接看到字庫(kù)以及生成的大文本的話,可以直接下載 output.7z。
視頻演示:
視頻中出現(xiàn)的,串口返回的 Arduino 程序
void setup()
{
Serial.begin(9600);
}
void loop()
{
}
void serialEvent()
{
char s[5];
while (Serial.available())
{
byte inChar = (byte)Serial.read();
// Serial.write(inChar);
sprintf(s, "0x%02x", inChar);
Serial.write(s);
Serial.println();
}
}
推薦一些編輯器:
vi/vim,牛逼之選。
SCITE,跨平臺(tái)輕量級(jí)文本編輯器,切換編碼方式很方便。
總結(jié)
以上是生活随笔為你收集整理的字模c语言,[C/C++]字模的解析(视频)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java初学者也可以实现的图书系统小练习
- 下一篇: C++-STL--吐泡泡