How to extract image from a bitmapped font

Started by
2 comments, last by triangles 12 years, 7 months ago
So I need a small bitmapped font for a retro game I am working on. I found several sites offering free bitmapped fonts for download which look suitable. However, they are always in the ttf format, and I can't figure out any way to extract the actual image data. What should I do?
I trust exceptions about as far as I can throw them.
Advertisement
Assuming you are on windows, use GDI to output all the fonts glyphs to a window, storing glyph position info along the way. Then save the output to a bitmap image and store the glyph positions in a data file.
I've never used GDI. Is there any way to do it with SDL_TTF or with Python?

Why do they make this so hard? Surely the only information you need is the width, and height, and the actual bitmap? It's not like a monospace bitmapped font requires a lot of special metadata.
I trust exceptions about as far as I can throw them.
I expect you can use SDL to render the font glyphs onto a surface and save that, but since I haven't used fonts with SDL I can't help with that.

GDI is pretty easy. In fact I have some code here which renders all the ASCII characters for any given font. Hope it helps.


/// create font
///param font Win32 font handle
///param sz wSize of font
///param fg foreground colour
///param bg background colour
///param hdc Win32 device context handle
///return rectangle representing bounds of drawn area
RECT texmapfont::Create(HFONT font, WORD sz, COLORREF fg, COLORREF bg, HDC hdc) {
// allocate and clear pBitmap data
SetSize(sz);
// create windows hdc and pBitmap
HBITMAP hbm = 0;
HGDIOBJ oldgdiobj[2];
if (hdc == 0) {
HDC tdc = GetDC(NULL);
hdc = CreateCompatibleDC(tdc);
hbm = CreateCompatibleBitmap(tdc, wSize, wSize);
oldgdiobj[0] = SelectObject(hdc, hbm);
ReleaseDC(NULL, tdc);
}
// create and fill character buffer with ASCII characters 32-126
char buffer[256-32];
for (int i = 0; i < 255-32; i++)
buffer = 32 + i;
buffer[255-32] = 0;
// set text colours
SetTextColor(hdc, RGB(255,255,255));
SetBkColor(hdc, RGB(0, 0, 0));
// wipe DC to black
HBRUSH hb = CreateSolidBrush(RGB(255,0,0));
RECT rc = {0, 0, wSize, wSize};
FillRect(hdc, &rc, hb);
DeleteObject(hb);
// set font details
oldgdiobj[1] = SelectObject(hdc, font);
LOGFONT lf;
GetObject(font, sizeof(LOGFONT), &lf);
name = lf.lfFaceName;
dwItalic = lf.lfItalic;
dwWeight = lf.lfWeight;
// draw glyphs
GLYPHMETRICS gm;
MAT2 matrix;
char txt[2] = {0, 0};
memset(&gm, 0, sizeof(gm));
memset(&matrix, 0, sizeof(matrix));
matrix.eM11.value = 1;
matrix.eM22.value = 1;
int sx = 0, sy = 0; // glyph rcPos
for (int i = 0; i < 255-32; i++) {
// calculate glyph wSize
int wOhl = 0, wOhr = 0; // overhang left/right
txt[0] = buffer;
rc.left = sx; rc.top = sy;
rc.right = rc.bottom = wSize - 1;
DrawText(hdc, txt, 1, &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX);
GetGlyphOutline(hdc, buffer, GGO_METRICS, &gm, 0, NULL, &matrix);
if (gm.gmptGlyphOrigin.x < 0) {
// glyph overhangs left edge
wOhl = gm.gmptGlyphOrigin.x;
rc.left -= gm.gmptGlyphOrigin.x;
rc.right = rc.left + gm.gmCellIncX;
}
if (gm.gmptGlyphOrigin.x + gm.gmBlackBoxX > (WORD)(rc.right - rc.left)) {
// glyph overhangs right edge
wOhr = (gm.gmptGlyphOrigin.x + gm.gmBlackBoxX) - (rc.right - rc.left);
rc.right = rc.left + gm.gmptGlyphOrigin.x + gm.gmBlackBoxX;
}
// rercPos if over end of line
if ((DWORD)rc.right >= wSize) {
sx = 0;
sy += rc.bottom - rc.top;
if ((DWORD)sx >= wSize)
break;
rc.left = sx; rc.top = sy;
rc.right = rc.bottom = wSize - 1;
DrawText(hdc, txt, 1, &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX);
if (gm.gmptGlyphOrigin.x < 0) {
// glyph overhangs left edge
wOhl = gm.gmptGlyphOrigin.x;
rc.left -= gm.gmptGlyphOrigin.x;
rc.right = rc.left + gm.gmCellIncX;
}
if (gm.gmptGlyphOrigin.x + gm.gmBlackBoxX > (WORD)(rc.right - rc.left)) {
// glyph overhangs right edge
wOhr = (gm.gmptGlyphOrigin.x + gm.gmBlackBoxX) - (rc.right - rc.left);
rc.right = rc.left + gm.gmptGlyphOrigin.x + gm.gmBlackBoxX;
}
}
// draw glyph
DrawText(hdc, txt, 1, &rc, DT_LEFT|DT_NOPREFIX|DT_NOCLIP);
// store glyph info in array
glyph.bValue = txt[0];
glyph.wOhl = -wOhl;
glyph.wOhr = wOhr;
glyph.rcPos.left = (WORD)rc.left + wOhl;
glyph.rcPos.top = (WORD)rc.top;
glyph.rcPos.right = (WORD)rc.right;
glyph.rcPos.bottom = (WORD)rc.bottom;
// move draw rcPos
sx = rc.right;
}
SelectObject(hdc, oldgdiobj[1]);
// copy drawn data to pBitmap data
COLORREF pv;
for (DWORD iy = 0; iy < wSize; iy++) {
for (DWORD ix = 0; ix < wSize; ix++) {
pv = GetPixel(hdc, ix, iy);
pBitmap[iy * wSize + ix] = (BYTE)(pv & 0xFF);
}
}
if (hbm != 0) {
SelectObject(hdc, oldgdiobj[0]);
DeleteObject(hbm);
DeleteDC(hdc);
}
dwHeight = glyph[0].rcPos.bottom;
rc.left = rc.top = 0;
RECT ret = { (WORD)rc.left, (WORD)rc.top, (WORD)rc.right, (WORD)rc.bottom };
return ret;
}

This topic is closed to new replies.

Advertisement