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
| Вернуться в корень Архива
|