Printing with OpenGL - Another method

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



Comments

  • OpenGL Printing; Better to render directly to a DIB

    Posted by Legacy on 02/01/1999 12:00am

    Originally posted by: David Calkins

    I think that the method presented for printing an OpenGL scene is good if you want something quick-and-dirty, but it has some drawbacks. The method basically, copys the window contents to the printer. So, you're limited by the screen resolution (window size, actually).

    Most printers have a much higher resolution than the screen, and you should really try and take advantage of this when printing OpenGL scenes. The better method is to make OpenGL render directly to a DIB section. This DIB section can be huge (sized for the printers resolution not the screens). Then, you can blit the DIB to the printer.

    1. create a DIB, using CreateDIBSection() the size of the printer page
    2. select the DIB into a DC.
    3. set up GL to render to this DC.
    4. when GL is done, you can blit the image to the printer.

    I was told that this was the best way by a Microsoft GL guru. It does make more sense than simply rendering to a window, and then blitting the low-res image (or worse, stretching it) to the printer.

    Having said this, there are some drawbacks to this method. Creating huge DIBs requires more resources than simply blitting the window out, and for some applications you would certainly have fewer headaches if you just use the method described above. You won't take advantage of the high-res of your printer though.

    There is an excellent example of printing from GL on Microsoft's ftp site. This example does all GL rendering directly to a DIB. Then to display the image you can blit to the window, and to print it, you can blit to the printer. Of course, if you want you can make a larger DIB for printing to accomodate high printer resolution.

    ftp.microsoft.com/SoftLib/MSLFILES/GLBMP.EXE

    Reply
  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds