how do I get the correct font width for print formatting vb.net

Hi,
I have two lines both are the same other than the font color. The second line prints with extra spaces between the letters. I need a way  to get the correct font width for calculating the start/x position for printing. The attached code uses MeasureString and prints wrong.

Thanks
Richard
Dim pic_font As New Font("Lucida Console", 10, FontStyle.Regular, GraphicsUnit.Pixel)
        Dim c As Long
        Dim ps As String
        Dim h As Integer
        Dim w As Double

        w = 0
        h = 0

        e.Graphics.DrawString("Rich", pic_font, Brushes.Black, w, 10)

        ps = "R"
        e.Graphics.DrawString("R", pic_font, Brushes.Black, w, 20)
        c = e.Graphics.MeasureString(ps, pic_font).Width
        w = w + c

        ps = ps + "i"
        e.Graphics.DrawString("i", pic_font, Brushes.Red, w, 20)
        c = e.Graphics.MeasureString(ps, pic_font).Width
        w = w + c

        ps = ps + "c"
        e.Graphics.DrawString("c", pic_font, Brushes.Blue, w, 20)
        c = e.Graphics.MeasureString(ps, pic_font).Width
        w = w + c

        ps = ps + "h"
        e.Graphics.DrawString("h", pic_font, Brushes.Green, w, 20)

        e.HasMorePages = False

Open in new window

Bad-Output.bmp
Good-Output.bmp
fwlrichardAsked:
Who is Participating?
 
grayeConnect With a Mentor Commented:
I don't know... I'm a little puzzled by this myself.
If you do a MeasureString on "Rich", it will be 56.3 points wide (which equates to 14.08 point for each character).  But if you meassure each character separately, you get 19.07 point each.
The documentation tells us what's going on... and tell us to use MeasureCharacterRanges instead

The MeasureString method is designed for use with individual strings and includes a small amount of extra space before and after the string to allow for overhanging glyphs. Also, the DrawString method adjusts glyph points to optimize display quality and might display a string narrower than reported by MeasureString. To obtain metrics suitable for adjacent strings in layout (for example, when implementing formatted text), use the MeasureCharacterRanges method or one of the MeasureString methods that takes a StringFormat, and pass GenericTypographic. Also, ensure the TextRenderingHint for the Graphics is AntiAlias.
0
 
grayeCommented:
Just get rid of the following lines:
        w = w + c

As they are only needed to *add* spacing (and are not needed to write one character after another) .  Recall that the "w" parameter is passed by value and gets incremented inside the function
http://msdn.microsoft.com/en-us/library/aa327575(VS.71).aspx 
0
 
grayeCommented:
Uh, you don't need the MeasureString either
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
fwlrichardAuthor Commented:
Hi graye,

I removed w=w+c and thy all print on top of each other.  
Would you have an example that fixes my code.
Also-bad.bmp
0
 
grayeCommented:
Oops, you're right... sorry about that
OK.. try the following.... it will be "close", but not exactly what you want.   The problem is that with printing a single character at a time, the graphics engine can't use any of it's kerning rules.   So, you'll have to turn that off, or just fudge it a little bit.
In this case, with a fixed width font, you could use a single value as the width (without having to calculate it).  I'd use something like

        w = w + pic_font.SizeInPoints * 0.65

        Dim pic_font As New Font("Lucida Console", 20, FontStyle.Regular, GraphicsUnit.Point)
        Dim c As Single
        Dim ps As String
        Dim h As Single
        Dim w As Single

        e.Graphics.PageUnit = GraphicsUnit.Point

        ' set the margins
        w = e.MarginBounds.Left
        h = e.MarginBounds.Top

        e.Graphics.DrawString("Rich", pic_font, Brushes.Black, w, h)
        ' a new line...
        h = e.MarginBounds.Top + pic_font.Height + 1
        w = e.MarginBounds.Left

        e.Graphics.DrawString("R", pic_font, Brushes.Black, w, h)
        c = e.Graphics.MeasureString("R", pic_font).Width
        w = w + c

        e.Graphics.DrawString("i", pic_font, Brushes.Red, w, h)
        c = e.Graphics.MeasureString("i", pic_font).Width
        w = w + c

        e.Graphics.DrawString("c", pic_font, Brushes.Blue, w, h)
        c = e.Graphics.MeasureString("c", pic_font).Width
        w = w + c

        ps = ps & "h"
        e.Graphics.DrawString("h", pic_font, Brushes.Green, w, h)

        e.HasMorePages = False

Open in new window

0
 
fwlrichardAuthor Commented:
Graye,

Yes the problem is it's not fixed and the color itn't all I want to change it's just what I chose for this example/code. I'm new to vb.net I came from vb6 this isn't a problem with vb6 as with it you just don't give it a new x location.
Your code MeasureString calculates the width to be 19.0722656
My guess is it should be around 12.4
Any idea why it wrong?

Thanks
Richard
0
 
fwlrichardAuthor Commented:
Graye
Thank you for all your help.
The MeasureCharacterRanges method is what I was missing.
This may not be the best way but it works.

Thanks
Richard
Dim stringFont As New Font("Lucida Console", 20)

        ' Set character ranges to "First" and "Second".
        Dim characterRanges As CharacterRange() = {New CharacterRange(0, 1)}

        ' Create rectangle for layout.
        Dim x As Single = 50.0F
        Dim y As Single = 50.0F
        Dim width As Single = 1000
        Dim height As Single = 1000
        Dim layoutRect As New RectangleF(x, y, width, height)
        Dim measureRect1 As RectangleF
        Dim stringRegions() As [Region]
        Dim stringFormat As New StringFormat

        stringFormat.SetMeasurableCharacterRanges(characterRanges)

        ' Draw First line to screen
        e.Graphics.DrawString("Rich", stringFont, Brushes.Black, x, y)
        ' Set new Y location for next line
        y = y + 25

        ' Draw Second line first string
        e.Graphics.DrawString("R", stringFont, Brushes.Black, x, y)

        ' Measure the string.
        stringRegions = e.Graphics.MeasureCharacterRanges("R", stringFont, layoutRect, stringFormat)
        ' Get string X,Y,Width,Height
        measureRect1 = stringRegions(0).GetBounds(e.Graphics)
        x = x + measureRect1.Width

        ' Draw second line second string
        e.Graphics.DrawString("i", stringFont, Brushes.Red, x, y)

        stringRegions = e.Graphics.MeasureCharacterRanges("i", stringFont, layoutRect, stringFormat)
        measureRect1 = stringRegions(0).GetBounds(e.Graphics)
        x = x + measureRect1.Width

        ' Draw second line third string
        e.Graphics.DrawString("c", stringFont, Brushes.Blue, x, y)

        stringRegions = e.Graphics.MeasureCharacterRanges("c", stringFont, layoutRect, stringFormat)
        measureRect1 = stringRegions(0).GetBounds(e.Graphics)
        x = x + measureRect1.Width

        ' Draw second line forth string
        e.Graphics.DrawString("h", stringFont, Brushes.Green, x, y)

        e.HasMorePages = False

Open in new window

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.