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 were 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 loose 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.