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

從 TTF 字體提取字模信息並生成多灰度級位圖

     編輯:關於VC++

背景與動機

傳統點陣字體存在固有缺陷:

  • 分辨率固定,放大嚴重鋸齒
  • 字體資源稀缺,樣式單一
  • 縮放變形效果差、速度慢

TTF (TrueType Font) 作為矢量輪廓字體,支持無級縮放、旋轉、傾斜、多灰度級反走樣,是現代字模提取的理想來源。本文實現從 TTF 直接提取字模並導出 BMP,支持 2/4/16/65 級灰度。

核心流程

  1. 創建邏輯字體 (CFont::CreateFont) 並選入 DC
  2. 調用 GetGlyphOutline 提取字模數據
  3. 根據灰度級處理數據對齊與位圖信息頭構建
  4. 內存顯示 (StretchDIBits) 與 BMP 文件保存

關鍵技術實現

1. 字體創建與選入

CFont newfont;
newfont.CreateFont(m_intHeight, 0, m_intAngle, 0, m_intBold, m_bCheckItalic, 
                   0, 0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
                   DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, m_strFontName);

CDC* pdc = m_ctlDisplay.GetDC();
CFont* poldfont = pdc->SelectObject(&newfont);

參數說明:m_intHeight 決定輸出分辨率,值越大字模越清晰;m_intAngle 支持旋轉;m_intBold/m_bCheckItalic 控制粗體/斜體。

2. GetGlyphOutline 核心調用

DWORD GetGlyphOutline(
    HDC hdc,           // 設備上下文
    UINT uChar,        // 目標字符 (Unicode/ANSI)
    UINT uFormat,      // 輸出格式:GGO_BITMAP/GGO_GRAY2/4/8_BITMAP
    LPGLYPHMETRICS lpgm, // 字模度量信息
    DWORD cbBuffer,    // 緩衝區大小
    LPVOID lpvBuffer,  // 緩衝區指針 (NULL 時返回所需大小)
    CONST MAT2* lpmat2 // 變換矩陣 (縮放/旋轉/切變)
);

3. 灰度級與數據對齊處理

uFormat灰度級像素位深行字節對齊公式
GGO_BITMAP2 級 (單色)1 bit((gmBlackBoxX + 31) / 32) * 4
GGO_GRAY2_BITMAP5 級8 bit((gmBlackBoxX + 3) / 4) * 4
GGO_GRAY4_BITMAP17 級8 bit((gmBlackBoxX + 3) / 4) * 4
GGO_GRAY8_BITMAP65 級8 bit((gmBlackBoxX + 3) / 4) * 4
// 兩次調用模式:先查大小,再分配內存提取
DWORD nLen = GetGlyphOutline(hdc, uChar, uFormat, &gm, 0, NULL, &mat2);
if (nLen > 0) {
    BYTE* pBuf = new BYTE[nLen];
    GetGlyphOutline(hdc, uChar, uFormat, &gm, nLen, pBuf, &mat2);
    // 處理 pBuf...
}

4. 位圖信息頭構建與顯示

// 根據灰度級設置調色盤
int nColors = (uFormat == GGO_BITMAP) ? 2 : 256;
BITMAPINFOHEADER bih = {0};
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = gm.gmBlackBoxX;
bih.biHeight = gm.gmBlackBoxY;
bih.biPlanes = 1;
bih.biBitCount = (uFormat == GGO_BITMAP) ? 1 : 8;
bih.biCompression = BI_RGB;
bih.biSizeImage = charLineW * gm.gmBlackBoxY;

// 構建 RGBQUAD 調色盤 (灰度級均勻分布)
RGBQUAD* pRGB = new RGBQUAD[nColors];
for (int i = 0; i < nColors; i++) {
    BYTE val = (uFormat == GGO_BITMAP) ? (i ? 255 : 0) : (BYTE)(i * 255 / (nColors - 1));
    pRGB[i] = {val, val, val, 0};
}

// 內存 DC 顯示 (雙緩衝)
CRect rect;
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
CDC memdc;
memdc.CreateCompatibleDC(pdc);
CBitmap nbitmap;
nbitmap.CreateCompatibleBitmap(pdc, rect.Width(), rect.Height());
CBitmap* poldbitmap = memdc.SelectObject(&nbitmap);

::StretchDIBits(memdc.m_hDC, -m_intScrollHPos, -m_intScrollVPos,
                m_intPixX, m_intPixY, 0, 0, m_intPixX, m_intPixY,
                pBuf, (BITMAPINFO*)&bih, DIB_RGB_COLORS, SRCCOPY);

pdc->BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY);
memdc.DeleteDC();

5. BMP 文件保存

CFile cf;
cf.Open(strFile, CFile::modeCreate | CFile::modeWrite);

BITMAPFILEHEADER bfh = {0};
bfh.bfType = 0x4D42;  // 'BM'
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColors;
bfh.bfSize = bfh.bfOffBits + charLineW * gm.gmBlackBoxY;

cf.Write(&bfh, sizeof(BITMAPFILEHEADER));
cf.Write(&bih, sizeof(BITMAPINFOHEADER));
cf.Write(pRGB, sizeof(RGBQUAD) * nColors);
cf.Write(pBuf, charLineW * gm.gmBlackBoxY);
cf.Close();

功能特性

  • 字體選擇:系統字體枚舉下拉框
  • 幾何變換:高度、旋轉角度、粗細、斜體可調
  • 灰度級選擇:2/5/17/65 級單選
  • 反色/負片:一鍵翻轉前景背景
  • 滾動查看**:大字模支持水平/垂直滾動
  • BMP 導出**:標準文件格式,兼容所有圖片查看器

應用場景

  • 嵌入式設備字庫生產 (LCD/OLED/e-ink)
  • 遊戲字體圖集預烘焙
  • 打印/雕刻/刺繡矢量轉點陣
  • OCR 訓練數據合成
  • 藝術字體設計預覽

總結

利用 GetGlyphOutline 直接從 TTF 提取字模,繞過了 GDI 文本輸出管線,獲得了對像素級數據的完全控制。支持多灰度級輸出使其能適應從單色顯示屏到高質量印刷的多樣化需求。代碼結構清晰,適合作為字體工具開發的基礎模塊。

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