As I\'m bringing in images into my program, I want to determine if:
#1
Since posting my first answer here , I found out that the LockBits
command can actually convert image data to a desired pixel format. This means that, no matter the input, you can simply check the bytes 'as' 32 bit per pixel ARGB data. Since that format has 4-byte pixels, and the stride in the .Net framework is always a multiple of 4 bytes, the normally very important issue of correctly adjusting data reading to scanline lengths becomes irrelevant. This all vastly simplifies the code.
Of course, the first two checks from my other answer still apply; checking the HasAlpha
flag on the bitmap flags and the alpha on the palette entries of indexed formats is a very quick initial way to determine if an image can have transparency, before switching to the full data sweep.
I have also since found out that indexed png with alpha-capable palettes is actually a thing (though poorly supported in .Net), so only checking on a single alpha-capable colour on indexed formats is too naive.
With all that in mind, and a linq operation that turns the palette check into a one-liner, the final adjusted code becomes this:
public static Boolean HasTransparency(Bitmap bitmap)
{
// Not an alpha-capable color format. Note that GDI+ indexed images are alpha-capable on the palette.
if (((ImageFlags)bitmap.Flags & ImageFlags.HasAlpha) == 0)
return false;
// Indexed format, and no alpha colours in the image's palette: immediate pass.
if ((bitmap.PixelFormat & PixelFormat.Indexed) != 0 && bitmap.Palette.Entries.All(c => c.A == 255))
return false;
// Get the byte data 'as 32-bit ARGB'. This offers a converted version of the image data without modifying the original image.
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Int32 len = bitmap.Height * data.Stride;
Byte[] bytes = new Byte[len];
Marshal.Copy(data.Scan0, bytes, 0, len);
bitmap.UnlockBits(data);
// Check the alpha bytes in the data. Since the data is little-endian, the actual byte order is [BB GG RR AA]
for (Int32 i = 3; i < len; i += 4)
if (bytes[i] != 255)
return true;
return false;
}
This works for any input pixel format, be it paletted or not.