bool wxWindowsPrintPreview::RenderPageIntoBitmap(wxBitmap& bmp, int pageNum) { // The preview, as implemented in wxPrintPreviewBase (and as used prior to // wx3) is inexact: it uses screen DC, which has much lower resolution and // has other properties different from printer DC, so the preview is not // quite right. // // To make matters worse, if the application depends heavily on // GetTextExtent() or does text layout itself, the output in preview and on // paper can be very different. In particular, wxHtmlEasyPrinting is // affected and the preview can be easily off by several pages. // // To fix this, we render the preview into high-resolution enhanced // metafile with properties identical to the printer DC. This guarantees // metrics correctness while still being fast. // print the preview into a metafile: wxPrinterDC printerDC(m_printDialogData.GetPrintData()); wxEnhMetaFileDC metaDC(printerDC, wxEmptyString, printerDC.GetSize().x, printerDC.GetSize().y); if ( !RenderPageIntoDC(metaDC, pageNum) ) return false; wxEnhMetaFile *metafile = metaDC.Close(); if ( !metafile ) return false; // now render the metafile: wxMemoryDC bmpDC; bmpDC.SelectObject(bmp); bmpDC.Clear(); wxRect outRect(0, 0, bmp.GetWidth(), bmp.GetHeight()); metafile->Play(&bmpDC, &outRect); delete metafile; // TODO: we should keep the metafile and reuse it when changing zoom level return true; }
bool wxWindowsPrintPreview::RenderPageFragment(float scaleX, float scaleY, int *nextFinalLine, wxPrinterDC& printer, wxMemoryDC& finalDC, const wxRect& rect, int pageNum) { // compute 'rect' equivalent in the small final bitmap: const wxRect smallRect(wxPoint(0, *nextFinalLine), wxPoint(int(rect.GetRight() * scaleX), int(rect.GetBottom() * scaleY))); wxLogTrace("printing", "rendering fragment of page %i: [%i,%i,%i,%i] scaled down to [%i,%i,%i,%i]", pageNum, rect.x, rect.y, rect.GetRight(), rect.GetBottom(), smallRect.x, smallRect.y, smallRect.GetRight(), smallRect.GetBottom() ); // create DC and bitmap compatible with printer DC: wxBitmap large(rect.width, rect.height, printer); if ( !large.IsOk() ) return false; // render part of the page into it: { PageFragmentDC memoryDC(&printer, large, rect.GetPosition(), wxSize(m_pageWidth, m_pageHeight)); if ( !memoryDC.IsOk() ) return false; memoryDC.Clear(); if ( !RenderPageIntoDC(memoryDC, pageNum) ) return false; } // release bitmap from memoryDC // now scale the rendered part down and blit it into final output: wxImage img; { wxDIB dib(large); if ( !dib.IsOk() ) return false; large = wxNullBitmap; // free memory a.s.a.p. img = dib.ConvertToImage(); } // free the DIB now that it's no longer needed, too if ( !img.IsOk() ) return false; img.Rescale(smallRect.width, smallRect.height, wxIMAGE_QUALITY_HIGH); if ( !img.IsOk() ) return false; wxBitmap bmp(img); if ( !bmp.IsOk() ) return false; img = wxNullImage; finalDC.DrawBitmap(bmp, smallRect.x, smallRect.y); if ( bmp.IsOk() ) { *nextFinalLine += smallRect.height; return true; } return false; }