首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 實現漢字點陣字模提取:指定尺寸字體渲染至單色位圖並導出十六進制數組

     編輯:Delphi

應用場景

嵌入式開發中,需將漢字字模燒錄至 EPROM 或在無字庫的 LCD/LED 屏顯示。Windows 提供矢量字體 (TrueType),需在運行時渲染為指定尺寸的點陣矩陣 (每像素 1 bit),並按「行優先、高位在前」順序導出為 C 數組或二進制文件。

核心函數:ConvertToMatrix

function ConvertToMatrix(Text: PChar; ChrWidth, ChrHeight: Byte; SaveFileName: PChar): Boolean;
// Text: 單個漢字 (2 字節),ChrWidth: 字符寬度(點陣列數),實際漢字寬度 = ChrWidth*2
// ChrHeight: 字符高度(點陣行數),SaveFileName: 輸出文件路徑

實現關鍵步驟

  1. 創建兼容位圖:TBitmap 設置 PixelFormat := pf8bit (256 色),寬高按參數設定。
  2. 構建邏輯字體:CreateFont 指定高度、寬度 (ChrWidth)、字符集 GB2312_CHARSET、字體名 'script' (系統默認中文字體)。
  3. 繪製文本:SelectObject(DC, Font) → TextOut(DC, 0, 0, Text, Len)。
  4. 獲取 DIB 數據:GetObject → GetDIBits 將位圖像素數據讀入內存緩衝區 (lpvSBits),像素值 0=黑(前景),非 0=白(背景)。
  5. 垂直翻轉:Windows DIB 原點在左下,需翻轉為左上原點 (逐行拷貝)。
  6. 打包為位流:每行像素按序打包進 Word (16 bit),高位對應左側像素。黑(0)→bit=1,白(非0)→bit=0。不足 16 位高位補 0。
  7. 寫入文件: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 字節。
  • 顯示時:外層循環行 (0..ChrHeight-1),內層循環列 (0..ChrWidth*2-1),取字節高位到低位 (或低位到高位,視硬件掃描順序),點亮/熄滅像素。
  • 若硬件掃描順序為列優先,需在 PC 端轉置矩陣或調整打包邏輯。

遷移建議 (Delphi 2009+ Unicode 版本)

  1. 參數 Text 改為 string,調用時傳 '北',內部用 PChar(Text)。
  2. CreateFont 字體名建議明確指定 'SimSun' (宋體) 或 'Microsoft YaHei',確保有字形。
  3. AllocMem 返回 Pointer,操作時用 PByte 或 PAnsiChar 避免 Unicode 字符大小混淆。
  4. 文件流用 TFileStream 替代 SaveToFile 更可控。

總結

該函數利用 GDI 渲染字體 → 獲取 DIB → 翻轉 → 位打包,實現了從矢量字體到單色點陣字模的自動化轉換。代碼邏輯清晰,可直接集成到字庫製作工具中,支持任意字體、任意尺寸,滿足嵌入式顯示開發需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved