I added code to save my crossword puzzle and solution to two bitmap files. It is interesting how many people write code to do things of this sort that don’t write it correctly.

image

Puzzle Bitmap
void CChildView::SaveImageToFile( const char *pFilename, bool bSolution )
{
	CSize GridSize = GetGridCellSize();

	// Convert from grid cell size to grid pixel size.
	GridSize.cx *= SQUARE_SIZE;
	GridSize.cy *= SQUARE_SIZE;
	// We know about some extra pixels that are needed beyond the cell pixels.
	GridSize.cx += 3;
	GridSize.cy += 3;

	CDC ScreenDC;
	ScreenDC.Attach( ::GetDC( 0 ) );
	CDC MemoryDC;

	BYTE *lpBitmapBits = NULL; 

	int nWidth = GridSize.cx;
	int nHeight = GridSize.cy;

	// Use a larger bitmap than what is drawn on the screen.
	// The bitmap will get stuck in a Word document and this makes for a better picture.
	static const int SCALEUP = 4;
	nWidth *= SCALEUP;
	nHeight *= SCALEUP;

	MemoryDC.CreateCompatibleDC( &ScreenDC ); 

	BITMAPINFO bi; 
	ZeroMemory(&bi, sizeof(BITMAPINFO));
	bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bi.bmiHeader.biWidth = nWidth;
	bi.bmiHeader.biHeight = nHeight;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 24;
	bi.bmiHeader.biCompression = BI_RGB;
	bi.bmiHeader.biSizeImage =  ( ( bi.bmiHeader.biWidth * bi.bmiHeader.biBitCount + 31 ) & ~31 ) / 8 * bi.bmiHeader.biHeight;
	bi.bmiHeader.biXPelsPerMeter = 2834;
	bi.bmiHeader.biYPelsPerMeter = 2834;

	HBITMAP bitmap = ::CreateDIBSection( MemoryDC.GetSafeHdc(), &bi, DIB_RGB_COLORS, (LPVOID*)&lpBitmapBits, NULL, 0);
	HGDIOBJ oldbmp = MemoryDC.SelectObject( bitmap ); 

	// Make the bitmap larger by using window and viewport settings.
	MemoryDC.SetMapMode( MM_ISOTROPIC );
	MemoryDC.SetWindowExt( GridSize.cx, GridSize.cy );
	MemoryDC.SetViewportExt( nWidth, nHeight );

	DrawGrid( &MemoryDC, 0, 0, bSolution );

	BITMAPFILEHEADER bh;
	ZeroMemory( &bh, sizeof ( bh ) );
	bh.bfType = 'B' + ( 'M' << 8 );

	bh.bfOffBits = sizeof( bh ) + sizeof( bi.bmiHeader );

	bh.bfSize = bh.bfOffBits + ( 3 * nWidth * nHeight );

	CFile file;
	if( file.Open(pFilename, CFile::modeCreate | CFile::modeWrite) )
	{ 
		file.Write( &bh, sizeof( bh ) );
		file.Write( &(bi.bmiHeader ), sizeof( bi.bmiHeader ) );
		file.Write( lpBitmapBits, bi.bmiHeader.biSizeImage );
		file.Close();
	}

	MemoryDC.SelectObject( oldbmp );
	::DeleteObject( bitmap );
}

I didn’t write this from scratch. I just took it from a code sample somewhere. This bit of code was wrong where it writes the bitmap data because the bitmap data size is not just the width * height * 3 as was in the bad code. Strange that someone would stick that equation in there when they earlier set the bi.bmiHeader.biSizeImage value properly.

The interesting thing I did here was reusing the code that draws to the screen to draw to the bitmap for the file. I used the window and viewport settings to scale the image. The number of logical pixels does not change but fonts are smooth at the actual bitmap resolution making this ideal for a quick and dirty file writing function.

Now on to the code to handle the 4-letter clump that I described in an earlier blog post.