傳統點陣字體存在固有缺陷:
TTF (TrueType Font) 作為矢量輪廓字體,支持無級縮放、旋轉、傾斜、多灰度級反走樣,是現代字模提取的理想來源。本文實現從 TTF 直接提取字模並導出 BMP,支持 2/4/16/65 級灰度。
CFont::CreateFont) 並選入 DCGetGlyphOutline 提取字模數據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 控制粗體/斜體。
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 // 變換矩陣 (縮放/旋轉/切變)
);
| uFormat | 灰度級 | 像素位深 | 行字節對齊公式 |
|---|---|---|---|
| GGO_BITMAP | 2 級 (單色) | 1 bit | ((gmBlackBoxX + 31) / 32) * 4 |
| GGO_GRAY2_BITMAP | 5 級 | 8 bit | ((gmBlackBoxX + 3) / 4) * 4 |
| GGO_GRAY4_BITMAP | 17 級 | 8 bit | ((gmBlackBoxX + 3) / 4) * 4 |
| GGO_GRAY8_BITMAP | 65 級 | 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...
}
// 根據灰度級設置調色盤
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();
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();
利用 GetGlyphOutline 直接從 TTF 提取字模,繞過了 GDI 文本輸出管線,獲得了對像素級數據的完全控制。支持多灰度級輸出使其能適應從單色顯示屏到高質量印刷的多樣化需求。代碼結構清晰,適合作為字體工具開發的基礎模塊。