<

Win32: Capture an image

Published on
10,237 Points
6,137 Views
1 Endorsement
Last Modified:
Currently I'm working on a Win32 GDI Application - thousands of polygons and polylines are drawn on an internal device context and then copied on the application screen. Tons of geometrical data and few coordinate transformations made the debugging totally useless operation. So, for the debug purpose, I added a function saving the image from the internal DC. I use this function as the well-know TRACE, but in my case, I have a bitmap file as a report instead of the text.

Here is the function:

 
BOOL Capture(HDC hDC, LPRECT lpRect, LPCWSTR lpszFile)
{
	BITMAPINFO bmi = { 0 };

	LPBYTE pBits = NULL;
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = lpRect->right - lpRect->left;
	bmi.bmiHeader.biHeight = lpRect->bottom - lpRect->top;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 32;
	bmi.bmiHeader.biCompression = BI_RGB;
	HBITMAP hBitmap = CreateDIBSection(hDC, &bmi, 
		DIB_RGB_COLORS, (LPVOID*)&pBits, NULL, 0);

	HDC hMemDC = CreateCompatibleDC(hDC);
	HGDIOBJ hOld = SelectObject(hMemDC, hBitmap);
	BitBlt(hMemDC, 0, 0, 
		lpRect->right - lpRect->left,
		lpRect->bottom - lpRect->top,
		hDC, lpRect->left, lpRect->top, SRCCOPY);
	SelectObject(hMemDC, hOld);
	DeleteDC(hMemDC);

	DWORD nImageSize = ((((bmi.bmiHeader.biWidth * 
		bmi.bmiHeader.biBitCount) 
		+ 31) & ~31) >> 3) 
		* bmi.bmiHeader.biHeight;

	BITMAPFILEHEADER header = { 0 };
	header.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + 
		(DWORD)sizeof(BITMAPINFOHEADER); 
	header.bfSize = nImageSize + sizeof(BITMAPFILEHEADER) + 
		sizeof(BITMAPINFOHEADER);
	header.bfType = 0x4D42;

	HANDLE hFile = CreateFile(lpszFile, GENERIC_WRITE,
		0, NULL, CREATE_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL, NULL);   

	if (hFile != INVALID_HANDLE_VALUE) 
	{
		DWORD nWritten = 0;;
		WriteFile(hFile, (LPVOID)&header, 
			sizeof(BITMAPFILEHEADER), 
			&nWritten, NULL);
		WriteFile(hFile, (LPVOID)&bmi, 
			sizeof(BITMAPINFOHEADER), 
			&nWritten, NULL);
		WriteFile(hFile, (LPVOID)pBits, nImageSize, 
			&nWritten, NULL);
		CloseHandle(hFile);
	}

	return TRUE;
}

Open in new window


If you'd prefer the C style:

 
BOOL Capture(HDC hDC, LPRECT lpRect, LPCWSTR lpszFile)
{
	HDC hMemDC;
	HBITMAP hBitmap;
	HGDIOBJ hOld;
	BITMAPINFO bmi;
	LPBYTE pBits;
	DWORD nImageSize;
	DWORD nWritten;
	BITMAPFILEHEADER header;
	HANDLE hFile;

	ZeroMemory((LPVOID)&bmi, sizeof(BITMAPINFO));
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = lpRect->right - lpRect->left;
	bmi.bmiHeader.biHeight = lpRect->bottom - lpRect->top;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 24;
	bmi.bmiHeader.biCompression = BI_RGB;

	pBits = NULL;

	hBitmap = CreateDIBSection(hDC, &bmi, 
		DIB_RGB_COLORS, (LPVOID*)&pBits, NULL, 0);

	hMemDC = CreateCompatibleDC(hDC);
	hOld = SelectObject(hMemDC, hBitmap);
	BitBlt(hMemDC, 0, 0, 
		lpRect->right - lpRect->left,
		lpRect->bottom - lpRect->top,
		hDC, lpRect->left, lpRect->top, SRCCOPY);
	SelectObject(hMemDC, hOld);
	DeleteDC(hMemDC);

	nImageSize = ((((bmi.bmiHeader.biWidth * 
		bmi.bmiHeader.biBitCount) 
		+ 31) & ~31) >> 3) 
		* bmi.bmiHeader.biHeight;

	ZeroMemory((LPVOID)&header, sizeof(BITMAPFILEHEADER));
	header.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + 
		(DWORD)sizeof(BITMAPINFOHEADER); 
	header.bfSize = nImageSize + sizeof(BITMAPFILEHEADER) + 
		sizeof(BITMAPINFOHEADER);
	header.bfType = 0x4D42;

	hFile = CreateFile(lpszFile,	GENERIC_WRITE,
		0, NULL, CREATE_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL, NULL);   

	if (hFile != INVALID_HANDLE_VALUE) 
	{
		WriteFile(hFile, (LPVOID)&header, 
			sizeof(BITMAPFILEHEADER), &nWritten, NULL);
		WriteFile(hFile, (LPVOID)&bmi, 
			sizeof(BITMAPINFOHEADER), &nWritten, NULL);
		WriteFile(hFile, (LPVOID)pBits, 
			nImageSize, &nWritten, NULL);
		CloseHandle(hFile);
	}

	return TRUE;
}

Open in new window


Brief explanation. The function receives 3 parameters:

1. The device context handle from which the image should be grabbed.

2. The image rectangle.

3. The file name to save the grabbed image.

Capture function creates new DIB section (32-bits but it works with 24 also) and copy the image from the input device context onto this DIB section. The next task is to save this DIB section. In the Win32 application for me was easier to save it as BMP-file. The file structure is simple:

1. File header that contains general information about the file such as the type and size of the image, and the offset to the bit-array of the graphical data. A

2. Bitmap information header contains the information about the image such as width and height, bits per pixel and a compression.

3. The bit-array or the color table - the image pixels.

Note. If your application supports ATL/MFC, you can use CImage class whenever you need to save an image. This MSDN example saves an image in BMP, JPG and PNG formats.

The following code shows how to use this function:
 
#include <Windows.h>

BOOL Capture(HDC, LPRECT, LPCWSTR);

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
	LPWSTR lpCmdLine, int nCmdShow)
{
	HWND hWnd;
	HDC hDC;
	RECT rect;
	rect.left = 0;
	rect.top = 0;
	rect.right = 260;
	rect.bottom = 512;

	hWnd = GetDesktopWindow();
	hDC = GetDC(hWnd);

	Capture(hDC, &rect, L"capture.bmp");
	return 0;
}

Open in new window

Compiled this application will grab the top-left corner of the desktop.

Of course, when I almost finished my capturing function I found an article in MSDN with an unexpected name "Capturing an Image": http://msdn.microsoft.com/en-us/library/dd183402(VS.85).aspx. It helped me to understand the bitmap file header, but the source code in this article looks for me more complicated that the one I propose it this article.
1
Comment
Author:pgnatyuk
0 Comments

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Join & Write a Comment

This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
From store locators to asset tracking and route optimization, learn how leading companies are using Google Maps APIs throughout the customer journey to increase checkout conversions, boost user engagement, and optimize order fulfillment. Powered …

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month