As I'm bringing in images into my program, I want to determine if:
- they have an alpha-channel
- if that alpha-channel is used
#1 is simple enough with using Image.IsAlphaPixelFormat
. For #2 though, other than looping through every single pixel, is there a simple way I can determine if at least one of the pixels has an alpha channel that is used (i.e. set to some other value than 255
)? All I need back is a boolean and then I'll make determination as to whether to save it out to 32-bit or 24-bit.
UPDATE: I have discovered that ImageFlags.HasTranslucent should provide me with what I'm looking for - unfortunately, it doesn't work at all. For example, PNGs with pixel formats that have at least alpha channel of 66 (semi-transparent) continue to report False
(Usage: if((img.Flags & ImageFlags.HasTranslucent) == 4) ...;
). I've tested on all types of images, including .bmp that have an alpha value >0 and <255 and it still reports False
. Anyone ever use this and know if it even works in GDI+?
Combining a bunch of methods for different types of images got me this final method, which seems to do a good job for any image you dump into it, be it a potentially transparent gif or a png containing an alpha channel. Thanks to Elmo's answer for the fast byte reading method.
Side note: do not use
Image.IsAlphaPixelFormat(bitmap.PixelFormat))
; it sees paletted formats as non-alpha-capable, while such images can in fact possess transparency. Just, not the 'alpha' kind. Such transparency-enabled 8-bit images do have the HasAlpha flag enabled, though, so that's still a useful check.[[Note: I have since vastly simplified this logic. See my other answer.]]
I get a more advanced solution, based on ChrisF answer:
It has a optional bg color string to non transparent images:
Example of usage:
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:
This works for any input pixel format, be it paletted or not.
You won't find a solution better than this, it took me hours to optimize:
You don't have to loop through every pixel (well you might, but it depends on the image). Set up to loop over all the pixels, but just break out of the loop when you find an alpha value other than 255 use the following pseudo code:
You'll only have to check all the pixels for images that don't have any alpha. For images that do have alpha this will break out quite quickly.