Thursday, July 06, 2006

Problem stretching images with GDI+


I've noticed a problem when trying to zoom in on an image using the DrawImage method. The above image shows the problem. Basically, if you scale the image, the first row and column doesn't get scaled correctly. I've posted the problem twice on Expert-Exchange but have not found an explanation or fix yet.

I created a test app that takes a 40x40 bitmap with a checkerboard pattern and zooms it by a zoomfactor. The render code is as follows:

Protected Overrides Sub OnPaint(ByVal e As
System.Windows.Forms.PaintEventArgs) Try

If (bmp Is Nothing) Then

Else

Dim g As
Graphics = e.Graphics()
g.SmoothingMode = Drawing2D.SmoothingMode.None

g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
g.SmoothingMode = Drawing2D.SmoothingMode.None

Dim rect As New Rectangle
rect.X = 0
rect.Y = 0
rect.Width = (bmp.Width * m_ZoomLevel)
rect.Height = (bmp.Height * m_ZoomLevel) 'attribute shows that destination rect is
the right size but not needed for test.

Dim attr As System.Drawing.Imaging.ImageAttributes
attr = New System.Drawing.Imaging.ImageAttributes()

attr.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY)


g.DrawImage(bmp, rect,0, 0, 40, 40, GraphicsUnit.Pixel, attr)
attr.Dispose()

End If
Catch ex As Exception

MessageBox.Show("ouch")

End Try
End Sub


This bug has been posted to Microsoft and confirmed by other programmers. A fix is to do the following:

Use (-0.5 + 0.5*srcw/dstw, -0.5 + 0.5*srch/dsth) as the source origin.

Happy Coding!
Jas

11 comments:

  1. I did some testing with all of the interpolation methods and it looks to me like every pixel is scaled propertly but since the first row and column are on an edge, the information for the pixel that would have been scaled away from the center of the bitmap is discarded.

    One fix may be to use a larger graphics context, scale it to the center of the image, and extract the result at the new upper left coordinate.

    ReplyDelete
  2. Anonymous7/09/2006

    I validated your bug on Connect and left a note about what I think is going on. Try using (-0.5 + 0.5*srcw/dstw, -0.5 + 0.5*srch/dsth) as the source origin.

    ReplyDelete
  3. The above fix using works great. Thanks for the input. I will modify the blog to list this solution.

    ReplyDelete
  4. Anonymous7/17/2006

    This comment has been removed by a blog administrator.

    ReplyDelete
  5. FYI: I got word from Microsoft regarding this bug. They wanted me to create a project and send it to them. They didn't want to invest any time into reproducing the bug.

    I told them I would bill them for the work...

    Their response was that they only focus on the largest bugs with the greatest impact to their user base. It made since to me... We'll see if its fixed in the next release.

    ReplyDelete
  6. Anonymous5/10/2007

    What does "source origin" mean?

    ReplyDelete
  7. source origin or X,Y position for the source rectangle to be passed to DrawRect, which has the bug.
    Hope this helps.

    ReplyDelete
  8. fortnum11/23/2008

    Thank you! Thank you! At last... phew... I has been working on the problem whole night and was such frustrated, without any hopes searched Google and found your blogpost - thank you, shame Microsoft!

    ReplyDelete
  9. hey it didnt work for me :( i m using 2005 and but result is still same, and the calculation u suggested returns amount in decimal and i guess the parameter type for x,y is integer so it will not accept decimal amount

    ReplyDelete
  10. my apologies :) it worked fine with rectangleF :)
    thanx alot dude

    ReplyDelete
  11. Anonymous11/08/2011

    it is no bug
    u just need to set this:
    g.PixelOffsetMode = Drawing2D.PixelOffsetMode.Half

    ReplyDelete