GDIPlusX: Bug in 1.10 when resizing bitmaps

Developer
Nov 27, 2007 at 3:17 PM
Edited Nov 27, 2007 at 3:26 PM
I have uploaded a zip file showing a problem when resizing bitmaps, that did not happen with a previous version. The problem is a strange border at the right and bottom edges of the resized image.

Since in previous versions FromVarBinary did not work, there is a property "UseFromVarBinary" in the xfcIcon class. Set it to .F. to test previous versions.

The only change is using the system.drawing.prg file from one version or the other. The "old" version is a system.drawing.prg file Cesar sent me, the one that had GetMask added., it is dated 2007-11-21 02:37

Here is the file:
http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=VFPX&DownloadId=22754
Nov 27, 2007 at 3:47 PM
Carlos,
Can you give me more details ?
First, I'd like you to download the version from this link:
https://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=VFPX&ReleaseId=8606

If it persists, can you send me a sample that generates the error ?

Thanks in advance

Cesar
Developer
Nov 27, 2007 at 5:23 PM
Edited Nov 28, 2007 at 7:11 PM
UPDATE
Have found the problem is not related to system.drawing.prg versions, but to the pixelformat of the bitmap.

Below you will find two resizing methods, "A" and "B"

Method "A" only works well with bitmaps with a PixelFormat of Format32bppARGB (saved as png and displayed in an image control using the Picture property)

Method "A" shows gray/black/3d raised right/bottom border for bitmaps Format24bppRGB, (saved as bmp along with a msk generated with getmask, and displayed using an image control)

Method "B" works well for bitmaps Format32bppARGB and Format24bppRGB, so I will say this is a NET/GDI+ bug, for which there is a workaround.

Have project with repro code available here:
http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=VFPX&DownloadId=22762

The problem seems to be that when using interpolation, the right and bottom border pixels have no "neighbour" pixels to interpolate with to the right of a right border pixel, or under a bottom border pixel, so GDI uses black pixels by default. NICE!

I wonder why that happens only on the right and bottom border? Maybe GDI correctly assumes neighbour pixels that are of the same value as the border pixels for left and top pixels? Probably.

UPDATE
Depending on various settings of the Graphics object:
SmoothingMode, InterpolationMode, PixelOffsetMode, CompositingQuality
this may happen on all four borders or only on the right and bottom borders
END OF UPDATE

So this is the original code: (Resizing method A)

*** ResizeBitmap
Lparameters m.poBitmap
 
With _Screen.System.Drawing
	m.loResized = .Bitmap.New(This.IconWidth, This.IconHeight, m.poBitmap.PixelFormat)
	m.loResized.SetResolution(m.poBitmap.HorizontalResolution, m.poBitmap.VerticalResolution)
	m.loGraphics = .Graphics.FromImage(m.loResized)
	m.loGraphics.SmoothingMode = .Drawing2D.SmoothingMode.HighQuality
	m.loGraphics.InterpolationMode = .Drawing2D.InterpolationMode.HighQualityBicubic
 
	m.loGraphics.DrawImage(m.poBitmap, 0, 0, m.loResized.Width, m.loResized.Height)
	m.loBitmap = .Null.
	m.poBitmap= m.loResized
	m.loResized = .Null.
Endwith
 
Return m.poBitmap

And this is the fixed code. The fixed code just places a mirror image of the bitmap in each side, so border pixels will have themselves as neighbour pixels. (Resizing method B)

Lparameters m.poBitmap
 
Local ;
	loAttributes, ;
	loResized, ;
	loRectangle, ;
	loGraphics, ;
	loBitmap
 
With _Screen.System.Drawing
	m.loAttributes 	= .Imaging.ImageAttributes.New()
	m.loAttributes.SetWrapMode(.Drawing2D.WrapMode.TileFlipXY)
	m.loResized = .Bitmap.New(This.IconWidth, This.IconHeight, m.poBitmap.PixelFormat)
	m.loBitmapRect	=  m.poBitmap.GetBounds()
	m.loResizedRect	=  m.loResized.GetBounds()
	m.loResized.SetResolution(m.poBitmap.HorizontalResolution, m.poBitmap.VerticalResolution)
	m.loGraphics = .Graphics.FromImage(m.loResized)
	m.loGraphics.SmoothingMode = .Drawing2D.SmoothingMode.HighQuality
	m.loGraphics.InterpolationMode = .Drawing2D.InterpolationMode.HighQualityBicubic
 
	m.loGraphics.DrawImage(m.poBitmap, m.loResizedRect, m.loBitmapRect, .GraphicsUnit.Pixel, m.loAttributes)
	m.loBitmap = .Null.
	m.poBitmap= m.loResized
	m.loResized = .Null.
Endwith
 
Return m.poBitmap

I found the solution/workaround here:

http://decenturl.com/groups.google/resizing-image-defect-strange

And found this other references to this problem:

http://decenturl.com/groups.google/asp.net-image-resizing-microsoft
http://decenturl.com/forums.microsoft/resize-image-unwanted-border
http://decenturl.com/forums.microsoft/interpolationmode.highqualitybicubic
Developer
Nov 27, 2007 at 6:00 PM
Edited Nov 27, 2007 at 7:30 PM
Excellent article regarding this here:

BorderBug
http://decenturl.com/codeproject/borderbug-the-code-project

And
Image Resizing - outperform GDI+
http://decenturl.com/codeproject/image-resizing-outperform
Now searching for

DrawImage HighQualityBicubic TileFlipXY

in Google gives you lots of hits, the only problem being is that to be able to use those keywords, you already have to know the solution to the problem!

Also, this could be the cause of the "fading pictureval" problem of the image control?
Nov 27, 2007 at 7:39 PM
Cool !
I've learned a good one today.

I'm glad to see you flying with GDI+X.
I suspect that now you really understand the great advantages that being .NET compatible GDI+X brings to us.

Our knowledge base has become HUGE !
Developer
Nov 28, 2007 at 1:11 AM
Carlos,

Great research. Thanks for posting this. This has drivin me crazy in the past.