Printing to a Printer DC with MFC

匿名 (未验证) 提交于 2019-12-03 01:00:01

问题:

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

回答1:

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.

LOGFONT lf = {0}; lf.lfHeight = -MulDiv(point_size, ::GetDeviceCaps(dcPrinter, LOGPIXELSY), 72); // init other field of lf as you like HFONT hfontPrinter = ::CreateFontIndirect(&lf); HFONT hfontOld = ::SelectObject(hdcPrinter, hfontPrinter);  // now draw to the hdcPrinter  ::SelectObject(hdcPrinter, hfontOld); ::DeleteObject(hfontPrinter);

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.



回答2:

Here is the problem:

dcPrinter.SetMapMode(MM_TEXT);

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.



回答3:

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).



回答4:

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):

CDC printDC( GetMyPrintDC() );    // e.g. as per original code DOCINFO di( GetMyDocInfo() );     // e.g. as per original code printDC.StartDoc( &di );   ATL::CImage logo;   logo.Load( "MyLogo.bmp" );   const BOOL result( logo.Draw( printDC.GetSafeHdc(), CPoint( 0, 0 ) ) ); CFont myFont, *old; myFont.CreatePointFont(100, "Courier New", &printDC); old = printDC.SelectObject(&myFont); printDC.TextOut( 250, 50, "   Hello World!" ); printDC.TextOut( 250, 150, "Have a nice Day!" ); printDC.SelectObject( old ); myFont.DeleteObject(); printDC.EndPage(); printDC.EndDoc(); printDC.DeleteDC();

The three indented lines highlight all that is required to render a CImage on my printer. Vary the parameter in CreatePointFont() to size the (otherwise tiny) text to suit.



转载请标明出处:Printing to a Printer DC with MFC
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!