Resizing System.Drawing.Bitmap to less than 1/128th (Bilinear) or 1/256th (Bicubic) of its original width/height corrupts the result
- Dominant language
- C#
- Stars
- 4.9k
- Forks
- 1.1k
- Avg merge
- 20h 23m
- Merged PRs (30d)
- 103
Description
### .NET version
8.0
### Did it work in .NET Framework?
No
### Did it work in any of the earlier releases of .NET Core or .NET 5+?
Unlikely
### Issue description
The result of a resizing operation, for example via the Bitmap-constructor or using Graphics, becomes corrupted when an image is resized to less than 1/128th (using Bilinear interpolation) or 1/256th (using Bicubic) of the original size.
The resulting image turns transparent and colors become corrupted, and as the scale goes beyond the point where corruption starts, the output changes.
I have conducted tests for this with different sized images, 16384x16384, 16384x100, 2048x2048, 1024x1024 for example, resizing width and/or height, all with the results being faulty.
A 16384x16384 test image resized to 128x128:

The same resized to 127x127, it is barely visible:

Resized to 64x64, transparency is slightly reduced at 247 instead of 255:

My assumption is that resizing by that much causes overflowing in the interpolation algorithms, leading to higher bytes being modified when they should not be.
This is likely an issue in the underlying GDI+ library, but I do not know where else to report this bug.
I was unable to find any information on this issue.
### Steps to reproduce
Resize an image to less than 1/128th of its original width and/or height, either using the _Bitmap(Bitmap height, int width, int height)_-constructor or via Graphics, using _InterpolationMode.Bilinear_ (or _Default_).
Or resize it to less than 1/256th when using Bicubic interpolation.
Code example:
```cs
var file = [PATH_TO_IMAGE]; // image of at least 16384 pixels in either width or height
var fullSize = new Bitmap(file);
var size0 = 127;
var size1 = 128;
resizeAndSaveDefault(size0, size0); // FAULTY at 1/128
resizeAndSaveDefault(size1, size1); // OK
resizeAndSave(size0, size0, InterpolationMode.Bicubic); // FAULTY at 1/256
resizeAndSave(size1, size1, InterpolationMode.Bicubic); // OK
resizeAndSave(size0, size0, InterpolationMode.Bilinear); // FAULTY at 1/128 (same as InterpolationMode.Default)
resizeAndSave(size1, size1, InterpolationMode.Bilinear); // OK
resizeAndSave(size0, size0, InterpolationMode.HighQualityBicubic); // OK
resizeAndSave(size1, size1, InterpolationMode.HighQualityBicubic); // OK
resizeAndSave(size0, size0, InterpolationMode.HighQualityBilinear); // OK
resizeAndSave(size1, size1, InterpolationMode.HighQualityBilinear); // OK
resizeAndSave(size0, size0, InterpolationMode.NearestNeighbor); // OK
resizeAndSave(size1, size1, InterpolationMode.NearestNeighbor); // OK
void resizeAndSaveDefault(int width, int height) =>
new Bitmap(fullSize, width, height).Save($"{Path.GetDirectoryName(file)}\\{Path.GetFileNameWithoutExtension(file)}_{width}x{height}.png");
void resizeAndSave(int width, int height, InterpolationMode interpolationMode)
{
var bitmap = new Bitmap(width, height);
using var graphics = Graphics.FromImage(bitmap);
graphics.InterpolationMode = interpolationMode;
graphics.Clear(Color.Transparent);
graphics.DrawImage(fullSize, 0, 0, width, height);
bitmap.Save($"{Path.GetDirectoryName(file)}\\{Path.GetFileNameWithoutExtension(file)}_{interpolationMode}_{width}x{height}.png");
}
```
Contributor guide
Assessment
This issue has not been assessed yet.