UTF8 To BIG5 + bmfont

BMF.C 程序說明文件

程式概述

本程式 bmf.c 是一個專門用於處理 Unicode(UTF-8)字串與 Big5 編碼之間轉換的 C 語言程式,同時具備從 Big5 編碼查詢對應點陣字體資料的功能。程式的核心設計目標是為了嵌入式系統或點陣顯示裝置(如 LCD、OLED 螢幕)提供中文字型的顯示支援。程式透過二分搜尋演算法高效地查詢 Unicode 到 Big5 的映射關係,並根據 Big5 編碼的特定區塊結構計算字型資料在字庫陣列中的偏移位置,最終輸出符合特定尺寸規格的點陣資料。

程式的設計採用了模組化架構,將字元編碼轉換與字型資料獲取分離,使得各個函式可以獨立重用。轉換流程從 UTF-8 字串出發,首先解析出每個 Unicode 碼點(codepoint),接著查詢對應的 Big5 編碼,最後根據 Big5 編碼的區塊分類從預先定義的字庫中提取點陣資料。這種設計方式不僅提高了轉換效率,也使得程式碼結構清晰易於維護。

依賴與編譯需求

本程式的運作依賴於兩個外部標頭檔案,這些檔案必須與 bmf.c 放置在同一專案目錄下或正確配置包含路徑。lili/big5_sort_table.h 檔案包含名為 mapping 的結構陣列,該陣列儲存了 Unicode 與 Big5 編碼之間的對應關係,每個元素為 Big5Mapping 結構,內含 unicodebig5 兩個欄位。lili/bmFont.h 檔案則包含各種字型資料陣列,如 spcFont(特殊符號區)、spcFsupp(擴充符號區)、stdFont(常用字區)以及 ascFont(ASCII 字元區),這些陣列以連續記憶體的方式儲存點陣字型的位元資料。

編譯本程式時,需要確保編譯器支援 C99 標準或更新版本,因為程式使用了如 uint32_tsize_t 等標準類型定義,以及指定陣列大小的初始化方式。編譯指令範例如下:

gcc -std=c99 -o bmf bmf.c

執行編譯後產生的可執行檔案,即可測試程式功能。若編譯過程中出現找不到標頭檔案的錯誤,請檢查 lili 目錄是否存在於專案根目錄,或透過 -I 參數指定額外的包含路徑。

函式詳細說明

比較函式(cmp_mapping)

cmp_mapping 函式專門設計作為二分搜尋(bsearch)的比較回呼函式,其功能是比較兩個 Big5Mapping 結構的 unicode 欄位大小。函式接收兩個指向常數的指標作為參數,分別代表搜尋鍵與陣列元素。實作方式採用了現代 C 語言的簡潔寫法,透過 ((ua > ub) - (ua < ub)) 的運算式直接返回 -1、0 或 1 作為比較結果,這種寫法不僅程式碼精簡,且經過編譯器最佳化後效率與傳統的 if-else 寫法相當。

該函式的設計遵循了標準庫函式對比較函式的慣例要求,確保與 bsearch 配合使用時能夠正確執行二分搜尋演算法。在實際應用中,由於映射表通常包含數萬筆資料,二分搜尋的時間複雜度為 O(log N),能夠在毫秒等級的時間內完成查詢,這對於需要即時轉換字元的顯示系統而言至關重要。

Unicode 到 Big5 查表函式(lookup_big5)

lookup_big5 函式是整個轉換流程的核心樞紐,負責將輸入的 Unicode 碼點轉換為對應的 Big5 編碼。函式首先對 ASCII 範圍(0x00-0x7F)進行快速處理,因為這些字元在兩種編碼中表示方式相同,可直接返回原值。對於 ASCII 範圍外的字元,函式會構造一個搜尋鍵結構,並呼叫標準庫的 bsearch 函式在預先排序好的映射表中進行二分搜尋。

搜尋成功時,函式返回映射表中對應的 Big5 編碼;若搜尋失敗,則返回預設值 0xA1BC,該值對應 Big5 編碼中的全形空格或方塊字元,用於表示無法轉換的不明字元。這種容錯設計確保了即使遇到映射表中未收錄的罕用字,程式仍能維持運作而不會崩潰。值得注意的是,映射表 mapping 的大小由 mapping_size 變數定義,該變數應在 lili/big5_sort_table.h 中正確定義。

UTF-8 解析函式(next_utf8_codepoint)

next_utf8_codepoint 函式專門用於解析 UTF-8 編碼字串中的下一個 Unicode 碼點。函式接收兩個指標參數:第一個是指向字元指標的指標(用於更新解析位置),第二個是字串結束位置的指標(用於邊界檢查)。解析邏輯依據 UTF-8 編碼的位元模式規律,支援 1-byte 到 4-byte 的各種編碼長度。

對於 1-byte 情況(ASCII 字元),直接返回該位元組的值。對於 2-byte 到 4-byte 的情況,函式會驗證位元組序列的合法性,檢查各個位元組是否符合 UTF-8 的前綴模式(如 110xxxxx 表示 2-byte),並在確認序列完整且有效後,透過位元運算重組各個位元組中的有效資料位元,形成完整的 21-bit Unicode 碼點。若遇到無效的 UTF-8 序列(如預期長度不足或格式錯誤),函式會跳過第一個位元組並返回 Unicode 替換字元(U+FFFD,0xFFFD),這是 UTF-8 標準規定的標準處理方式。

UTF-8 轉 Big5 轉換函式(utf8_to_big5)

utf8_to_big5 函式作為高階轉換介面,將輸入的 UTF-8 字串批量轉換為 Big5 編碼陣列。函式參數包括輸入字串指標、要處理的位元組數量上限、輸出緩衝區指標以及輸出緩衝區可容納的元素數量。這種設計允許呼叫者控制記憶體配置,避免緩衝區溢出的風險。

轉換過程中,函式會持續呼叫 next_utf8_codepoint 解析下一個碼點,並將解析結果傳遞給 lookup_big5 取得對應的 Big5 編碼。轉換會在以下任一條件發生時停止:輸入字串結束、遇到空字元、達到輸出緩衝區容量上限,或解析到無效的 UTF-8 序列(碼點為 0)。函式最終返回成功轉換的字元數量,呼叫者可以依此判斷轉換是否完整完成。

字型資料獲取函式(GetBmfontBuf)

GetBmfontBuf 函式是程式中最為複雜的部分,負責根據 Big5 編碼計算並提取對應的點陣字型資料。函式的核心邏輯是基於 Big5 編碼的區塊結構特性:Big5 編碼由高位元組(Hi Byte)和低位元組(Low Byte)組成,高位元組範圍通常為 0x81-0xFE,但標準字庫從 0xA1 開始;低位元組則分為兩個區段,分別是 0x40-0x7E(63 個字元)和 0xA1-0xFE(94 個字元),每個高位元組對應的區塊共計 157 個字元。

函式首先根據輸入的 Big5 編碼值判斷其所屬區塊:區塊一(0xA140-0xA3BF)對應特殊符號區,使用 spcFont 字庫;區塊二(0xC6A1-0xC8D3)對應擴充符號區,使用 spcFsupp 字庫;區塊三(0xA440-0xC67E 和 0xC940-0xF9FE)對應常用字和次常用字區,使用 stdFont 字庫;其他情況則處理為 ASCII 字元。

確定區塊後,函式會計算字元在字庫陣列中的線性偏移位置。計算方式首先將高位元組減去該區塊的起始值(如 0xA1、0xC6、0xA4 等),乘以頁大小(157),再加上低位元組在該頁中的索引位置。低位元組索引的計算需要區分兩個子區段,因為 0x40-0x7E 和 0xA1-0xFE 在連續陣列中是連續排列的。最終偏移量乘以每個字元的位元組大小(FONT_SIZE_FULL = 72,表示 24x24 點的圖像),得到精確的記憶體偏移地址。函式最後使用 memcpy 直接複製字型資料到輸出緩衝區,避免了逐位元組複製的低效率問題。

點陣顯示函式(PrintbmFont 與 PrintbmFontAsc)

PrintbmFontPrintbmFontAsc 函式用於在文字終端機上以視覺化方式顯示點陣字型資料。這兩個函式主要作為除錯和測試用途,但在某些嵌入式環境中也可直接用於字型驗證。PrintbmFont 處理全形字元,採用 24x24 的點矩陣佈局,每列使用 3 個位元組(24 位元);PrintbmFontAsc 處理半形 ASCII 字元,採用 16x24 的點矩陣佈局,每列使用 2 個位元組(16 位元)。

兩個函式的實作邏輯相似:首先遍歷字型緩衝區的每一列,讀取每個位元組後再逐一檢查其 8 個位元。若某一位元為 1,則在終端機輸出 "##" 兩個井字元號;若為 0,則輸出兩個空白。這種表示方式使得字型的輪廓在終端機上清晰可見。輸出時每列結束會換行,每個字元顯示完畢會輸出分隔線以便於區分相鄰字元。

應用場景與方向

本程式最直接的應用場景是嵌入式系統中的中文字型顯示。許多嵌入式裝置(如工業控制器、智慧型家電、儀器儀表等)需要顯示使用者介面資訊,而傳統的點陣顯示器(如 128x64 OLED、LCD 模組)儲存空間有限,無法預載完整的中文字型圖庫。本程式提供的轉換機制允許嵌入式系統僅儲存必要的 Big5 字型資料,並在需要顯示時即時從 UTF-8 輸入轉換為點陣格式,這種「隨需載入」的方式大幅降低了記憶體需求。

另一個重要的應用方向是字型轉換工具的開發。開發者可以基於本程式的核心函式(utf8_to_big5GetBmfontBuf),建構批量字型轉換工具,將文字檔案或字串轉換為特定格式的點陣資料陣列,用於預先燒錄到顯示器的快閃記憶體中。此外,,程式的架構也具有良好的擴充性,若要支援其他字型尺寸(如 16x16、32x32)或編碼格式(如 GB2312、GBK),僅需修改相關的常數定義和字庫包含,核心轉換邏輯可以保持不變。

在文字處理領域,本程式可作為編碼轉換的基礎元件。例如,需要將 UTF-8 編碼的使用者輸入轉換為 Big5 編碼以相容傳統系統的場景,或需要從 Big5 編碼的資料檔案中提取可讀文字並統一為 UTF-8 編碼的場景,都可以利用本程式的查表機制實現。

程式使用範例

以下範例展示如何使用本程式的主要功能。此範例已包含在程式的 main 函式中,編譯執行後可觀察輸出結果。

#include <stdio.h>
#include <string.h>

// 假設相關標頭檔案已正確包含
extern uint16_t lookup_big5(uint32_t unicode);
extern size_t utf8_to_big5(const char* utf8_str, size_t max_utf8_bytes,
    uint16_t* out_buf, size_t out_buf_size);
extern void GetBmfontBuf(uint16_t big5, uint8_t* buf);
extern void PrintbmFont(uint8_t* buf);
extern void PrintbmFontAsc(uint8_t* buf);

#define FONT_SIZE_FULL 72

int main(void) {
    const char* text = "乂幹測試Abc!";
    uint16_t big5_buf[256] = { 0 }; 
    uint8_t bmBuf[FONT_SIZE_FULL] = { 0 };

    // UTF-8 轉 Big5
    size_t count = utf8_to_big5(text, strlen(text), big5_buf, 256);

    printf("原字串: %s\n", text);
    printf("轉換個數: %zu\n", count);
    printf("Big5 Codes: ");
    for (size_t i = 0; i < count; i++) {
        printf("%04X ", big5_buf[i]);
    }
    printf("\n\n");

    // 取得並印出點陣字
    for (size_t i = 0; i < count; i++) {
        memset(bmBuf, 0, sizeof(bmBuf));
        GetBmfontBuf(big5_buf[i], bmBuf);
      
        printf("Char Code: 0x%04X\n", big5_buf[i]);
        if (big5_buf[i] < 0x80) {
            PrintbmFontAsc(bmBuf);
        } else {
            PrintbmFont(bmBuf);
        }
        printf("----------------------\n");
    }

    return 0;
}

執行上述範例程式,輸出將包含原始 UTF-8 字串、每個字元對應的 Big5 編碼值,以及每個字元在終端機上的點陣視覺化呈現。開發者可以透過修改 text 變數的值測試不同的字元組合,驗證轉換邏輯的正確性。

技術特性與限制

本程式在設計上具有以下技術特性值得注意。首先,程式完全基於標準 C 函式庫實作,不依賴任何特定平台的功能,因此具有良好的可攜性,可在 Windows、Linux、macOS 等各種作業系統上編譯執行。其次,核心轉換函式均經過記憶體安全的設計,所有指標參數在進入函式後都會進行有效性檢查,避免空指標存取導致的程式崩潰。

然而,程式也存在若干限制需要注意。目前程式僅支援 Big5 編碼標準中定義的常用字元區塊,對於某些罕用字元或擴充字元(如 Big5-2003 的新增字元)可能無法正確處理。此外,程式的字型資料來源假設為 lili/bmFont.h 中定義的特定格式(24x24 全形、16x24 半形),若實際使用的字型尺寸不同,需要相應調整 #define 巨集定義和 GetBmfontBuf 函式中的計算邏輯。

另一個潛在的限制是記憶體使用量。lili/big5_sort_table.h 中的映射表可能佔用數百 KB 的記憶體,對於極度記憶體受限的嵌入式系統,可能需要考慮使用更精簡的映射方式(如雜湊表或字典樹)。在這種情況下,可以保留 utf8_to_big5next_utf8_codepoint 函式作為輸入解析層,僅替換 lookup_big5 的實作方式。

未來擴展方向

基於本程式的現有架構,以下擴展方向可作為未來開發的參考。第一,可擴充編碼支援,透過新增對 GB2312、GBK、Shift-JIS 等東亞編碼的轉換邏輯,使程式能夠處理更多語言的文字。第二,可實作字型快取機制,對於重複出現的字元保存已查詢的點陣資料,避免重複的記憶體複製操作,提升顯示更新效率。第三,可增加字型尺寸的動態支援,允許在執行階段指定輸出點陣的解析度,透過上採樣或下採樣的方式調整字型大小。第四,可與圖形庫整合,如將輸出改為Framebuffer格式或直接寫入顯示驅動程式,使其能夠直接控制實際的顯示硬體。

源碼在這裏