/////////////////////////////////////////////////////
// Recommend Method, uses GdiPlus to draw an image //
/////////////////////////////////////////////////////
void CVcprint6View::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
// Get Device DPI Resolutions //
int nLogPx = ::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSX);
int nLogPy = ::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSY);
// Added a margin in case you want header/footer info. Set 0 to consume full page.
// Setting to nLogPx creates an inch margin //
int nMarginX = nLogPx;
int nMarginY = nLogPy;
// Setting DPIX and DPIY is recommended, we set these below as needed. //
int nOldDPIx = PEnget(m_hPE, PEP_nDPIX);
int nOldDPIy = PEnget(m_hPE, PEP_nDPIY);
// TIP! If switching mapping modes (OR VIEWPORTEXT or VIEWPORTORG) more than once,
// it's a good idea to use SaveDC, and then RestoreDC between these changes.
int nStartingDC = pDC->SaveDC();
// ProEssentials uses mapping mode = Text //
int oldMM = pDC->SetMapMode(MM_TEXT);
///////////////////////////////////
// If drawing Header, do so here //
///////////////////////////////////
pDC->SetTextAlign(TA_LEFT);
pDC->TextOut(0, 0, "Left Justified header text.");
pDC->SetTextAlign(TA_CENTER);
pDC->TextOut(pInfo->m_rectDraw.Width()/2, 0, "Centered header text.");
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(pInfo->m_rectDraw.Width(), 0, "Right Justified header text.");
///////////////////////////////////
// If drawing Footer, do so here //
///////////////////////////////////
pDC->SetTextAlign(TA_LEFT | TA_BOTTOM );
pDC->TextOut(0, pInfo->m_rectDraw.Height(), "Left Justified footer text.");
pDC->SetTextAlign(TA_CENTER | TA_BOTTOM );
pDC->TextOut(pInfo->m_rectDraw.Width()/2, pInfo->m_rectDraw.Height(), "Centered footer text.");
pDC->SetTextAlign(TA_RIGHT | TA_BOTTOM );
pDC->TextOut(pInfo->m_rectDraw.Width(), pInfo->m_rectDraw.Height(), "Right Justified footer text.");
/////////////////////////////////////
// Start ProEssentials Image Logic //
/////////////////////////////////////
DWORD gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
int nChartSizeX = (pInfo->m_rectDraw.Width()-nMarginX-nMarginX);
int nChartSizeY = (pInfo->m_rectDraw.Height()-nMarginY-nMarginY);
Graphics graphics(pDC->m_hDC);
int nGdiPlusLogPx = (int) graphics.GetDpiX();
int nGdiPlusLogPy = (int) graphics.GetDpiY();
// Necessary when sending to actual printer //
if (!pInfo->m_bPreview)
{
graphics.SetPageUnit(UnitPixel);
graphics.SetPageScale(((REAL) nGdiPlusLogPx / (REAL) nLogPx));
}
float fX = (float) nLogPx / 300.0F; // 300 can be upto 400, any higher, may fail.
int nDPI300x = (int) ( (float) nLogPx / fX );
int nExt300x = (int) ( (float) nChartSizeX / fX );
float fY = (float) nLogPy / 300.0F;
int nDPI300y = (int) ( (float) nLogPy / fY );
int nExt300y = (int) ( (float) nChartSizeY / fY );
// Setting DPIs //
PEnset(m_hPE, PEP_nDPIX, nDPI300x);
PEnset(m_hPE, PEP_nDPIY, nDPI300y);
IStream* pstream = NULL;
HGLOBAL hPngData = NULL;
POINT pt;
pt.x = nExt300x;
pt.y = nExt300y;
// Create PNG as a Global Memory Object //
PEcopypngtohglobal(m_hPE, &pt, &hPngData, pDC->m_hDC);
// Create Stream based off Global Memory //
CreateStreamOnHGlobal(hPngData, FALSE, &pstream);
// Create Bitmap based off Stream //
Bitmap bm(pstream);
// Create a Rect object that specifies the destination of the image.
Rect destRect(nMarginX, nMarginY, nChartSizeX, nChartSizeY );
graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
graphics.DrawImage(&bm, destRect);
GdiplusShutdown( gdiplusToken );
// Free Png Global Memory Object //
::GlobalFree(hPngData);
///////////////////////////////////
// End ProEssentials Image Logic //
///////////////////////////////////
// Restore the mapping mode
pDC->SetMapMode(oldMM);
// Restore DC //
pDC->RestoreDC(nStartingDC);
// ReSetting DPIs //
PEnset(m_hPE, PEP_nDPIX, nOldDPIx);
PEnset(m_hPE, PEP_nDPIY, nOldDPIy);
// Reset the image to match control's size //
PEresetimage(m_hPE, 0, 0);
}
//////////////////////////////////////////////////////////////////////////////////
// Complex Method, prepares as a bitmap, or sends commands directly to printer. //
//////////////////////////////////////////////////////////////////////////////////
void CPpreviewView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
HMETAFILE hMeta = 0;
int oldMM = 0;
// Note, if you want to always support real clipping without use of DisableClipping or ClipAxesInMetafiles,
// set this property to TRUE will force StretchBlt in all Preview cases.
// Setting FALSE allows an optional method of previewing, but we recommend leaving this TRUE if possible.
BOOL bStretchBlt = TRUE;
// This property will possibly disable clipping and set ClipAxesInMetafiles True to achieve clipping without
// using an actual clipping region. ClipAxesInMetafiles has a side effect of potentially corrupting the slope
// of a data-line when it extends outside the chart. As long as there's data near the zoom extents, there
// won't be a problem. For charts with not much data, and you need to print a zoomed chart, it may be best to
// set bStretchBlt = True.
BOOL bDisableClipping = FALSE;
// TIP! If switching mapping modes (OR VIEWPORTEXT or VIEWPORTORG) more than once,
// it's a good idea to use SaveDC, and then RestoreDC between these changes.
// PrintPreview in PreviewMode changes mapping mode to Anisotropic and changes viewportorg and extents
// anytime you do any mappingmode of viewport adjustments.
int nStartingDC = pDC->SaveDC();
// CreateCompatibleBitmap fails with large extents, so we need a scale factor to improve reliability .
// This can cause some tiled bitmaps to tile less often in screen preview than on printer.
// Sad that MS didn't provide a PrintPreview func to learn destination screen viewport size.
// Optional, to work around WYSIWYG issue and bitmaps, you could have alternate bitmaps used only for
// PrintPreview. If nStretchFudge=2, any alternate bmps should be 1/2 the size but represent the same image.
int nStretchFudge = 2;
//smaller number (2,3) improves bitmap WYSIWYG, larger number (3,4) improves reliability and memory needs.
// Get Device DPI Resolutions //
int nLogPx = ::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSX);
int nLogPy = ::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSY);
// Added a margin in case you want header/footer info. Set to 0 to consume full page.
int nMarginX = 0; // or nLogPx or as needed;
int nMarginY = nLogPy / 2; // 1/2 an Inch.
// Setting DPIX and DPIY is recommended, we set these below as needed. //
int nOldDPIx = PEnget(m_hPE, PEP_nDPIX);
int nOldDPIy = PEnget(m_hPE, PEP_nDPIY);
// ProEssentials uses mapping mode = Text, so there is likely no need to adjust mapping mode further //
oldMM = pDC->SetMapMode(MM_TEXT);
///////////////////////////////////
// If drawing Header, do so here //
///////////////////////////////////
pDC->SetTextAlign(TA_LEFT);
pDC->TextOut(0, 0, "Left Justified header text.");
pDC->SetTextAlign(TA_CENTER);
pDC->TextOut(pInfo->m_rectDraw.Width()/2, 0, "Centered header text.");
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(pInfo->m_rectDraw.Width(), 0, "Right Justified header text.");
///////////////////////////////////
// If drawing Footer, do so here //
///////////////////////////////////
pDC->SetTextAlign(TA_LEFT | TA_BOTTOM );
pDC->TextOut(0, pInfo->m_rectDraw.Height(), "Left Justified footer text.");
pDC->SetTextAlign(TA_CENTER | TA_BOTTOM );
pDC->TextOut(pInfo->m_rectDraw.Width()/2, pInfo->m_rectDraw.Height(), "Centered footer text.");
pDC->SetTextAlign(TA_RIGHT | TA_BOTTOM );
pDC->TextOut(pInfo->m_rectDraw.Width(), pInfo->m_rectDraw.Height(), "Right Justified footer text.");
/////////////////////////////////////
// Start ProEssentials Image Logic //
/////////////////////////////////////
if (pInfo->m_bPreview)
{
if (bStretchBlt || (PEnget(m_hPE, PEP_nVIEWINGSTYLE) == PEVS_COLOR &&
PEnget(m_hPE, PEP_bBITMAPGRADIENTMODE) == TRUE ))
{
bStretchBlt = TRUE;
}
else
bDisableClipping = TRUE;
}
if (bDisableClipping)
{
PEnset(m_hPE, PEP_bDISABLECLIPPING, TRUE);
// PrintPreview wont work without due to MFC Preview not supporting clipping regions
PEnset(m_hPE, PEP_bCLIPAXESINMETAFILES, TRUE);
// Helps clip axes when normal clipping regions can't be relied on.
}
// Uncomment only if you adjusted mapping mode for header/footer text //
//pDC->SetMapMode(MM_TEXT);
// Set viewport Extents //
pDC->SetViewportOrg(nMarginX, nMarginY);
pDC->SetViewportExt(pInfo->m_rectDraw.Width()-nMarginX-nMarginX, pInfo->m_rectDraw.Height()-nMarginY-nMarginY);
if (bStretchBlt)
{
//////////////////////////////////////////////////////////////////////
// bStretchBlt is TRUE, prepare a bitmap to StretchBlt to target DC //
//////////////////////////////////////////////////////////////////////
// Setting DPIs but factor in nStretchFudge //
PEnset(m_hPE, PEP_nDPIX, nLogPx / nStretchFudge);
PEnset(m_hPE, PEP_nDPIY, nLogPy / nStretchFudge);
HDC hCDC = ::GetDC(this->GetSafeHwnd());
HDC hDC = ::CreateCompatibleDC(hCDC);
HBITMAP hBitmap = ::CreateCompatibleBitmap(hCDC,
(pInfo->m_rectDraw.Width()-nMarginX-nMarginX)/nStretchFudge,
(pInfo->m_rectDraw.Height()-nMarginY-nMarginY)/nStretchFudge);
HGDIOBJ hOldBmp = ::SelectObject(hDC, hBitmap);
// Has to be called before PEbitmapgradients, builds image to be played to DC //
PEresetimageEx(m_hPE, (pInfo->m_rectDraw.Width()-nMarginX-nMarginX)/nStretchFudge,
(pInfo->m_rectDraw.Height()-nMarginY-nMarginY)/nStretchFudge, 0, 0);
int oldmode = ::SetMapMode(hDC, MM_TEXT);
::SetViewportExtEx(hDC, (pInfo->m_rectDraw.Width()-nMarginX-nMarginX)/nStretchFudge,
(pInfo->m_rectDraw.Height()-nMarginY-nMarginY)/nStretchFudge, NULL);
if (PEnget(m_hPE, PEP_nVIEWINGSTYLE) == PEVS_COLOR && PEnget(m_hPE, PEP_bBITMAPGRADIENTMODE) == TRUE)
{
// Prepare a RECT r which has same coordinates used with SetViewportExt above.
RECT r;
r.left = 0; r.top = 0;
r.right = (pInfo->m_rectDraw.Width()-nMarginX-nMarginX)/nStretchFudge;
r.bottom = (pInfo->m_rectDraw.Height()-nMarginY-nMarginY)/nStretchFudge;
PEbitmapandgradients(m_hPE, hDC, hDC, &r);
}
// Retrieve the handle to the prepared metafile //
hMeta = PEgetmeta(m_hPE);
// Send image to device context //
PEplaymetafile(m_hPE, hDC, hMeta );
// Stretch Blit image to screen dc //
int nOldMode = ::SetStretchBltMode(pDC->m_hDC, HALFTONE);
::StretchBlt(pDC->m_hDC, 0, 0, pInfo->m_rectDraw.Width()-nMarginX-nMarginX,
pInfo->m_rectDraw.Height()-nMarginY-nMarginY, hDC, 0, 0,
(pInfo->m_rectDraw.Width()-nMarginX-nMarginX)/nStretchFudge,
(pInfo->m_rectDraw.Height()-nMarginY-nMarginY)/nStretchFudge, SRCCOPY);
::SetStretchBltMode(pDC->m_hDC, nOldMode);
// Restore bmpdc mapmode //
::SetMapMode(hDC, oldmode);
// Clean up resources //
::SelectObject(hDC, hOldBmp);
::DeleteObject(hBitmap);
::DeleteDC(hDC);
::ReleaseDC(this->GetSafeHwnd(), hCDC);
}
else
{
///////////////////////////////////////////////////////////////////////////
// bStretchBlt is FALSE, use simple PEplaymetafile directly to target DC //
///////////////////////////////////////////////////////////////////////////
// Setting DPIs is recommended //
PEnset(m_hPE, PEP_nDPIX, nLogPx);
PEnset(m_hPE, PEP_nDPIY, nLogPy);
// Has to be called before PEbitmapgradients, builds image to be played to DC //
PEresetimageEx(m_hPE, pInfo->m_rectDraw.Width()-nMarginX-nMarginX,
pInfo->m_rectDraw.Height()-nMarginY-nMarginY, nMarginX, nMarginY);
// Optional Section, only needed if setting BitmapGradientMode = True while printing //
// If chart is in color bitmap mode, print gradients and background bitmaps.
if (PEnget(m_hPE, PEP_nVIEWINGSTYLE) == PEVS_COLOR && PEnget(m_hPE, PEP_bBITMAPGRADIENTMODE) == TRUE)
{
// Prepare a RECT r which has same coordinates used with SetViewportExt above.
RECT r;
r.left = 0; r.top = 0;
r.right = pInfo->m_rectDraw.Width()-nMarginX-nMarginX;
r.bottom = pInfo->m_rectDraw.Height()-nMarginY-nMarginY;
PEbitmapandgradients(m_hPE, pDC->m_hDC, pDC->m_hDC, &r);
}
// Retrieve the handle to the prepared metafile //
hMeta = PEgetmeta(m_hPE);
// Send image to device context //
PEplaymetafile(m_hPE, pDC->m_hDC, hMeta);
}
// Restore the mapping mode
pDC->SetMapMode(oldMM);
// Restore DC //
pDC->RestoreDC(nStartingDC);
// ReSetting DPIs //
PEnset(m_hPE, PEP_nDPIX, nOldDPIx);
PEnset(m_hPE, PEP_nDPIY, nOldDPIy);
// Reset the image to match control's size //
PEresetimage(m_hPE, 0, 0);
if (bDisableClipping)
{
PEnset(m_hPE, PEP_bDISABLECLIPPING, FALSE);
PEnset(m_hPE, PEP_bCLIPAXESINMETAFILES, FALSE);
}
|