Drawing to a Bitmap

Starting with the earliest versions of Windows and continued with the Win32 API, the device context used for manipulating graphics in the GDI library has been a mainstay of Windows graphics programming. I have found the need to do more than just render graphics on a monitor or printer. Every once in a while I need to render graphics right onto a bitmap image. Recently, I found a need to do this when I was working with some code that needed to render TrueType fonts onto a screen painted through calls to the FastGraph library.

The basic concept is that the GDI calls work on a memory based device context that has a bitmap selected into it. Any subsequent calls drawing to that device context will result in drawing directly onto the selected bitmap.

char *string = "My Text";
HDC dc = GetDC(GetDesktopWindow());
HFONT ttfont = CreateFont(-10*GetDeviceCaps(dc, LOGPIXELSY)/72, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS | CLIP_LH_ANGLES, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "Arial");
HDC memdc = CreateCompatibleDC(dc);
HBITMAP hbmp, hbmpOld;
SIZE textsize;
RECT textrect = {0};
COLORREF transparent = 0; // black is transparent for FastGraph in this instance
HBRUSH transbrush = CreateSolidBrush(transparent);
BITMAPINFO bmi = {0};
COLORREF *dibuf;

SelectObject(memdc, ttfont);
GetTextExtentPoint32(memdc, string, strlen(string), &textsize);

textrect.right = textsize.cx;
textrect.bottom = textsize.cy;
hbmp = CreateCompatibleBitmap(dc, textsize.cx, textsize.cy);
hbmpOld = SelectObject(memdc, hbmp);

FillRect(memdc, &textrect, transbrush);
SetBkColor(memdc, transparent);
SetTextColor(memdc, textcolor);
DrawText(memdc, string, -1, &textrect, DT_SINGLELINE);

SelectObject(memdc, hbmpOld);

bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = textsize.cx;
bmi.bmiHeader.biHeight = -textsize.cy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = textsize.cx * 4 * textsize.cy;

dibuf = (COLORREF *)malloc(bmi.bmiHeader.biSizeImage);
if (GetDIBits(memdc, hbmp, 0, textsize.cy, dibuf, &bmi, DIB_RGB_COLORS))
{
    // copy pixels over to FastGraph buffers
}

free(dibuf);
DeleteObject(transbrush);
DeleteObject(hbmp);
DeleteDC(memdc);
ReleaseDC(dc);

The call to GetDIBits using 32 bits per pixel makes the copying process simpler when dealing with true color displays. It is important that the device context used to create the compatible bitmap is NOT the one created in memory. That is why dc is used instead of memdc in the call to CreateCompatibleBitmap above.