Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

GDI Graphics Are Inexact

4 views
Skip to first unread message

existential...@gmail.com

unread,
Oct 26, 2008, 12:32:06 PM10/26/08
to
When I use standard GDI graphics methods, like DrawRectangle or
FillEllipse, I've noticed that the results are slightly off.

I seldom work with graphics, but I'm doing a project now which
requires me to draw precise shapes. I've discovered that, in order to
get crisp results, I have to "nudge" the coordinates. For instance,
instead of drawing a rectangle with

DrawRectangle(Pen1, X, Y, Width, Height)

I must use

DrawRectangle(Pen1, X + 0.001953, Y + 0.001953, Width, Height)

Is anyone familiar with this issue? I'm guessing it is a problem with
Windows (I'm using Windows XP Pro), but I'd like to learn more.


-TC

Tom Dacon

unread,
Oct 26, 2008, 5:56:08 PM10/26/08
to
Ultimately, whatever coordinates you send to the API have to get transformed
and rounded to pixel coordinates on the screen, which depend on screen
resolution. In addition, nost screen resolutions these days are not
isotropic (equally scaled in X and Y), because the X and Y resolutions are
not exactly in proportion to the actual viewable dimensions of the display
surface (CRT or LCD screen).

Sorry - fact of life.

Tom Dacon
Dacon Software Consulting

<existential...@gmail.com> wrote in message
news:efbcd39a-4afb-4ebf...@k16g2000hsf.googlegroups.com...

SurturZ

unread,
Oct 27, 2008, 1:18:01 AM10/27/08
to
To sort this out in GDI+ is pretty tricky; you need to learn about the World
Transformation, Page transformation and Affine transformations in general.

http://en.wikibooks.org/wiki/Visual_Basic_.NET/GDI%2B is a bluffer's guide,
but really you need to study GDI+ a bit to get it right.

If you can ensure that you dpi (dots per inch) is the same at every step,
you'll have a fighting chance. You need to turn off any "smoothing" etc that
your printer might perform.

--
David Streeter
Synchrotech Software
Sydney Australia

Gigasoft

unread,
Oct 30, 2008, 2:36:14 PM10/30/08
to
Hi,

Use MM_TEXT mapping mode and work directly in pixels. To use any other
mapping mode will result in never knowing exactly where something will end
up pixel wise. Working with pixels you create your own coordinate system
as needed via math.

best regards,

Robert Dede
Gigasoft, Inc.
www.gigasoft.com


<existential...@gmail.com> wrote in message
news:efbcd39a-4afb-4ebf...@k16g2000hsf.googlegroups.com...

existential...@gmail.com

unread,
Nov 2, 2008, 11:12:05 AM11/2/08
to

I wasn't very clear in my original post. What I meant to say is that
in pixel mode with no smoothing, I find that the graphics methods are
imprecise. Specifically, they seem to suffer from rounding errors when
Single arguments are used, and they seem to have inconsistent
definitions of "Width" and "Height". The result is shapes that don't
look as expected, and which must be "nudged" to fit properly into
place.

I wrote a simple form which illustrates what I'm talking about. I'd be
grateful if other people would try this form and let me know if the
problems I'm seeing affect only me, only XP systems, or all Windows
systems.

-TC

Imports System.Drawing
Imports System.Windows.Forms

Public Class GraphicsTestForm
Inherits Form

Private FlowLayoutPanel1 As FlowLayoutPanel
Private TextBox1 As TextBox
Private WithEvents ComboBox1 As ComboBox
Private TextBox2 As TextBox
Private WithEvents Panel1 As Panel

Public Sub New()

'TextBox1
TextBox1 = New TextBox
With TextBox1
.BorderStyle = BorderStyle.FixedSingle
.Multiline = True
.ReadOnly = True
.Size = New Size(400, 60)
.TabStop = False
.Text = "This form demonstrates the implementation of graphics
methods by drawing shapes inside a 100x100 white square with a 1-pixel
margin."
End With

'ComboBox1
ComboBox1 = New ComboBox
With ComboBox1
.Width = 400
.Items.AddRange(New String() {"DrawLine", "DrawRectangle 1",
"DrawRectangle 2", "FillRectangle 1", "FillRectangle 2",
"DrawEllipse", "FillEllipse"})
.MaxDropDownItems = 20
End With

'TextBox2
TextBox2 = New TextBox
With TextBox2
.BorderStyle = BorderStyle.FixedSingle
.Multiline = True
.ReadOnly = True
.Size = New Size(400, 60)
.TabStop = False
End With

'Panel1
Panel1 = New Panel
With Panel1
.BackColor = Color.White
.BorderStyle = BorderStyle.FixedSingle
.ClientSize = New Size(100, 100)
End With

'FlowLayoutPanel1
FlowLayoutPanel1 = New FlowLayoutPanel
With FlowLayoutPanel1
.Controls.Add(TextBox1)
.Controls.Add(ComboBox1)
.Controls.Add(TextBox2)
.Controls.Add(Panel1)
.Dock = DockStyle.Fill
.FlowDirection = FlowDirection.TopDown
End With

'Me
With Me
.Controls.Add(FlowLayoutPanel1)
.ClientSize = New Size(420, 300)
End With

End Sub

Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint

Select Case ComboBox1.Text
Case "DrawLine"
e.Graphics.DrawLine(Pens.Red, 1, 1, 1, 98)
e.Graphics.DrawLine(Pens.Red, 1, 98, 98, 98)
e.Graphics.DrawLine(Pens.Red, 98, 98, 98, 1)
e.Graphics.DrawLine(Pens.Red, 98, 1, 1, 1)
Case "DrawRectangle 1"
e.Graphics.DrawRectangle(Pens.Red, 1, 1, 98, 98)
Case "DrawRectangle 2"
e.Graphics.DrawRectangle(Pens.Red, 0.501, 0.501, 98, 98)
Case "FillRectangle 1"
e.Graphics.FillRectangle(Brushes.Red, 1, 1, 98, 98)
Case "FillRectangle 2"
e.Graphics.FillRectangle(Brushes.Red, 1.1, 1.1, 98, 98)
Case "DrawEllipse"
e.Graphics.DrawEllipse(Pens.Red, 1, 1, 98, 98)
Case "FillEllipse"
e.Graphics.FillEllipse(Brushes.Red, 1, 1, 98, 98)
End Select

End Sub

Private Sub ComboBox1_TextChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles ComboBox1.TextChanged
Panel1.Invalidate()

Select Case ComboBox1.Text
Case "DrawLine"
TextBox2.Text = "DrawLine with integer arguments: This method
works as expected."
Case "DrawRectangle 1"
TextBox2.Text = "DrawRectangle(Pens.Red, 1, 1, 98, 98): This
method does not work as expected. The rectangle is too big."
Case "DrawRectangle 2"
TextBox2.Text = "DrawRectangle(Pens.Red, 0.501, 0.501, 98,
98): This method does not work as expected. The rectangle is
positioned improperly and is too big."
Case "FillRectangle 1"
TextBox2.Text = "FillRectangle(Brushes.Red, 1, 1, 98, 98):
This method works as expected."
Case "FillRectangle 2"
TextBox2.Text = "FillRectangle(Brushes.Red, 1.1, 1.1, 98, 98):
This method does not work as expected. The rectangle is positioned
improperly."
Case "DrawEllipse"
TextBox2.Text = "DrawEllipse(Pens.Red, 1, 1, 98, 98): This
method does not work as expected. The ellipse is too big and is not
centered properly."
Case "FillEllipse"
TextBox2.Text = "FillEllipse(Brushes.Red, 1, 1, 98, 98): This
method does not work as expected. The ellipse is too small and is not
centered properly."
End Select

End Sub

End Class

SurturZ

unread,
Nov 2, 2008, 9:21:02 PM11/2/08
to
I see what you mean!

I am far from an assembly programmer, but for fun I thought I'd see how far
I could get looking at the IL disassembly (to see whether the different
DrawLine functions add or subtract 1 to yield the error).

There are several wrapper functions in different assemblies, but I hit a
brick wall when I got to gdiplus.dll - I can only assume this is a real (not
PE) executable, since it won't disassemble into ILAsm. None of the wrapper
functions convert from Single to Integer, so if there is a bug, it's probably
there.

--
David Streeter
Synchrotech Software
Sydney Australia

0 new messages