字模c语言,[C/C++]字模的解析(视频)
取模是個很有意思的事情。單片機開發會用到的取模,常常就是用來把漢字字模對應的數組保存到單片機的flash之中,在顯示的時候進行調用。而從字到字模之間的轉換,常常是通過一個“取模軟件”來實現,根據輸入的文本,返回相應的數組常量。
而這些字模(點陣字體)的數據是從哪里來的呢?似乎大多數來自于Dos時代,漢字點陣字體則來源于UCDOS,或是早期的WPS。在沒有圖形界面的年代,在終端上進行字符的顯示,感覺就是在填充一個大點陣,這個大點陣的尺寸,就是屏幕的分辨率,感覺各個方位所對應的字符,將其對應的點陣字體“貼”上去。而在網上搜了半天,也就只是找到幾種點陣字體:
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(宋簡體)
16 x 16
32
HZK16F(宋繁體)
16 x 16
32
HZK16S(美術體)
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編碼進行排序。
在簡體中文windows系統下,中文默認的編碼為GBK/CP936,是GB2312/區位碼的擴展。文中提到的字庫因為年代久遠,所以也都是采用最早的GB2312編碼,算是現在GBK編碼的子集,所以在windows平臺上的中文,默認都是以雙字節的編碼出現。
而在linux類平臺下,以ubuntu為例,即便是簡體中文的語言版本,都使用UTF-8編碼進行表達,一般情況下,中文字符采用3個字節進行表示,是對unicode編碼的再次轉換。這也就是造成windows平臺的文本文件/音樂文件的tag,在linux系統下會出現亂碼的根本原因。因為其文本編輯器默認都采用UTF-8編碼對其進行解碼。解決方法無非兩種,一種給linux系統添加GBK字符集,另一種就是轉換被解碼對象的編碼方式。從我個人的角度出發,更傾向于后者,一方面,我不希望一個系統里面出現過多的編碼方式,要確定新建文本其唯一的編碼方式;另一方面,UTF-8本來就是通用的編碼方式,我們的數據庫、網頁,大多數都采用標準更為統一的UTF-8編碼進行表達。相信Mac平臺的中文字符集也是UTF-8。unicode 網羅的世上幾乎所有的字符,其中中文編碼規則部分和GB2312也沒有什么直接的換算關系,完全就是兩套系統。
轉碼的工具有很多,畢竟隨著計算機國際化的發展,這個問題在很早的時候就出現了。在程序開發的過程中,C語言的話可以使用 iconv 庫(這是一個標準庫)進行轉碼。在ruby中,String 類可以直接通過 encoding 方法進行轉碼。
而其實需要轉碼的,只是中文部分而已,相信在絕大多數的編碼中,半角英文的部分都是重合的。所以為了保險起見,請盡量將您的電腦系統的文件名、卷標使用英文命名,這樣不管是系統恢復,或是使用其它系統打開的時候都能正確顯示,而且這樣在終端/命令行中操作也更簡單,不用老是切換輸入法,tab補全也更快速。
繼續說點陣字庫,在BitmapFont項目中的點陣字庫文件,部分進行了一定調整,偏移量是統一設置為0。這些字庫的原始文件并不是這樣,相信可能是為了節省空間的考慮,畢竟在這些文件誕生之初,存儲的成本還是比較高。那些本來就沒法顯示的字符,比方說’\n’換行、’\r’回車都沒有什么東西好顯示,我對其缺少的部分用0x00進行填充。畢竟現在Arduino都開始用SD卡來進行存儲了,存儲這樣幾k的字庫文件,根本不在話下。而在原始字庫文件中,哪怕本身偏移量就是0,它也不是老老實實地用0填充,也又不少自定義的字體在里面。比方說下圖中的“馬”,出現在一系列象棋的棋子字模中,根據其字模位置推算出的GB2312編碼中,并沒有對應的字符。
所以的字庫中,字體都根據其編碼順序依次排列,每 unit_length(單位模長) 個字節為一個單位。而這 unit_length 個字節正好可以排列出一個點陣字體。
unit_length * index = position
單位模長 * 序列號 = 文件位置
在ASC系列字庫中,序列號 index 就等于其 ASCII 編碼,范圍是 0x00-0x7f
在HZK系列字庫中,序列號 index 中,設其 GB2312 編碼為HL,即區碼位為H,位碼為L,則 index = 94 * (H – 0xa1) + (L – 0xa1)
因為按照HZK編碼規則,每個字符使用2個字節表示,高字節H表示區碼,低字節L標志位碼,區碼和位碼都從0xa1開始計數直至0xfe,當 index 為 0 時,GB2312 編碼 等于 0xa1a1。
根據這樣的規則,當得知字符的 index,就可以計算出其在文件中的地址,通過對文件的隨機讀取(區別于順序讀取),就可以很容易的把“模”給“取”出來。
視頻中,演示的串口發送中文并在液晶屏上顯示,大概就是這樣的原理。因為默認發送的是UTF-8編碼,無法對應字模的GB2312編碼,所以在上位機腳本內部,將其轉化為了GB2312編碼,再進行串口發送。而Arduino下位機根據,接收到的 GB2312 編碼,計算相應字模在字庫文件中的位置,打開SD卡上存儲的字庫文件,找到相應位置,讀取對應單位模長的數個字節,并打印到液晶屏上,倒也不是很復雜。因為 Arduino 有強大的SD庫,配合我自己的dot-matrix庫來驅動液晶屏,所以實現起來就很簡單啦。腳本之所以用 ruby 來寫,還是因為其操作串口非常簡單。
這里可以發現一點,就是在一個中英文混雜的 ASCII 文件中,英文的字節肯定是小于0x7f(該字節最高位為0),而中文的兩個字節都必然大于0x80(字節最高位為1),所以在這樣的字節流里面,依然可以很容易就區分出哪些是英文半角字符,那些中文全角字符。UTF-8的編碼方式也是使用類似的方法進行解碼。
介紹一下 BitmapFont 程序,這是我用 GNU C++,建立的一個很小的 Makefile 命令行工程。其作用是將收集到的點陣字庫文件,以hex代碼的方式,重新生成一個UTF-8編碼的大文本,如果只是需要在程序flash中預存少量字模,則可以將其中字節代碼部分直接復制到程序中。區別與一般“取摸軟件”,我把所有字模都放在文本中,通過文本編輯期自帶的查找工具進行檢索。現在的文本編輯器,掃描一個幾十M的純文本,想必也應該是很快的。程序中還有一個HackFont 程序,對整個字庫文件進行,翻轉、平移、取反等操作以生存新的字庫文件,因為只適用于方形的字體,所以在此就不再展開。
如果大家對程序沒什么興趣,就想直接看到字庫以及生成的大文本的話,可以直接下載 output.7z。
視頻演示:
視頻中出現的,串口返回的 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,跨平臺輕量級文本編輯器,切換編碼方式很方便。
總結
以上是生活随笔為你收集整理的字模c语言,[C/C++]字模的解析(视频)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java初学者也可以实现的图书系统小练习
- 下一篇: 汉字库,字模的了解