1

I have a function that draws a text centered, but I have a math flaw somewhere in there that I just don't spot.

enter image description here

As you can see the font is offset to the bottom and to the right, and part of the shadow is cut off although I thought I accounted for it.

The bigger the rect, the more obvious the flaw gets.

Perhaps it is even a flaw in my usage of the Graphics.DrawImage function because to me the function looks fine.

Does anybody see my mistake?

Thank you for the help!

Public Sub pDraw(ByVal uGraphics As Graphics, ByVal uText As String, ByRef uRect As Rectangle, ByVal uFont As Font, ByVal uStringFormat As StringFormat)

    'I have established nice values using a font size of 50. So if we project them onto other font sizes, we will use these templates and percentages
    Dim cstOutlineThickness As Integer = 4
    Dim cstShadowX As Integer = 1
    Dim cstShadowY As Integer = 4
    Dim cstDefaultFontSize As Integer = 50

    Dim nPngOutlineText As New PngOutlineText()
    nPngOutlineText.TextGradOutline(
                    Color.FromArgb(56, 106, 150),
                    Color.FromArgb(255, 0, 56, 113),
                    Color.FromArgb(255, 0, 56, 113),
                    0)
    nPngOutlineText.EnableReflection(False)
    nPngOutlineText.EnableShadow(False)

    'we can add the border and shadow sizes later. These are fixed values!
    Dim fDestWidth As Single
    Dim fDestHeight As Single
    SetGoodFontSize(nPngOutlineText, uGraphics, uText, uFont, uRect, fDestWidth, fDestHeight, 4000)

    Dim sngPerc As Single = modConversions.Percent(cstDefaultFontSize, uFont.Size, False)

    Dim iOutlineThickness As Integer = (sngPerc * cstOutlineThickness) / 100
    Dim iShadowX As Integer = (sngPerc * cstShadowX) / 100
    Dim iShadowY As Integer = (sngPerc * cstShadowY) / 100

    uGraphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    uGraphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic

    Dim m_PngOutlineText As New PngOutlineText()
    m_PngOutlineText.TextGradOutline(
                    Color.FromArgb(56, 106, 150),
                    Color.FromArgb(255, 0, 56, 113),
                    Color.FromArgb(255, 0, 56, 113),
                    iOutlineThickness)
    m_PngOutlineText.EnableReflection(False)
    m_PngOutlineText.EnableShadow(True)

    m_PngOutlineText.DiffusedShadow(
    Color.FromArgb(10, 0, 0, 0),
   8,
    New Point(iShadowX, iShadowY))

    '10,0,0,0
    Dim fDestWidth2 As Single = 0
    Dim fDestHeight2 As Single = 0
    Dim sngStartX2 As Single = 0
    Dim sngStartY2 As Single = 0
    m_PngOutlineText.MeasureString(uGraphics, uFont.FontFamily, uFont.Style, CInt(uFont.Size), uText, New Point(0, 0), StringFormat.GenericDefault, sngStartX2, sngStartY2, fDestWidth2, fDestHeight2)

    'center it. There is no good way to specify the aligning in the font-drawing
    Dim r As Rectangle = Rectangle.FromLTRB(0, 0, fDestWidth2, fDestHeight2)
    CenterRect(uRect, r)

    Dim m_clrBkgd As Color = Color.FromArgb(255, 255, 255)
    m_PngOutlineText.SetShadowBkgd(m_clrBkgd, fDestWidth2, fDestHeight2)

    Dim m_pPngImage As Bitmap = New Bitmap(CInt(fDestWidth2), CInt(fDestHeight2), System.Drawing.Imaging.PixelFormat.Format32bppArgb)
    m_PngOutlineText.SetPngImage(m_pPngImage)
    Dim gradientBrush As New LinearGradientBrush(New RectangleF(0, 0, fDestWidth2, fDestHeight2), Color.FromArgb(56, 106, 150), Color.FromArgb(37, 119, 178), Drawing2D.LinearGradientMode.Vertical)
    m_PngOutlineText.TextGradOutline(gradientBrush, Color.FromArgb(255, 0, 56, 113), Color.FromArgb(255, 0, 56, 113), iOutlineThickness)
    m_PngOutlineText.DrawString(uGraphics, New FontFamily(uFont.Name), uFont.Style, uFont.Size, uText, New Point(0, 0), uStringFormat)

    uGraphics.DrawImage(m_pPngImage, r)

End Sub

Public Sub CenterRect(ByVal uMain As Rectangle, ByRef uRectToCenter As Rectangle)

    Dim iMainLeft As Integer = uMain.Left
    Dim iMainTop As Integer = uMain.Top
    Dim iMainWidth As Integer = uMain.Width
    Dim iMainHeight As Integer = uMain.Height
    Dim iDestW As Integer = uRectToCenter.Width
    Dim iDestH As Integer = uRectToCenter.Height
    Dim iDestX2 As Integer = iMainLeft + ((iMainWidth - iDestW) / 2)
    Dim iDestY2 As Integer = iMainTop + ((iMainHeight - iDestH) / 2)

    Dim nPoint As New Point(iDestX2, iDestY2)
    uRectToCenter.Location = nPoint

End Sub

Here is another screenshot from debugging: As you can see, the image is drawn at X=22, Y=-11, Width=212, Height=278, but as you can see from the screenshot, that is not how it looks like in the end.

That is why I was asking if it might be a mistake in Graphics.DrawImage.

enter image description here

Edit 3: I have filled the m_pPngImage with Color.Red so that I can see where it is actually drawn. This looks fine to me, so I guess the problem is not in CenterRect or similar.

enter image description here

tmighty
  • 10,734
  • 21
  • 104
  • 218
  • What is "uRectToCenter?" Rarely are characters centered within their "cell." They include spacing between the next or previous character, and the previous or next line. It's possible your "centering function" is correct, you're just not considering the margins in character. (This is especially relevant for bitmapped or fixed-width fonts.) (On another note: ditch the pseudo-Hungarian notation. It's useless.) – 3Dave Oct 06 '16 at 19:45
  • @DavidLively The passed ByRef parameter. Why it isn't a function returning a rectangle is a mystery. – LarsTech Oct 06 '16 at 19:48
  • @LarsTech Yes, I can see that. I was asking *what it means.* – 3Dave Oct 06 '16 at 19:49
  • Lots of bad coding habits here. I'm pretty sure you've been told to turn "Option Strict On" before. You are leaking resources by not disposing your image objects. You need to post more information, since we don't know what values you used for uRect, etc. I would avoid using ByRef unless it's absolutely necessary. – LarsTech Oct 06 '16 at 19:57
  • This should be fairly easy for you to debug. You just need to compare the uRect value to your r value. It hints at your MeasureString function returning a larger rectangle than you think. – LarsTech Oct 06 '16 at 20:25
  • `X = (ContainerWidth / 2) - (MyObjectWidth / 2)` – TyCobb Oct 06 '16 at 20:37

1 Answers1

0

Pseudocode...

Briefly, given a rect r:

centerX = (r.Left + r.Right) / 2;
centerY = (r.Top  + r.Bottom) / 2;

To center it a rect about its local, well, center:

r.Left -= r.Width / 2;
r.Right -= r.Width /2;
r.Top -= r.Height / 2;
r.Bottom -= r.Height / 2;

Really, that's all there is to it.

Update

Based on your update / new screenshot, I'm convinced that either the character cell contains the margin, or MeasureString is adding it. Either way, your output is correct.

Also, you may find this thread helpful.

Community
  • 1
  • 1
3Dave
  • 28,657
  • 18
  • 88
  • 151
  • Your code is more beautiful than mine, but in the end it does the same, so the error must be somewhere else. – tmighty Oct 06 '16 at 19:59
  • @tmighty likely the character image is not centered in the rect returned by "measureString " it is drawing correctly - with the margins that every character image includes. – 3Dave Oct 06 '16 at 20:01
  • `MeasureString` does add extra padding to the string to account for overhanging glyphs, but I would expect that padding to make the image appear too for up the form, rather than too far down. – Bradley Uffner Oct 06 '16 at 20:05
  • @BradleyUffner why? – 3Dave Oct 06 '16 at 20:06
  • Because if the rectangle is taller, it would have to move it up higher to keep it centered. – Bradley Uffner Oct 06 '16 at 20:07