Visit Gigasoft's Web Site
ProEssentials v8 Help

Chapter 5: DLL Printing within VC/MFC

 

You can print ProEssentials based images either via simple DLL function calls or via low level API calls.

 

Simple Printing with Dialog Intervention:

BOOL PElaunchprintdialog(hObject, bFullPage, lpPoint)

HWND 

hObject

Handle returned from PEcreate.

BOOL 

bFullPage

Controls page size. Use 0 or 1

POINT FAR* 

lpPoint

Pointer to POINT struct holding size.

 

This function invokes a modal print dialog. If bFullPage equals TRUE then lpPoint is ignored. If bFullPage equals FALSE then lpPoint must point to a POINT that holds the size (in 1/100th millimeter units) of the image to export.

 

PrintStyleControl

This property controls the visibility of radio buttons and the option selected for printing on the print dialog.

Constant

Description

PEPSC_NONE (0)

No control over Viewing Style

PEPSC_CURRENT_STYLE(1)

Current Viewing Style

PEPSC_DEFAULT_MONO(2)

Switch to Mono Viewing Style

 

DefOrientation

This property controls the default orientation of the printer paper when printing a ProEssentials object.

Constant

Description

PEDO_DRIVERDEFAULT(0)

Use the printer driver

PEDO_LANDSCAPE(1)

Landscape orientation.

PEDO_PORTRAIT(2)

Portrait orientation.

 

PrintDpi

Controls the target resolution in DotsPerInch when printing. If set to Zero, graphic commands are sent directly to the printer:

Value

Description

0

If zero, the chart's image is sent to the printer via the actual graphic primitives and final resolution is based upon the printer's driver settings. This produces the sharpest graphics and may be the best setting when printing with ViewingStyle set to MonoChrome, BitmapGradientMode = False

100
---
600

If non zero, the chart image is prepared as a bitmap (at the specified PrintDpi) and this bitmap is sent to the printer. The default and recommend setting is 300. 300 produces a good looking image while not requiring a huge amount of memory to be sent to the printer.

 

HidePrintDpi

This property controls the visibility of the above PrintDpi end-user setting shown within the ProEssentials built-in print dialog:

Value

Description

TRUE

The End-User can not adjust the PrintDpi setting.

FALSE

The End-User can adjust the PrintDpi setting.

 

 

 

Simple Printing without Dialog Intervention:

BOOL PEprintgraph(hObject, nWidth, nHeight, nOrient)

 

HWND 

hObject

Handle returned from PEcreate.

INT 

nWidth

Width in 1/100th millimeters.

INT 

nHeight

Height in 1/100th millimeters.

INT 

nOrient

0=Driver Default, 1=Landscape, 2=Portrait.

 

This function prints the objects image to the operating systems default printer. If nWidth and nHeight are both zero, the image will print full page.

 

 

BOOL PEprintgraphEx(hObject, hDC, nWidth, nHeight, nOriginX, nOriginY)

 

HWND 

hObject

Handle returned from PEcreate.

INT 

hDC

Device Context ready to receive graphic commands, ie, StartDoc, StartPage already called.

INT 

nWidth

Width in 1/100th millimeters.

INT 

nHeight

Height in 1/100th millimeters.

INT 

nOriginX

Top-Left horizontal position in 1/100th millimeters.

INT 

nOriginY

Top-Left vertical position in 1/100th millimeters.

 

This function prints the objects image to a target device context. This function works great with a Printer DC supplied by MFCs standard print dialog, however, due to issues with MFC's print preview, it will not work for the screen preview mechanism. See code below for code that will work with MFC's print preview.

 

 

 

Low Level Printing:

Within a MFC based project, override CPpreviewView::OnPrint with the following code.

 

Note MFC's PrintPreview doesn't have the best reputation due to many bugs/issues. Though, the code below shows some examples of how ProEssentials can be printed within MFCs print preview mechanism. It's a tedious process working with MFCs print preview, but it is possible.

 

/////////////////////////////////////////////////////

// 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);
}

 

 

TIP

If your charts will be in a zoomed state when printed, then you'll want to create a clipping region

and select it into the DC prior to the PlayMetaFile call. However MFC's Preview does not support clipping.