Capturing a Window Image Into a Bitmap File, Supporting MS PaintBrush and All — (Like the Thumbnail View of Windows Explorer)

Environment: VC++

Introduction

I have written this article to capture a Windows image into a bitmap file that will support all PaintBrush tools and Thumbnail Views of Windows Explorer. I have found many programmers suffering from this problem, including me, until I wrote this article.

The problem was that a Windows image is captured and also saved into a bitmap file. But, when it is opened with any paint tool, it will be seen as white only and also will not appear properly in the thumbnail view of Windows Explorer. But, after you save this bitmap file, using MS Paint or any other paint tool, it will open properly again as a common bitmap. Here, with this cool code, I have solved this problem. I hope it will be helpful to someone.

I also needed to capture an active window image and to save it into the “.bmp” file format. Therefore, I have written code to capture the window image and to save it into the BMP format.

Here, I used two functions, WndToBmpFile() and DDBToDIB(). Here is cool code for it.

About the Author

Hi! Guys,

I am not a well-experienced programmer but always try to do my best. So, that’s why I have found this solution. I am working in an Indian Company as a senior programmer. We develop software and hardware related to video mixing and photography. My desire is to do a lot in the VC++ field especially in Graphics and Image Processing side. This is my beginning, so maybe you will not find many problems with my code. But, your appreciation will become an inspiration for me.

Code Compilation and Testing

I have compiled and tested well this code. So, don’t bother about it!!

From:
Shailesh N. Kanzariya, shailesh_kanzariya@hotmail.com


//////////////////////////////////////////////////////////////////
Function Name :BOOL WndToBmpFile(CDC *pDC, CString szFile)
Parameters:
CDC *pDC: is pointer to window DC whose image should be
captured.
CString szFile : is null terminated string with that name Bmp
file should be saved.
//////////////////////////////////////////////////////////////////

//it will capture a wnd image and save it into a bmp file

BOOL WndToBmpFile(CDC *pDC, CString szFile)
{
//it will capture a wnd image and save it into a bmp file

CString fname=szFile;
CBitmap bmp,*pOldBmp;
CRect rect;
CWnd *pWnd;
BOOL flg=0;
CPalette pal;
LOGPALETTE *pLp;

if(pDC==NULL) //if pDC is NULL return
{
return FALSE;
}

pWnd=pDC->GetWindow(); //Get Window of PDC

pWnd->GetClientRect(&rect); //Get dimension of Window

if(fname.IsEmpty())
return FALSE;

CDC memdc;

memdc.CreateCompatibleDC(pDC); //Make Compatible DC for memdc
bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
//Create Compatible DDB
pOldBmp=memdc.SelectObject(&bmp);
memdc.BitBlt(0,0,rect.Width(),rect.Height(),pDC,0,0,SRCCOPY);

//The following code will detect whether the BMP uses a Raster
//palette or not.

if(pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
{
int nSize;
nSize=sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 256;
pLp=(LOGPALETTE*) new BYTE[nSize];
pLp->palVersion=0x300;
pLp->palNumEntries=GetSystemPaletteEntries(
pDC->m_hDC,0,255,pLp->palPalEntry);
pal.CreatePalette(pLp);

delete [] pLp;
}
memdc.SelectObject(pOldBmp);

//will convert bitmap from DDB to DIB see DDBToDIB()
// See DDBToDIB function for more..

HANDLE hDIB=DDBToDIB(bmp,BI_RGB,&pal);
if(hDIB==NULL)
return FALSE;

//*************************************
//This code writes the BMP file

CFile m_file;
if(!m_file.Open(fname,CFile::modeWrite |
CFile::modeCreate,NULL))
return FALSE;
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;
lpbi=(LPBITMAPINFOHEADER ) hDIB;
int nColors= 1 << lpbi->biBitCount;
hdr.bfType= ((WORD) (‘M’ << 8) | ‘B’);
hdr.bfSize=sizeof(hdr) + GlobalSize(hDIB);
hdr.bfReserved1=0;
hdr.bfReserved2=0;
hdr.bfOffBits=(DWORD) sizeof(hdr) + nColors * sizeof(RGBQUAD);
m_file.Write(&hdr,sizeof(hdr));
m_file.Write(lpbi,GlobalSize(hDIB));
m_file.Close();
//**************************************

//This is the tricky part of the code. It will open the BMP file
//again, but in Binary Mode. Then, it will read the first 14
//bytes from the bitmap file.
//It will change the 11th byte from 11 to 36.
//It will change the 14th byte from 4 to 0 because this is the
//basic requirement for the bitmap format.
//So, it will support all PaintBrush Tools and thumbnail views
//of Windows Explorer.

CBinFile m_tempFile; //CBinFile is derived from CFile
BYTE dummy=0;//14 //14
BYTE pBuf[14]; //11

BOOL fres=m_tempFile.Open(fname,CFile::modeReadWrite |
CFile::typeBinary);

if(fres==0)
return FALSE;

UINT tt=m_tempFile.Read(pBuf,14);
pBuf[13]=dummy;//will replace from 04 to 00
m_tempFile.SeekToBegin();
m_tempFile.Write(pBuf,14);

m_tempFile.Close();

return flg;

//it will capture wnd and save into a bmp file
//End of the code

}

//////////////////////////////////////////////////////////////////
Function Name :HANDLE DDBToDIB(CBitmap &bitmap,
DWORD dwCompression,
CPalette *pPal)
Parameters:
CBitmap &bitmap : Compatible Device Dependent Bitmap
DWORD dwCompression : Compression format for Bitmap must not be
BI_BITFIELDS in this case.
CPalette *pPal : Pointer to Palette. If this is NULL, the
default system palette will be used.

//////////////////////////////////////////////////////////////////
HANDLE DDBToDIB(CBitmap &bitmap, DWORD dwCompression,
CPalette *pPal)
{

BITMAP bm;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen;
HANDLE hDIB;
HANDLE handle;
HDC hDC;
HPALETTE hPal;

ASSERT( bitmap.GetSafeHandle() );

// The function has no arg for bitfields
if( dwCompression == BI_BITFIELDS )
return NULL;

// If a palette has not been supplied, use default palette
hPal = (HPALETTE) pPal->GetSafeHandle();
if (hPal==NULL)
hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);

// Get bitmap information
bitmap.GetObject(sizeof(bm),(LPSTR)&bm);

// Initialize the bitmap infoheader
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
//bm.bmPlanes * bm.bmBitsPixel;
bi.biCompression = dwCompression;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

// Compute the size of the infoheader and the color table
int nColors = (1 << bi.biBitCount);
if( nColors > 256 )
nColors = 0;
dwLen = bi.biSize + nColors * sizeof(RGBQUAD);

// We need a device context to get the DIB from
hDC = ::GetDC(NULL);
hPal = SelectPalette(hDC,hPal,FALSE);
RealizePalette(hDC);

// Allocate enough memory to hold bitmap infoheader and
// color table

hDIB = GlobalAlloc(GMEM_FIXED,dwLen);

if (!hDIB){
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

lpbi = (LPBITMAPINFOHEADER)hDIB;

*lpbi = bi;

// Call GetDIBits with a NULL lpBits param, so the device
// driver will calculate the biSizeImage field

GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L,
(DWORD)bi.biHeight,
(LPBYTE)NULL, (LPBITMAPINFO)lpbi,
(DWORD)DIB_RGB_COLORS);

bi = *lpbi;

// If the driver did not fill in the biSizeImage field, then
// compute it
// Each scan line of the image is aligned on a DWORD (32bit)
// boundary

if (bi.biSizeImage == 0){
bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31)
& ~31) / 8) * bi.biHeight;

// If a compression scheme is used, the result may in fact
// be larger
// Increase the size to account for this.

if (dwCompression != BI_RGB)
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
}

// Realloc the buffer so that it can hold all the bits
dwLen += bi.biSizeImage;
if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
hDIB = handle;
else{
GlobalFree(hDIB);

// Reselect the original palette
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

// Get the bitmap bits
lpbi = (LPBITMAPINFOHEADER)hDIB;

// FINALLY get the DIB
BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(),
0L, // Start scan line
(DWORD)bi.biHeight, // # of scan lines
(LPBYTE)lpbi // address for bitmap bits
+ (bi.biSize + nColors * sizeof(RGBQUAD)),
(LPBITMAPINFO)lpbi, // address of bitmapinfo
(DWORD)DIB_RGB_COLORS); // Use RGB for color table

if( !bGotBits )
{
GlobalFree(hDIB);

SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);

return hDIB;

//End of the function
}

Downloads

Download Project Source – 128 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read