-
-
Notifications
You must be signed in to change notification settings - Fork 316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BMP: Support fake alpha in BMPImageReader #727
Comments
Thank you for your work and the PR! I think I understand your use case, and unfortunately transparency in BMPs is a feature that seems to be a bit of an afterthought. Causing different implementations, which doesn't adhere to spec... I guess the fact that formats like Microsofts own ICO will put alpha values in the BMP (DIB) structure just like this "fake" alpha, without writing BI_BITFIELDS or BI_ALPHA_BITFIELDS doesn't help either... Anyway, I think that However, the extra bits (alpha values) are kept in the data, even if they aren't displayed as transparency. They are just ignored. You can convert it back to transparency like this (quick and dirty implementation, will only work for 32 bit packed with the normal channel ordering); int[] rgba = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
BufferedImage tmp = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
tmp.setRGB(0, 0, image.getWidth(), image.getHeight(), rgba, 0, image.getWidth());
image = tmp; I think the best/cleanest way to implement a way to "force" the decoder to treat the extra bits as transparency would be to do it using the |
Is there a way to determine if the original BMP used 32 bpp? |
Yes. If the bitmap info header says the bit count is 32, then... it's 32 bits/pixel. If that's what you mean? If the bit count is 24, then there is obviously no ambiguity. And if the bit count is 32 and masks are present (ie. BI_BITFIELDS or BI_ALPHA_BITFIELDS) there is no ambiguity; masks decide. However, when the bit count is 32 and there are no masks, the pixel format is supposed to be RGBx, where x must be 0 for all pixels. The ambiguity starts when we have 32 bits/pixel, no masks and an x > 0... This is BMP "fake alpha". And the problem is that we (the decoder) can't know the intention of the values (could be alpha channel, could be garbage from an uninitialized buffer or just random noise of some sort). Of course, if you are also "the encoder" of this file or know its origin, you could know what the intention is, and then force the values to become transparency if you like. So I think it makes the most sense to allow that as an option. |
Sorry, I should have been more clear. I meant, is there a way to get that information from the final I think that
would probably work? |
This is what I ended up with: if (image.getType() == BufferedImage.TYPE_INT_RGB) {
int[] bandMasks = {0xff0000, 0xff00, 0xff, 0xff000000};
WritableRaster raster = Raster.createPackedRaster(
image.getRaster().getDataBuffer(),
image.getWidth(),
image.getHeight(),
image.getWidth(),
bandMasks,
null
);
image = new BufferedImage(ColorModel.getRGBdefault(), raster, false, null);
} |
👍🏻That should be fairly safe. It’s also much faster than my initial suggestion, as you don’t duplicate the data buffer/copy pixel values. If you want to be really sure, you could also scan the pixels for non-zero alpha values as you outlined above in the initial request, to avoid a completely transparent image. |
Is your feature request related to a use case or a problem you are working on? Please describe.
Some user-supplied BMP images use fake alpha. Meaning that even though they use RGB compression,
Describe the solution you'd like
Use a heuristic to determine if a BMP is using fake alpha. In particular, if any of the unused bits are non-zero for any pixel when using 32 bpp and a compression method of RGB (no bitfields), then assume it is used as alpha.
Describe alternatives you've considered
Another alternative would be to unconditionally assume that if there are 32 bpp it is using fake alpha. But that isn't necessarily a good assumption, and I don't even know if it is more common for BMPs with 32 bpp to use fake alpha or not.
** Possible implementations **
This is a little tricky because you can't know if the image is using an alpha channel until you have read the pixels.
I can think of a few ways to do this:
getRawImageType
do a pass over the pixels if the bitCount is 32 andhasMasks
is false to determine if any unused bits are usedgetRawImageType
returnTYPE_INT_ARGB
if the bitCount is 32 andhasMasks
is false, then inread(
we keep track of whether we have encountered any pixels with a non-zero alpha. Then if all pizels have an alpha of zero, change them all to have an alpha of 255. And possibly if we encounter a pizel with an alpha of zero, but non-zero RGB, then convert all previous pixels to be opaque, and switch into a mode where we set all future pixels to be opaque. (or maybe there at the end we just create a new BufferedImage with a different colormodel that ignores the alpha?).Additional context
See the q/rgb32fakealpha.bmp in the bmp suite
The text was updated successfully, but these errors were encountered: