Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SkiaSharp.SKBitmap as alternative to System.Drawing.Bitmap doesn't work as expected

Tags:

c#

skiasharp

I have a working c# code that create a System.Drawing.Bitmap:

byte[] logoBytes = decodeBase64SafeWeb(json["logo.png"].ToString());
using (Bitmap bitmapold = (Bitmap)Bitmap.FromStream(new MemoryStream(logoBytes)))
{
    // do my code with bitmapold;
}

I want to replace the usage of System.Drawing library with SkiaSharp, tried following code instead:

byte[] logoBytes = decodeBase64SafeWeb(json["logo.png"].ToString());    
using (var stream = new SKMemoryStream(logoBytes))
using (var bitmap = SKBitmap.Decode(stream))
{
    // do my code with bitmap
}

Seems that pixels order is different in bitmap and bitmapold. in "do my code" I iterate over the bitmap and get pixels as follow:

for (int i = 0; i < bmp.Height; i++)
{
    // pass through each row
    for (int j = 0; j < bmp.Width; j++)
    {
        Color pixel = bmp.GetPixel(j, i);
        // ...
    }
}

For bitmapold (System.Draawing) => all first pixels have real values, while in bitmap (Skiasharp) - all first pixelsare zeros.

I tried to compare the non-zero pixels in bitmap and bitmapold, but failed to do it because bitmaphold pixels are not exposed. Also I tried get bitmap directly from byte[] and not from stream. Also added imageStream.seek(0, SeekOrigin.Begin); as see here: SKBitmap.Decode(imageStream) is returning null but got same results.

like image 508
RiB Avatar asked Jan 22 '26 13:01

RiB


1 Answers

The PixelFormat of the Bitmap is Format32bppArgb and ColorType/AlphaType of the SKBitmap is Bgra8888 / Premul

Alright, this may be the cause of the difference then. The SKBitmap is decoded with premultiplied alpha. It means that for completely transparent pixels the only valid ARGB value is #00000000, whereas the GDI+ Bitmap was decoded with straight alpha, where transparent pixels may have any RGB values. Just as an example, the ARGB value of Color.Transparent is actually #00FFFFFF (white transparent), though it is rendered exactly the same way as any other color with zero alpha.

If you compare the images pixel by pixel you should consider the pixels equal if their alpha is zero. Bitmap.GetPixel actually un-premultiplies the pixels but if A is zero in a premultiplied bitmap, the original RGB values are completely lost.

When comparing pixels with alpha you should take this in consideration. You can also convert the images in your test to use the same pixel format before comparing them (feel free to use my conversion methods for GDI+ and SkiaSharp). Please also note that you might want to allow at least 1 shade difference in the RGB values after the conversion (source).

like image 78
György Kőszeg Avatar answered Jan 25 '26 17:01

György Kőszeg