I've followed Microsoft's tutorial on creating a Device Context, and I've tried looking around the internet for a decent source (apparently, MFC is a mystical thing). The following successfully prints out "Hello, World!"; except it's extremely tiny.
How can I send a CImage to the printer, rather than text? And how could I get the text's size to be bigger than a couple millimeters? I've scoured MSDN, but everything is either outdated (like the example code I am using), or just not well documented.
// get the default printer
CPrintDialog dlg(FALSE);
dlg.GetDefaults();
// is a default printer set up?
HDC hdcPrinter = dlg.GetPrinterDC();
if (hdcPrinter == NULL)
{
//MessageBox(_T("Buy a printer!"));
}
else
{
// create a CDC and attach it to the default printer
CDC dcPrinter;
dcPrinter.Attach(hdcPrinter);
// call StartDoc() to begin printing
DOCINFO docinfo;
memset(&docinfo, 0, sizeof(docinfo));
docinfo.cbSize = sizeof(docinfo);
docinfo.lpszDocName = _T("CDC::StartDoc() Code Fragment");
// if it fails, complain and exit gracefully
if (dcPrinter.StartDoc(&docinfo) < 0)
{
//MessageBox(_T("Printer wouldn't initalize"));
}
else
{
// start a page
if (dcPrinter.StartPage() < 0)
{
//MessageBox(_T("Could not start page"));
dcPrinter.AbortDoc();
}
else
{
// actually do some printing
//CGdiObject* pOldFont = dcPrinter.SelectStockObject(SYSTEM_FONT);
dcPrinter.SetMapMode(MM_HIENGLISH);
auto font = CreateFont(
3'000, // nHeight
1'500, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Arial")); // lpszFacename
dcPrinter.SelectObject(&font);
dcPrinter.TextOut(450, 450, _T("Hello World!"), 12);
dcPrinter.EndPage();
dcPrinter.EndDoc();
//dcPrinter.SelectObject(pOldFont);
}
}
}
Use CFont::CreatePointFont() or CFont::CreatePointFontIndirect() to create a font that is reasonable. Most printers are 600 DPI. Most screens are 96 DPI. A 12 point font on the screen is basically a 2 point font and illegible on a printer.
Create the font and select it into your DC. Do not forget to select it out of the DC after using it and before destroying your DC (CDC class). (The CDC destructor automatically deletes the HDC).
I have used the following to successfully print "Hello World!" and "Have a Nice Day!" to the right of a 200x200 monochrome bitmap (MyLogo.bmp) placed at the origin of the printer page (I am using a black & white thermal printer):
The three indented lines highlight all that is required to render a
CImage
on my printer. Vary the parameter inCreatePointFont()
to size the (otherwise tiny) text to suit.Here is the problem:
MM_TEXT
maps one logical point to one device point; considering typical resolution of 600 DPI for a printer, your stuff will be few times smaller that on the screen.Use MM_HIENGLISH or some other device-independent mode; here is MSDN link.
Tiny Text Problem
The problem is that, by default, the size of a font is specified in device-dependent units and printers are generally much higher resolution that a screen. So if you've created a font that is 20 pixels high on the screen (which might have 96 pixels per inch) when you try to use that font on a printer, which maybe has 300 or 600 dots per inch, your text looks really small.
As another answer shows, one idea is to change the mapping mode so that the printer uses units that are closer to what is on the screen.
An alternative way is to create a new font with an appropriate size (the lfHeight field in the LOGFONT structure) based on the DPI of the printer, which you can determine with the
GetDeviceCaps
function. This can be handy if you want a particular font size, like 14 point text.Sending a CImage
I don't use MFC, but it looks like you can just call
CImage::StretchBlt
with the printer DC. Once again, you'll probably have to take the printer's much higher resolution into account when you choose the target coordinates.