Printing 'Postage Stamps' Problem
George Grant -- ggrant@ns.net Saturday, April 06, 1996 Environment: VC4.0, Win95 I've spent hours trying to figure this out so I wouldn't be bothering = everybody with a dumb question, but I need to ask, so here goes: I've spent weeks getting my CScrollView set up just right in MM_TEXT = mode with all the items I'm drawing prefectly aligned, neat little = masked icons, etc... So now it's time to print, and I think "Great! MFC = lets me print with just an OnDraw()!!" So I chuck in a couple of lines and add a Print Preview menu item, and = my CScrollView is printed.... in the top left corner in a = 1-inch-by-1-inch area, suitable for use as a POSTAGE STAMP. I think = there's a conflict between the MM_TEXT mode and the mode for the = printer, but I have _no_ idea what to do now. I think my employer would take a pretty dim view of this as our new = document format, even though we would save a hell of a lot of money on = paper. So, any and all ideas would be GREATLY appeciated... If I have to = re-wire all the drawing commands, I'm going to blow our deadline BIG = TIME.....-George
Daniel Rosengarten -- tbird@bw.webex.net Sunday, April 07, 1996 [Mini-digest: 5 responses] Mapping modes - I've had similar problems. The reason you are getting "postage stamp" size output is due to the different mapping modes used. You are using MM_TEXT (i.e. 1 pixel = 1 unit) in your screen view, but using MM_TWIPS (1440 units per inch (20*72 points)). If you weren't using a CScrollView then the very quick way out is to set the mapping mode to MM_ANISOTROPIC ( an example is in Petzold's book) and seting the window and viewport. But alas, it isn't supported in CScollView. There are a couple of quick & dirty solutions. 1)At the beginning of your on draw define a scaling factor m_scaleX,m_scaleY Use: // gives # units per inch LONG m_unitsPerInchX=pDC->GetDeviceCaps(LOGPIXELSX); LONGm_unitsPerInchY=pDC->GetDeviceCaps(LOGPIXELSY); // gives # units per point LONG lUnitsPerPointX=MulDiv(1, pDC->GetDeviceCaps(LOGPIXELSX), 72); LONG lUnitsPerPointY=MulDiv(1, pDC->GetDeviceCaps(LOGPIXELSY), 72); // for your reference MulDiv (A,B,C) = A*B/C in LONGS In your code, all point size references just multiply it by respective scaling factor. 2) set the mapping mode to MM_TWIPS and change your #'s. 3) set the mapping mode to MM_TWIPS and put in the scaling factor Hope this helps Daniel Rosengarten -----From: "Dan McNerthney"I solved this problem by setting the map mode to scale the output to the correct size, depending upon the paper size and the original window size. Here's the general idea: in the OnDraw function: if ( pDC->IsPrinting() ) { pDC->SetMapMode(MM_ANISOTROPIC); int iPageWidth = pDC->GetDeviceCaps(HORZRES); int iPageHeight = pDC->GetDeviceCaps(VERTRES); pDC->SetWindowExt(m_sizeWindow); pDC->SetViewportExt(iPageWidth,iPageHeight); } The variable m_sizeWindow is the size of your CView and should be set in the OnSize member function. -----From: Brad Wilson MM_TEXT is a pixel-oriented mode. 1 point =3D 1 pixel. You cannot use = this mode and get WYSIWYG-style results. You'll need to use one of the = measurement- related modes (eg, MM_LOENGLISH, MM_LOMETRIC, etc.), or use one of the Isotropic modes and scale it yourself. Good luck! Brad -- Brad Wilson, Crucial Software crucial@ix.netcom.com +1 (810) = 620-9803 Custom software engineering services for Microsoft Windows NT and = Windows 95 "Some may rise by sin; and some, fall by virtue." -----From: darius@world.std.com (Darius Thabit) In MM_TEXT mode you use device coordinates to locate and dimension things - that basically means pixels. The number of pixels required to get a certain physical dimension on your screen is probably far different than on your printer. If you call CDC::GetDeviceCaps every time you hit OnDraw, you can get the pixel resolution (dots per inch) of the current device (screen or printer) and calculate the appropriate location and dimensions for your various draw items - then your OnDraw will handle screen, print, and print preview (I do this with a formview). Your exact layout - titles, etc - may also be different for screen and print, so you may also want to look at CDC::IsPrinting(). Note that IsPrinting() is TRUE for print and print preview, while GetDeviceCaps() will yield the finer printer resolution only for actual printing. > I think my employer would take a pretty dim view of this as our new = Yeah, managers are like that ... -----From: michael Try MM_ANISOTROPIC instead of MM_TEXT. I've pasted some text from Microsoft's Development Libaray to help explain why. >From January 96 Development Libray CD: Many developers deal with only one mapping mode, MM_TEXT, which maps one logical unit to one device unit. The EZPRINT sample program allows the application to experiment with the MM_ANISOTROPIC mapping mode, which provides full control over coordinate mapping. In the MM_ANISOTROPIC mode, the application sets the window and viewport extents to any desired value. For a comprehensive discussion of mapping modes, see the "Coordinate Mapping" technical article by Ron Gery on the Developer Network CD (look under Technical Articles, Windows Articles, GDI Articles, in the Source index). By default, EZPRINT sets the logical coordinate system, mapping mode, origin, and extents of the printer device context (DC) as follows: SetMapMode(pd.hDC, MM_ANISOTROPIC ); SetWindowOrg(pd.hDC, 0, 0 ); SetWindowExt(pd.hDC, 1000, 1000 ); SetViewportOrg(pd.hDC, PhysicalPage.XOrg, PhysicalPage.YOrg ); SetViewportExt(pd.hDC, PhysicalPage.XExt, PhysicalPage.YExt ); These settings allow you to specify the center of the page as the (500, 500) ordered pair, regardless of paper size and orientation. In this implementation of the MM_ANISOTROPIC mapping mode, one logical unit is mapped to the total number of device units divided by 1000. For example, if the width of a page is 2000 device units, one logical unit maps to 2000/1000, or two device units. Hope this helps. Michael L. Thal Data Tree Corporation voice: (619) 231-3300 fax: (619) 231-3301
djw@arbortext.com Tuesday, April 09, 1996 Most of the replies to the problem of MM_TEXT yielding a postage stamp-sized printed result seem to be suggesting using a different mapping mode. In our application, we had far too much code rendering to the screen using device units, and wanted that code to be unchanged when printing. (A lot of it pre- dated our port to Windows from Unix.) Our solution was to leave the mode alone for screen output, and only change the mode when preparing to print. Obtaining the logical pixels per inch for the screen device context, and the print device context, gives us the ratio we need to scale. The former is always 96 ppi (in Windows), and the latter typically 300 or lately 600. When preparing to print, we then set the mapping mode to MM_ANISOTROPIC; the window extents to the horizontal and vertical ppi's of the screen; the viewport extents to the horizontal and vertical ppi's of the printer; and finally the viewport origin to our calculated left margin. (We leave the vertical origin unchanged, as we already had a parameter to tell our rendering code where to start, vertically. We prefer to leave a thin "margin" even when rendering to the screen.) From that point on, the code that knows how to render a document to the screen can run as always, oblivious to the underlying changes to scale to the printer's pixels per inch and the translation to leave the desired margins. It _is_ necessary for the rendering code to know how wide a space it's allowed to used for each line, and how much vertical space it can fill. As long as those values are parameters, rather than the rendering code checking the window extents directly, the code will behave as if the printed page is just a big window. One comment on setting the extents: my code is effectively concerned only with the _ratio_ of the screen to printer ppi's. Petzold says (third edition -- I haven't looked this up in the new edition) that that's ok. I recall that assumption biting me once, however, when I was doing some graphics scaling code. It might be safer to multiply the ppi values by the desired inches. E.g. if you're rendering 10 inch wide output, use 960 and 3000 for the window and viewport extents rather than 96 and 300. When we're starting and ending a page, in the printing-specific code, we draw any header and footer lines (page number, and various other optional information). We assume that a y-coordinate of zero is the top of the printable area. The VERTRES value from GetDeviceCaps tells you the height of the printable area, which you can scale back to the MM_TEXT (screen) units, to figure out where you can place a footer line. There are obviously multiple ways to skin this cat, depending on what fits best in your application. I'm sure the other suggestions work just fine. What I've described above was the most convenient in our particular situation. Dave Wilson djw@arbortext.com ArborText Inc. Ann Arbor Michigan
Jose Lamas RЎos -- JLR@ARTECH.COM.UY Tuesday, April 09, 1996 I think the correct (and the only needed) place where to fix this is in the OnPrepareDC(). When you use MM_TEXT, each logical unit is equivalent to 1 pixel in your device. Your screen will typically have 96 pixels per "logical inch (1)" while you may have 300 pixels per inch in your printer. If you ask your device context to draw a line with a length of 96 logical units, it converts it to 96 devices units (MM_TEXT implies 1 logical unit = 1 device unit), and you will see in your typical screen a line with a length of one logical inch. However, if your printer has a 300 pixels per inch resolution, you will see a line of aprox. 1/3 inch. Fortunately, I think there's an easy way to correct your problem. Try with the following code: void CYourView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { // allow the base class do its job CScrollView::OnPrepareDC(pDC, pInfo); if (pInfo) // are we printing/print previewing? { pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX),pDC->GetDeviceC aps(LOGPIXELSY)); HDC hDC = ::GetDC(NULL); CSize szDisplayCap(96,96); if (hDC) { szDisplayCap.cx = ::GetDeviceCaps(hDC,LOGPIXELSX); szDisplayCap.cy = ::GetDeviceCaps(hDC,LOGPIXELSY); ::ReleaseDC(NULL,hDC); } pDC->SetWindowExt(szDisplayCap); } } This worked fine in my project and should also work in yours. FYI: The OnPrepareDC() is "called by the framework before the OnDraw member function is called for screen display and before the OnPrint member function is called for each page during printing or print preview" (from MFC help). (1) Windows use the "logical inch" concept for screen devices in order to provide better font readability (a logical inch is a little longer than the physical inch). For printer devices the physical and logical inches are equal. Hope this helps. ---------- From: George Grant To: 'mfc-l@netcom.com' Subject: Printing "Postage Stamps" Problem Date: Sunday 7 de April de 1996 2:54 Environment: VC4.0, Win95 I've spent hours trying to figure this out so I wouldn't be bothering everybody with a dumb question, but I need to ask, so here goes: I've spent weeks getting my CScrollView set up just right in MM_TEXT mode with all the items I'm drawing prefectly aligned, neat little masked icons, etc... So now it's time to print, and I think "Great! MFC lets me print with just an OnDraw()!!" So I chuck in a couple of lines and add a Print Preview menu item, and my CScrollView is printed.... in the top left corner in a 1-inch-by-1-inch area, suitable for use as a POSTAGE STAMP. I think there's a conflict between the MM_TEXT mode and the mode for the printer, but I have _no_ idea what to do now. I think my employer would take a pretty dim view of this as our new document format, even though we would save a hell of a lot of money on paper. So, any and all ideas would be GREATLY appeciated... If I have to re-wire all the drawing commands, I'm going to blow our deadline BIG TIME.....-George
| Вернуться в корень Архива |