Go Back  Xtreme Visual Basic Talk > Legacy Visual Basic (VB 4/5/6) > Interface and Graphics > GDI+ Printer Metrics


Reply
 
Thread Tools Display Modes
  #1  
Old 07-01-2012, 11:42 PM
mms mms is offline
Ultimate Contributor
 
Join Date: Jul 2002
Location: Hamilton, Ontario
Posts: 1,665
Default GDI+ Printer Metrics


By trial and error this is the largest rectangle I can draw on a printed page.

stat = GdipDrawRectangle(graphics, pen, 0, 0, 799, 1066)

Trying to get these values programatically, I have to use this code
Code:
stat = GdipGetDpiX(graphics, DpiX)
stat = GdipGetDpiY(graphics, DpiY)

pw = GetDeviceCaps(hdcPrint, PHYSICALWIDTH)
ph = GetDeviceCaps(hdcPrint, PHYSICALHEIGHT)

pox = GetDeviceCaps(hdcPrint, PHYSICALOFFSETX)
poy = GetDeviceCaps(hdcPrint, PHYSICALOFFSETY)

MsgBox "printable width = " & (pw - pox - pox) / DpiX * 100
MsgBox "printable height = " & (ph - poy - poy) / DpiY * 100
I don't understand why I have to divide by DpiX * 100 and DpiY * 100
to get the values I am expecting??
Reply With Quote
  #2  
Old 07-02-2012, 04:10 PM
hDC_0 hDC_0 is offline
Contributor

* Expert *
 
Join Date: Feb 2004
Posts: 522
Default mms meets Windows Coordinate Systems

Quote:
Originally Posted by mms
I don't understand why I have to divide by DpiX * 100 and DpiY * 100
to get the values I am expecting??
<*sigh*>
mms you have gone deeper into the VB6 GDI+ than anyone else except OnErr0r himself,
but I really don't think you have a good (full) grasp of how complicated
things are at the lower levels of how Windows handles graphics,
and translates them between different device contexts.

That complexity is why most of the GDI+ examples,
(with the exception of the VB6 code posted in OnErr0r's KB GDI+ threads) are C/C++ code.
That's really the only language that the MSDN uses to document this stuff.
(I included an updated MSDN GDI+ Flat reference link below)

Oh well..I'll try to help you out a little..

Do you remember the last thread where you used the GdipGetDpiX function?

In that thread passel had a post where he tried to indicate (or at least hint at) the possible
"under the hood" complexity you were missing.

passel's explanation was targeted at where the device in question was a screen (monitor).
However there is also a transformation (translation) going on when considering
that device in question might be a printer.

Some links:
MSDN GDI+ Graphics Functions Page
MSDN Graphics.GetDpiX method page
Graphics.SetPageUnit method page
Graphics.SetPageUnit method alt page
..which says:
Quote:
The Graphics::SetPageUnit method sets the unit of measure for this Graphics object.
The page unit belongs to the page transformation, which converts page coordinates to device coordinates.
Do you see the word "transformation"?
This should be setting off every programming "spider-y sense" you have!

Of course this immediately brings to mind (for me among my thousands of remember bookmarks),
the MSDN "Types of Coordinate Systems" page.
Here's an excerpt:
Quote:
The coordinates of the endpoints of your line in the three coordinate spaces are as follows:
World (0, 0) to (160, 80)
Page (100, 50) to (260, 130)
Device (100, 50) to (260, 130)
Note that the page coordinate space has its origin at the upper-left corner of the client area; this will always be the case. Also note that because the unit of measure is the pixel, the device coordinates are the same as the page coordinates. If you set the unit of measure to something other than pixels (for example, inches), then the device coordinates will be different from the page coordinates.

The transformation that maps world coordinates to page coordinates is called the world transformation and is maintained by a Graphics object. In the previous example, the world transformation is a translation
100 units in the x direction and 50 units in the y direction. The following example sets the world transformation of a Graphics object and then uses that Graphics object to draw the line shown in the previous figure.

myGraphics.TranslateTransform(100.0f, 50.0f);
myGraphics.DrawLine(&myPen, 0, 0, 160, 80);

The transformation that maps page coordinates to device coordinates is called the page transformation. The Graphics class provides four methods for manipulating and inspecting the page transformation: Graphics::SetPageUnit, Graphics::GetPageUnit, Graphics::SetPageScale, and Graphics::GetPageScale. The Graphics class also provides two methods, Graphics::GetDpiX and Graphics::GetDpiY, for examining the horizontal and vertical dots per inch of the display device.

You can use the Graphics::SetPageUnit method of the Graphics class to specify a unit of measure.
..and if you are not completely comfortable and familiar with doing transforms,
you should study the links off the
MSDN "Coordinate Systems and Transformations" page,
including the MSDN "Matrix Representation of Transformations" page.

I know you probably already have the MSDN GDI+ Flat Reference page bookmarked,
but I'll give a link for others who may happen upon this page,
because the old link OnErr0r used to give out in some of the archived threads (like this one on GDI+ printing) has changed.

So according to this CodeGuru page the sequence of events for GDI+ printing might be:
Quote:
- graphics.SetPageUnit(UnitDocument);
- Calculate bitmap dimensions in UnitDocument
- Fill a Rect or a RectF rcDest with offsets and dimensions.
- graphics.DrawImage(pBitmap, rcDest, 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
If you end up having to deal with DEVMODEs then this CodeProject "Printing using GDI+" tips page may provide some insights.
Quote:
edit: The code for VB6 DEVMODE structures (like dmPaperSize; dmPaperLength; dmPaperWidth; dmScale; dmYResolution) is here
and on this off forum page.

In closing though, I want to tell you mms,
that you are really deep into the "nitty gritty" low level stuff
that usually only C/C++ developers using GDI+ get into,
so you may find very little VB6 code out in the open on the internet, for what you are trying to do,
so be prepared to do a lot of research, and some code translation,
(plus a fair amount of trial and error for GDI+ printer code --might want to
stock up on the printer paper and ink/toner).

Last edited by hDC_0; 07-02-2012 at 04:56 PM.
Reply With Quote
  #3  
Old 07-03-2012, 12:01 AM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,714
Default

Did you look at the values you were getting.
(pw - pox - pox) / DpiX

pw and pox should be printer pixels.
DpiX should be pixels per inch.

So the result of the above equation would be in inches.

Multiplying inches by 100 apparently gives you the numbers you're looking for.

My question is how did you get the graphics object to use such a small rectangle to fill the page?
Normally the default would be multiple 1000's X 1000's for a printer.
Perhaps you created the graphics object to be compatible with your screen, so the DPI is matching your screen (say 96 dpi) and your coordinate system is being stretched on the printer to match a 96 dpi scale.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #4  
Old 07-03-2012, 07:11 AM
mms mms is offline
Ultimate Contributor
 
Join Date: Jul 2002
Location: Hamilton, Ontario
Posts: 1,665
Default

hDC_0
I had forgotten about that old thread http://www.xtremevbtalk.com/showthread.php?t=322315 (I'm always having problems)

Quote:
so be prepared to do a lot of research, and some code translation,
(plus a fair amount of trial and error for GDI+ printer code --might want to
stock up on the printer paper and ink/toner).
I've already gone through one 500 sheet ream

passel
Quote:
Did you look at the values you were getting.
(pw - pox - pox) / DpiX
Yes, that part made sence (=8") and at 600 dpi was would be 4800 pixels,
so was expecting to use this with GDI+ calls

Quote:
My question is how did you get the graphics object to use such a small rectangle to fill the page?
Normally the default would be multiple 1000's X 1000's for a printer.
Perhaps you created the graphics object to be compatible with your screen, so the DPI is matching your screen (say 96 dpi) and your coordinate system is being stretched on the printer to match a 96 dpi scale.
I checked to make sure I didn't somehow create it based on screen; I didn't.

To be sure, I created a clean project, this is the only code in it, and still, max rectangle that can be drawn is 799 X 1066
Code:
Private Sub Command1_Click()
    
    Dim myDocInfo As DOCINFO
    myDocInfo.cbSize = Len(myDocInfo)
    myDocInfo.lpszDocName = "GdiplusPrint"
    
    ' Get a device context for the printer.
    Dim hdcPrint As Long
    hdcPrint = CreateDC(Printer.DriverName, Printer.DeviceName, 0, 0)

    ' Initialize the graphics class
    Dim graphics As Long
    stat = GdipCreateFromHDC(hdcPrint, graphics)
    stat = GdipSetSmoothingMode(graphics, SmoothingModeHighQuality)

    ' Create Pen object
    Dim pen As Long
    stat = GdipCreatePen1(&HFF000000, 1, UnitPixel, pen)

    ' Print
        
    Call StartDoc(hdcPrint, myDocInfo)
    Call StartPage(hdcPrint)

    stat = GdipDrawRectangle(graphics, pen, 0, 0, 799, 1066)

    Call EndPage(hdcPrint)
    Call EndDoc(hdcPrint)

    ' Cleanup GDI+ objects
    stat = GdipDeletePen(pen)
    stat = GdipDeleteGraphics(graphics)
    
    ' Cleanup GDI objects
    Call DeleteDC(hdcPrint)

End Sub
Reply With Quote
  #5  
Old 07-03-2012, 10:13 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,714
Default

Ok, I haven't done any printing with GDI+ as far as I know, so haven't tried anything.
Apparently you've "discovered" something that is by design, but seems to be remarkably hard to find documentation on. {someone will probably point out it's a known basic GDI+ feature, but I had a hard time finding a reference}.

A CS professor at the local university in town has a series of slides in a pdf file online, and one of them states {I added the bolding}:
"Video and Printer Coordinates
•Device coordinates: x-axis to the right, y -axis down
•Video uses pixel units
–Resolution of most video display modes is about 100
dpi (dots per inch)
•For printer, dots per inch, but under the GDI+ …
–Coordinates passed to its Graphics drawing functions
are interpreted as 0.01 inch units, regardless of printer

•So for most applications we’ll get about the same
results when we use the same coordinates to draw
on a video Graphics object and a printer Graphics
object"

So, it looks like if you use the default Graphics object and don't change the pageUnit or pageScale property of the graphics object, then all printers, regardless of their native resolution will use a coordinate system of .01 inch spacing.

Have you tried setting the PageUnit property of the printer graphics object to Pixel?
I don't have a printer conveniently located at the moment, so I can't play around with it myself.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #6  
Old 07-04-2012, 06:48 AM
mms mms is offline
Ultimate Contributor
 
Join Date: Jul 2002
Location: Hamilton, Ontario
Posts: 1,665
Default

Quote:
•For printer, dots per inch, but under the GDI+ …
–Coordinates passed to its Graphics drawing functions
are interpreted as 0.01 inch units, regardless of printer
Good to know.

Quote:
•So for most applications we’ll get about the same
results when we use the same coordinates to draw
on a video Graphics object and a printer Graphics
object
stat = GdipDrawRectangle(graphics, pen, 150, 10, 100, 200)
draws a rectangle exactly 1" X 2" on both screen and printer.

Quote:
Have you tried setting the PageUnit property of the printer graphics object to Pixel?
Setting the PageUnit property of the printer graphics object to UnitPixel
causes a 3/16" X 3/8" rectangle to be drawn on printed page.

Checking the default PageUnit property, I get UnitDisplay (whatever that means)
for both printer and screen graphics objects.

Given all of the above, then the following is correct?
Code:
hr = GetDeviceCaps(hdcPrint, HORZRES)
vr = GetDeviceCaps(hdcPrint, VERTRES)

lpx = GetDeviceCaps(hdcPrint, LOGPIXELSX)
lpy = GetDeviceCaps(hdcPrint, LOGPIXELSY)
    
printableWidth = hr / lpx * 100
printableHeight = vr / lpy * 100
Reply With Quote
  #7  
Old 07-04-2012, 10:29 AM
mms mms is offline
Ultimate Contributor
 
Join Date: Jul 2002
Location: Hamilton, Ontario
Posts: 1,665
Default

Quote:
Apparently you've "discovered" something that is by design, but seems to be remarkably hard to find documentation on.
Not something as significant as CERN's (& Fermilab's) annoucement today confirming the discovery of the Higgs boson particle, but still a discovery
Reply With Quote
  #8  
Old 07-04-2012, 05:59 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,714
Default

Quote:
Originally Posted by mms View Post
...
Setting the PageUnit property of the printer graphics object to UnitPixel
causes a 3/16" X 3/8" rectangle to be drawn on printed page.
...
Technically, I would have expected 3/18" X 3/9" ,aka, 1/6" X 1/3" assuming you're drawing a 100x200 rectangle on a 600 dpi printer.

As for the rest, I'm not familiar with the values being returned by the functions you're using, and am not taking time to get a printer and investigate, so I won't attempt to comment on the validity of the code.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
 
 
-->