This is a short test for another problem, where I try to replace colors in an image using ImageAttributes.SetRemapTable()
. I found that Graphics.DrawImage()
changes other colors as well, that are not part of the color mapping.
Therefore I created a small test on Graphics.DrawImage()
.
I expect both saved images to be identical:
var bitmap = new Bitmap (1, 1, PixelFormat.Format32bppArgb);
bitmap.SetPixel(0,0,Color.FromArgb(10,10,10,10));
bitmap.Save (@"bitmap1.png", ImageFormat.Png);
var bitmap2 = new Bitmap (1, 1, PixelFormat.Format32bppArgb);
var graphics = Graphics.FromImage(bitmap2);
graphics.DrawImage(bitmap, Point.Empty);
bitmap2.Save (@"bitmap2.png", ImageFormat.Png);
The ARGB of the pixel in bitmap1
is 10,10,10,10
.
The ARGB of the pixel in bitmap2
is 10,0,0,0
.
Why does DrawImage()
not draw as I expect?
How can I get the expected result?
I don't want to create my own color replacement method; I want the color mapping of .net to work correctly.
EDIT
I made another test, same 1 pixel image, but instead of ARGB 10,10,10,10
, I used ARGB 100,100,100,100
. The output pixel now has ARGB 100,99,99,99
.
This appears to me like a bug in GDI+ or .Net, but definitely not as an intended calculation output.
And, another improvement to ensure it's not caused by the 1 pixel width and height, I changed to
var bitmap = new Bitmap (5, 5, PixelFormat.Format32bppArgb);
bitmap.SetPixel(2,2,Color.FromArgb(100,100,100,100));
and again, the output pixel is ARGB 100,99,99,99
.
This looks like rounding errors now, but the 10,0,0,0
from above definitly is no rounding error.
EDIT 2
It all looks like rounding errors now: The calculation of the pixel color appears to round e.g. after a division (maybe dividing into an integer), so the rounding error is multiplicated at another multiplication.
This test uses a 16x16 with RGB 20,100,255 and Alpha 0 (upper left) to 255 (lower right).
The comparison of bitmap1 (left) and bitmap2 (right) in Beyond Compare, with results at the bottom (contrast of result image increased), shows that the differences are high at low alpha, and decrease towards 1 or 0 in RGB at high alpha:
Example values:
Pixel 0|0: Left = ARGB 0,20,100,255; Right = ARGB 0,0,0,0.
Pixel 1|0: Left = ARGB 1,20,100,255; Right = ARGB 1,0,0,255.
Pixel 2|0: Left = ARGB 2,20,100,255; Right = ARGB 2,0,127,255.
Pixel 3|0: Left = ARGB 3,20,100,255; Right = ARGB 3,0,85,255. (85 = 1/3*255 => obviously division by alpha 3)
Pixel 3|0: Left = ARGB 4,20,100,255; Right = ARGB 4,0,127,255. (127 = 2/4*255 => obviously division by alpha 4)
Pixel 5|0: Left = ARGB 5,20,100,255; Right = ARGB 5,0,102,255. (102 = 2/5*255 => obviously division by alpha 5)
Pixel 15|0: Left = ARGB 15,20,100,255; Right = ARGB 15,17,102,255. (17 = 1/15*255 => obviously division by alpha 15)
Pixel 14|15: Left = ARGB 254,20,100,255; Right = ARGB 254,20,100,254.
Pixel 15|15: Left = ARGB 255,20,100,255; Right = ARGB 255,20,100,255.
Is there an alternative way to draw partially transparent images?