Introduction
This article describes the operations needed to draw lines, shapes, or text on bitmaps. The task is quite simple, but a quick reference could be handy for the beginners.
Working with HBITMAPs
As first step, we need a background image, referenced by a hbitmap
handle. hbitmap
can be the result of previous operations, or created with CreateBitmap()
, or a resource:
HBITMAP hbitmap = ::LoadBitmap(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_BITMAP1));
From hbitmap
, we can extract the basic attributes:
BITMAP bm;
GetObject( hbitmap, sizeof(BITMAP), &bm );
long width=bm.bmWidth;
long height=bm.bmHeight;
Now let's create a memory device context and select a new bitmap.
BITMAPINFO bmInfo;
memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));
bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmInfo.bmiHeader.biWidth=width;
bmInfo.bmiHeader.biHeight=height;
bmInfo.bmiHeader.biPlanes=1;
bmInfo.bmiHeader.biBitCount=24;
HDC pDC = ::GetDC(0);
HDC TmpDC=CreateCompatibleDC(pDC);
BYTE *pbase;
HBITMAP TmpBmp=CreateDIBSection(pDC,
&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);
HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);
TmpDC
is the device context where you can draw lines, text, or images. For example, the next lines draw a string
over a background image:
HDC dcBmp=CreateCompatibleDC(TmpDC);
HGDIOBJ TmpObj2 = SelectObject(dcBmp,hbitmap);
BitBlt(TmpDC,0,0,width,height,dcBmp,0,0,SRCCOPY);
SelectObject(TmpDC,TmpObj2);
DeleteDC(dcBmp);
CFont m_Font;
LOGFONT* m_pLF;
m_pLF=(LOGFONT*)calloc(1,sizeof(LOGFONT));
strncpy(m_pLF->lfFaceName,"Times New Roman",31);
m_pLF->lfHeight=64;
m_pLF->lfWeight=600;
m_pLF->lfItalic=1;
m_pLF->lfUnderline=0;
m_Font.CreateFontIndirect(m_pLF);
CDC dc;
dc.Attach(TmpDC);
CFont* pOldFont=NULL;
if (m_Font.m_hObject)
pOldFont = dc.SelectObject(&m_Font);
else
dc.SelectObject(GetStockObject(DEFAULT_GUI_FONT));
dc.SetTextColor(RGB(60,120,240));
RECT pos = {40,40,0,0};
dc.SetBkMode(TRANSPARENT);
dc.DrawText("Test",4,&pos,DT_CALCRECT);
dc.DrawText("Test",4,&pos,0);
if (pOldFont) dc.SelectObject(pOldFont);
m_Font.DeleteObject();
dc.Detach();
free(m_pLF);
At this point, there are 2 bitmaps: hbitmap
and TmpBmp
, you can keep both the old and the new image, or replace hbitmap
with TmpBmp
:
DeleteObject(hbitmap);
hbitmap=TmpBmp;
Finally, we can delete the temporary device context. Do not delete hbitmap
and TmpBmp
here, or you'll lose the bitmap.
SelectObject(TmpDC,TmpObj);
DeleteDC(TmpDC);
Conclusion
The article starts with a background image stored in a HBITMAP
, and ends with a new image in a new HBITMAP
. This grants a high flexibility on what you can do before, after and in between: you can use all the GDI functions to build your image, and for example you can use CBitmap
, or image processing libraries like FreeImage and CxImage, to add effects or save the result in a file.