Printing with OpenGL – Another method

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

One of the largest problems I have encountered using OpenGL is that it is very difficult to print a rendered scene. I have only found one other sample on how to do this, however, there was no sample code and I was unable to actually print (let alone print preview a scene!).

What I have done is create a class, CCaptureImage, out of code snippets found on this site. CCaptureImage will capture an bitmap using a device context and the rect of the image you want. From there, you can paint it to a device or save it to a bmp file. Usage of the CCaptureImage class with respect to printing is shown below in the sample code.

OnPreparePrinting captures the bitmap for printing. For Print Preview, the bitmap is captured in the override of OnFilePrintPreview(). This is done in separate places as the Client rect size may be different if it is found in OnPreparePrinting (if you use dockable toolbars attached, for instance).


BOOL CPrintGLView::OnPreparePrinting(CPrintInfo* pInfo)
{
	if(!pInfo->m_bPreview)
	{
		CRect rcDIB;
		GetClientRect(&rcDIB);
		OnDraw(GetCDC());
		CapturedImage.Capture(GetCDC(), rcDIB);
	}
	return DoPreparePrinting(pInfo);
}

void CPrintGLView::OnFilePrintPreview()
{
	CRect rcDIB;
	GetClientRect(&rcDIB);
	OnDraw(GetCDC());
	CapturedImage.Capture(GetCDC(), rcDIB);

	CView::OnFilePrintPreview();
}

void CPrintGLView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo)
{
	CapturedImage.Release();
	CView::OnEndPrinting(pDC, pInfo);
}

Once the bitmap is captured and stored, it can bu used by the OnDraw method to print it to the printer DC or the print preview DC.

void CPrintGLView::OnDraw(CDC* pDC)
{
	CPrintGLDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	if (pDC->IsPrinting())
	{
		CRect rcDIB;
		GetClientRect(&rcDIB);

		rcDIB.right = rcDIB.Width();
		rcDIB.bottom = rcDIB.Height();


		// get size of printer page (in pixels)
		int cxPage = pDC->GetDeviceCaps(HORZRES);
		int cyPage = pDC->GetDeviceCaps(VERTRES);
		// get printer pixels per inch
		int cxInch = pDC->GetDeviceCaps(LOGPIXELSX);
		int cyInch = pDC->GetDeviceCaps(LOGPIXELSY);

		CRect rcDest;
		rcDest.top = rcDest.left = 0;
		rcDest.bottom = (int)(((double)rcDIB.Height() * cxPage * cyInch)
				/ ((double)rcDIB.Width() * cxInch));
		rcDest.right = cxPage;

		CapturedImage.OnDraw(pDC->m_hDC, &rcDest, &rcDIB);

	}
	else // not printer DC
	{
		pDoc->RenderScene();
	}
}

This method may not be the most elegant, however, it works. The following source has been updated to fix 2 bugs: resize crash
when compiled with VC++6.0, and saving as a bitmap with more than 256 colours.

Thanks for the replies and suggestions.

Download demo project with source – 41 KB

Date Updated: December 14, 1998

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read