-
Jul 18th, 2015, 10:48 PM
#1
Thread Starter
Frenzied Member
[RESOLVED] A better way for Print Page dpi awareness
In Printer Priting mode, I have considered the scale of printer vs screen. I expect I will get the same result because I have scaled the size of Text Rectangle. Printer DPI (normal 600) is larger than screen dpi (normal 96), so the ratio is 600/96 = 6.25.
But the text got slight difference on my preview Window and printer Page. The text is being wrapped in difference. Refer to my attachments.
I think the reason is the scale. Theory is OK but...
How to solve my problem or has a better way for Print Page dpi awareness?
Scale :
If bPrintingView then
SetRect rc, Round(rc.Left + 2 ), Round(rc.Top + 1), Round(rc.Right - 2), Round(rc.Bottom - 1)
ElseIf bPrintingMode Then
SetRect rc, Round(rc.Left + 2 * dpiXRatio), Round(rc.Top + 1* dpiYRatio), Round(rc.Right - 2 * dpiXRatio), Round(rc.Bottom - 1* dpiYRatio)
End If
Sample Code:
the hdc in preview window, it is picturebox hdc,otherwise, it is Printer.hdc
Code:
Dim lhDC As Long
lhDC = GetDC(0)
ScreenLogPixelsX = GetDeviceCaps(lhDC, 88) 'Const LOGPIXELSX As Long = 88 Number of pixels per logical inch along the screen width
ScreenLogPixelsY = GetDeviceCaps(lhDC, 90) 'Const LOGPIXELSY As Long = 90 Number of pixels per logical inch along the screen height
ReleaseDC 0, lhDC
'Logical pixels inch in X and Y
Dim DpiX As Long
Dim DpiY As Long
DpiX = GetDeviceCaps(hPrinterDC, 88) 'LOGPIXELSX= 88 (e.g. Sharp AR-5316: 600,Depend on Printer setting)
DpiY = GetDeviceCaps(hPrinterDC, 90) ' LOGPIXELSY = 90 (e.g. Sharp AR-5316: 600,Depend on Printer setting)
Dim dpiXRatio As Single
Dim dpiYRatio As Single
dpiXRatio = DpiX / ScreenLogPixelsX
dpiYRatio = DpiY / ScreenLogPixelsY
If bPrintingView then
SetRect rc, Round(rc.Left + 2 ), Round(rc.Top + 1), Round(rc.Right - 2), Round(rc.Bottom - 1)
ElseIf bPrintingMode Then
SetRect rc, Round(rc.Left + 2 * dpiXRatio), Round(rc.Top + 1* dpiYRatio), Round(rc.Right - 2 * dpiXRatio), Round(rc.Bottom - 1* dpiYRatio)
End If
Dim oFont As Std_Font
Dim hFont as Long, hOldFont as Long
Dim wFormat As Long
wFormat = &H12810
Set oFont = m_oFont
hFont= CreateFont(-pMulDiv(oFont.Size, GetDeviceCaps(hdc, 90), 72!), 0, 0, 0, IIf(oFont.Bold, 700, 400), _
IIf(oFont.Italic, 1, 0), IIf(oFont.Underline, 1, 0), IIf(oFont.Strikethrough, 1, 0), 1, 0, 0, 3, 48, oFont.Name)
Set oFont = Nothing
hOldFont= SelectObject(hdc, hFont)
DrawTextEx hdc, Text, rc, wFormat
SelectObject hdc, hOldFont
DeleteObject hFont
Last edited by Jonney; Jul 18th, 2015 at 11:19 PM.
-
Jul 19th, 2015, 08:39 AM
#2
Re: A better way for Print Page dpi awareness
Are you sure the indent (offset) of each paragraph in your preview window is proportionally correct? Maybe it's just that simple? Paragraph starts a couple pixels more to the right, so the text wrapping isn't the same any longer.
-
Jul 19th, 2015, 09:20 AM
#3
Thread Starter
Frenzied Member
Re: A better way for Print Page dpi awareness
Originally Posted by LaVolpe
Are you sure the indent (offset) of each paragraph in your preview window is proportionally correct? Maybe it's just that simple? Paragraph starts a couple pixels more to the right, so the text wrapping isn't the same any longer.
I remove all other text except the multi-line text:
I debug the rc position:
------------ Left Top Right Bottom
Preview: 283 173 679 358
Printing: 1768 1081 4244 2238
283*6.25 = 1768.75
173*6.25 = 1081.25
679*6.25 = 4243.75
358*6.25 = 2237.5
The Coordinates are almost proportionally same, But I can't figure out why DrawText wrapped differently.
Last edited by Jonney; Jul 19th, 2015 at 09:34 AM.
-
Jul 19th, 2015, 09:43 AM
#4
Re: A better way for Print Page dpi awareness
Are you using a true-type font? Maybe if you manually extend the right edge of the rectangle a pixel at a time to find out where the wrap is exactly the same, then you might be able to detect the problem?
-
Jul 19th, 2015, 09:54 AM
#5
Thread Starter
Frenzied Member
Re: A better way for Print Page dpi awareness
Originally Posted by LaVolpe
Are you using a true-type font? Maybe if you manually extend the right edge of the rectangle a pixel at a time to find out where the wrap is exactly the same, then you might be able to detect the problem?
I saw the same problem by direct assignment, I used "Tahoma", size is 9 for this testing :
Code:
If bPrintingView Then
rc.Left = 283 '283 173 679 358
rc.Top = 173
rc.Right = 679
rc.Bottom = 358
DrawTextW hDC, StrPtr(Text), -1, rc, wFormat
ElseIf bPrintingMode Then
rc.Left = 1768
rc.Top = 1081
rc.Right = 4244
rc.Bottom = 2238
DrawTextW hDC, StrPtr(Text), -1, rc, wFormat
End If
Last edited by Jonney; Jul 19th, 2015 at 10:04 AM.
-
Jul 19th, 2015, 10:03 AM
#6
Re: A better way for Print Page dpi awareness
You asked is there a better way? Maybe. On this link, MSDN briefly talks about issues similar to yours. Here is their answer
Finally, be aware that although TrueType fonts scale nicely, they don’t scale linearly: Increasing the DPI by 10 percent does not generally increase a string’s length by exactly 10 percent. (GDI+ doesn’t have this problem; see the GDI+ section.) This happens because any given letter only looks good at certain sizes, and TrueType picks the nearest size that looks good.
Is GDI+ the cure?
-
Jul 19th, 2015, 10:21 AM
#7
Thread Starter
Frenzied Member
Re: A better way for Print Page dpi awareness
Originally Posted by LaVolpe
You asked is there a better way? Maybe. On this link, MSDN briefly talks about issues similar to yours. Here is their answer
Is GDI+ the cure?
I will try GDI+ tomorrow. Thanks for the clue.
-
Jul 20th, 2015, 09:32 AM
#8
Thread Starter
Frenzied Member
Re: A better way for Print Page dpi awareness
I an trying to replace GDI with GDI+, But situation get complicated:
1. In GDI+, Preview window (picturebox) do show text, but the text font size looks smaller than normal (or than GDI).
2. In GDI+, LeftBottom and RightBottom alignment doesn't work when RECT is smaller than height of text need.
3. My Printer doesn't draw at all in GDI+ code. Nothing Text being drawn by GDI+ though picture and GDI code works.
GDI Code :
Code:
hFont = CreateFont(-pMulDiv(m_oFont.Size, GetDeviceCaps(hDC, 90), 72!), 0, 0, 0, IIf(m_oFont.Bold, 700, 400), _
IIf(m_oFont.Italic, 1, 0), IIf(m_oFont.Underline, 1, 0), IIf(m_oFont..Strikethrough, 1, 0), 1, 0, 0, 0, 48, m_oFont.Name)
hOldFont = SelectObject(hDC, hFont)
lColor = SetTextColor(hDC, vbBlack)
DrawTextW hDC, StrPtr(Text), -1, rc, wFormat
SetTextColor hDC, lColor
SelectObject hDC, hOldFont
DeleteObject hFont
GDI+ Code:
Code:
Dim hStringFormat As Long
lFontStyle = (IIf(m_oFont.Bond, 1, 0) Or _
IIf(m_oFont.Italic, 2, 0) Or _
IIf(m_oFont.Underline, 4, 0) Or _
IIf(m_oFont.Strikethrough, 8, 0))
GdipCreateFontFamilyFromName StrPtr(m_oFont.Name), 0&, hFontFamily
GdipCreateFont hFontFamily, m_oFont.Size, lFontStyle, UnitPixel, hFont
GdipCreateStringFormat 0&, 0&, hStringFormat
If ((wFormat And 16) <= 0) Then
GdipSetStringFormatFlags hStringFormat, StringFormatFlags.NoWrap
End If
If ((wFormat And 1) > 0) Then
GdipSetStringFormatAlign hStringFormat, StringAlignment.StringAlignmentCenter
ElseIf ((wFormat And 2) > 0) Then
GdipSetStringFormatAlign hStringFormat, StringAlignment.StringAlignmentFar
Else
GdipSetStringFormatAlign hStringFormat, StringAlignment.StringAlignmentNear
End If
If ((wFormat And 4) > 0) Then
GdipSetStringFormatLineAlign hStringFormat, StringAlignment.StringAlignmentCenter
Else
If ((wFormat And 8) > 0) Then
GdipSetStringFormatLineAlign hStringFormat, StringAlignment.StringAlignmentFar
Else
GdipSetStringFormatLineAlign hStringFormat, StringAlignment.StringAlignmentNear
End If
End If
GdipSetTextRenderingHint hGraphics, TextRenderingHintSystemDefault
GdipSetCompositingQuality hGraphics, CompositingQualityAssumeLinear
GdipSetPixelOffsetMode hGraphics, PixelOffsetModeHalf
Dim tRectF As RECTF
tRectF.Left = rc.Left
tRectF.Top = rc.Top
tRectF.Width = rc.Right - rc.Left
tRectF.Height = rc.Bottom - rc.Top
GdipSetClipRectI hGraphics, rc.Left, rc.Top, rc.Right - rc.Left, rc.Bottom - rc.Top, CombineMode.CombineModeReplace
Dim hBrush As Long
GdipCreateSolidFill RGBtoARGB(vbBlack, 255), hBrush
GdipDrawString hGraphics, StrPtr(Text), Len(Text), hFont, tRectF, hStringFormat, hBrush
GdipResetClip hGraphics
GdipDeleteBrush hBrush
GdipDeleteStringFormat hStringFormat
GdipDeleteFont hFont
GdipDeleteFontFamily hFontFamily
-
Jul 20th, 2015, 08:33 PM
#9
Re: A better way for Print Page dpi awareness
Those differences are quite normal, and you don't even have a guarantee, that
each and every Printer will follow a certain Font-Selection-Command with the exact
font in that exact metrics.
The only way to achieve true WYSIWYG-output (between Preview and Printer)
when using GDI, is to work with Enhanced-Metafiles (EMF).
Those APIs can provide you with a hDC as well - then you will render into the
EMF-File (either InMemory, or against a Disk-File) over that EMF.hDC - and
for correct "PlayBack" on both (a Pixelbased-Preview-Container on Screen,
or a Printer) you will then use "PlayEnhMetafile".
Here's an example which might be useful to validate the EMF-based approach
first on your System (simple Code, using EMF-Wrapper-Classes from vbRichClient5).
When these tests with EMF work out well on your Systems and Printers, you'd have
an ensurance that your own EMF-API-implementations are worth an attempt
(in case you don't plan to ship the RC5 with your solution).
Here's a Demo-Zip:
EMFReports.zip
Here's what the Demo produces (in Landscape-Mode, but this can be switched)...
EMF-Rendering into a VB-PictureBox:
EMF-Rendering onto a PDF-Printer:
HTH
Olaf
-
Jul 21st, 2015, 01:41 AM
#10
Thread Starter
Frenzied Member
Re: A better way for Print Page dpi awareness
Those differences are quite normal, and you don't even have a guarantee, that
each and every Printer will follow a certain Font-Selection-Command with the exact
font in that exact metrics.
The only way to achieve true WYSIWYG-output (between Preview and Printer)
when using GDI, is to work with Enhanced-Metafiles (EMF).
Those APIs can provide you with a hDC as well - then you will render into the
EMF-File (either InMemory, or against a Disk-File) over that EMF.hDC - and
for correct "PlayBack" on both (a Pixelbased-Preview-Container on Screen,
or a Printer) you will then use "PlayEnhMetafile".
Here's an example which might be useful to validate the EMF-based approach
first on your System (simple Code, using EMF-Wrapper-Classes from vbRichClient5).
When these tests with EMF work out well on your Systems and Printers, you'd have
an ensurance that your own EMF-API-implementations are worth an attempt
(in case you don't plan to ship the RC5 with your solution).
Thanks for the great experiment. I will try to draw into Metafile-DC.
Meta file has advantages such as adding our own transparent water print.
I am still wondering why the GDI+ code doesn't work for printer hdc. Sure some flaw inside my code.
I am still wondering why the GDI+ code doesn't work for printer hdc. Sure some flaw inside my code.
Edited: I see. I have to scale the canvas considering printer dpi and screen dpi. But GDI doesn't need.
Last edited by Jonney; Jul 23rd, 2015 at 08:48 AM.
-
Jul 23rd, 2015, 08:51 AM
#11
Thread Starter
Frenzied Member
Re: A better way for Print Page dpi awareness
Give up. I will try Schmidt's method: print into emf.
-
Jul 23rd, 2015, 09:56 AM
#12
Re: A better way for Print Page dpi awareness
A quick FYI before you rewrite too much. According to the GDI+ docs:
In the preceding code, the three GDI+ drawing commands are in between calls to the StartDoc and EndDoc functions, each of which receives the printer device context handle. All graphics commands between StartDoc and EndDoc are routed to a temporary metafile. After the call to EndDoc, the printer driver converts the data in the metafile into the format required by the specific printer being used.
Note If spooling is not enabled for the printer being used, the graphics output is not routed to a metafile. Instead, individual graphics commands are processed by the printer driver and then sent to the printer.
If you haven't already, check to see if spooling is enabled for your printer. If it isn't, try activating it, then testing your existing code again.
-
Jul 23rd, 2015, 07:38 PM
#13
Thread Starter
Frenzied Member
Re: A better way for Print Page dpi awareness
Originally Posted by Tanner_H
A quick FYI before you rewrite too much. According to the GDI+ docs:
If you haven't already, check to see if spooling is enabled for your printer. If it isn't, try activating it, then testing your existing code again.
I tried, the spooling can't being activated for pdfcreator and network sharing printer.
My problem is that the multiline text on preview window is not the same wrapped on Printing using the same GDI code or GDI+ code with different scale in (Printer dpi) / (screen dpi) . It's not WYSIWYG-output between Preview and Printer. GDI DrawTextW/TextOutW and GDI+ both failed. As Schmidt said, the only way is to print into file or DIB during print preview then output to printer.
Excel does a good job, I see it always producing WYSIWYG. But I don't know how MS did.
Last edited by Jonney; Jul 23rd, 2015 at 07:47 PM.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|