嵌入式開發中,需將漢字字模燒錄至 EPROM 或在無字庫的 LCD/LED 屏顯示。Windows 提供矢量字體 (TrueType),需在運行時渲染為指定尺寸的點陣矩陣 (每像素 1 bit),並按「行優先、高位在前」順序導出為 C 數組或二進制文件。
function ConvertToMatrix(Text: PChar; ChrWidth, ChrHeight: Byte; SaveFileName: PChar): Boolean;
// Text: 單個漢字 (2 字節),ChrWidth: 字符寬度(點陣列數),實際漢字寬度 = ChrWidth*2
// ChrHeight: 字符高度(點陣行數),SaveFileName: 輸出文件路徑
TBitmap 設置 PixelFormat := pf8bit (256 色),寬高按參數設定。CreateFont 指定高度、寬度 (ChrWidth)、字符集 GB2312_CHARSET、字體名 'script' (系統默認中文字體)。SelectObject(DC, Font) → TextOut(DC, 0, 0, Text, Len)。GetObject → GetDIBits 將位圖像素數據讀入內存緩衝區 (lpvSBits),像素值 0=黑(前景),非 0=白(背景)。Word (16 bit),高位對應左側像素。黑(0)→bit=1,白(非0)→bit=0。不足 16 位高位補 0。TMemoryStream.Write(Word, 2) 循環寫入,最後 SaveToFile。function ConvertToMatrix(Text: PChar; ChrWidth, ChrHeight: Byte; SaveFileName: PChar): Bool;
type PBITMAPINFO = ^TBitmapInfo;
var
TempBmp: TBitmap;
lpvSBits, lpvDBits: PChar;
dOffset, sOffset: Integer;
DC: HDC;
TheFont: HFont;
BMIInfo: PBITMAPINFO;
DS: TDIBSection;
BMIbuf: array[0..2047] of Byte;
i, j: Integer;
wData: Word;
MemoryStream: TMemoryStream;
begin
if (Length(Text) > 2) or (ChrWidth = 0) or (ChrHeight = 0) or (SaveFileName = '') then
begin ShowMessage('參數錯誤:請傳入單個漢字及有效尺寸/文件名'); Result := False; Exit; end;
MemoryStream := TMemoryStream.Create;
TempBmp := TBitmap.Create;
try
TempBmp.PixelFormat := pf8bit;
TempBmp.Width := ChrWidth * Length(Text); // 漢字佔 2 字符寬
TempBmp.Height := ChrHeight;
DC := TempBmp.Canvas.Handle;
TheFont := CreateFont(ChrHeight, ChrWidth, 0, 0, 400, 0, 0, 0,
GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH or FF_DONTCARE, 'System'); // 'script' 在某些系統不可用,改用 'System' 或 'SimSun'
SelectObject(DC, TheFont);
SetBkColor(DC, clWhite); SetTextColor(DC, clBlack); // 確保黑字白底
TextOut(DC, 0, 0, Text, Length(Text));
DeleteObject(TheFont);
BMIInfo := PBITMAPINFO(@BMIbuf);
lpvSBits := AllocMem(TempBmp.Width * TempBmp.Height);
lpvDBits := AllocMem(TempBmp.Width * TempBmp.Height);
DC := CreateCompatibleDC(0);
GetObject(TempBmp.Handle, SizeOf(DS), @DS);
BMIInfo.bmiHeader := DS.dsBmih;
GetDIBits(DC, TempBmp.Handle, 0, DS.dsBmih.biHeight, lpvSBits, BMIInfo^, DIB_RGB_COLORS);
// 垂直翻轉
for i := 0 to TempBmp.Height - 1 do
begin
sOffset := i * TempBmp.Width;
dOffset := (TempBmp.Height - i - 1) * TempBmp.Width;
Move(lpvSBits[sOffset], lpvDBits[dOffset], TempBmp.Width);
end;
// 打包位流 (每行一個 Word,高位在前,黑=1)
for i := 0 to TempBmp.Height - 1 do
begin
wData := 0;
for j := 0 to TempBmp.Width - 1 do
begin
if Byte(lpvDBits[i * TempBmp.Width + j]) = 0 then // 黑像素
wData := (wData shl 1) or 1
else
wData := (wData shl 1) or 0;
end;
MemoryStream.Write(wData, SizeOf(wData));
end;
MemoryStream.SaveToFile(SaveFileName);
// TempBmp.SaveToFile('temp.bmp'); // 調試用:對比生成的位圖
Result := True;
finally
FreeMem(lpvSBits); FreeMem(lpvDBits);
MemoryStream.Free; TempBmp.Free;
end;
end;
// 生成 12x18 點陣 '北' 字字模
ConvertToMatrix('北', 6, 18, 'Font.dat'); // ChrWidth=6 → 12像素寬
// Font.dat 內容 (十六進制視圖,每行 2 字節 = 1 Word = 16bit,高 4bit 為 0)
// 行 0: 00 00
// 行 1: 90 00 (二進制: 1001 0000 0000 0000 → 前兩點為黑)
// 行 2: ...
// 共 18 行 (ChrHeight)
Font.dat,每字符佔 ChrHeight * 2 字節。Text 改為 string,調用時傳 '北',內部用 PChar(Text)。CreateFont 字體名建議明確指定 'SimSun' (宋體) 或 'Microsoft YaHei',確保有字形。AllocMem 返回 Pointer,操作時用 PByte 或 PAnsiChar 避免 Unicode 字符大小混淆。TFileStream 替代 SaveToFile 更可控。該函數利用 GDI 渲染字體 → 獲取 DIB → 翻轉 → 位打包,實現了從矢量字體到單色點陣字模的自動化轉換。代碼邏輯清晰,可直接集成到字庫製作工具中,支持任意字體、任意尺寸,滿足嵌入式顯示開發需求。