Monogame: BGR bitmap swapped red and blue channels

Created on 10 Jun 2016  路  21Comments  路  Source: MonoGame/MonoGame

I wanted to set up a little sandbox project to mess around in, and tried to load and draw the Icon bitmap that comes with the template. The result is this
image
Opening in a text editor, I see BGR in front so I guess that's the format it's in, but it's interpreted by MG as RGB. I set the textureformat in the pipeline tool to color, since that only seems to say something about compression, it doesn't imply RGBA, right? After debugging a bit I found out FreeImage gets the channel masks as

R: 11111111 00000000 00000000, G: 00000000 11111111 00000000, B: 00000000 00000000 11111111

Now that's wrong right? Shouldn't this figure out the right masks based on the header? @KonajuGames

Help Wanted

All 21 comments

Which template? DesktopGL? I'll have to test that.

Jep

The Icon BMP in the DesktopGL template is a 32bit BMP, ARGB coded. It's not a standard 24bit BMP. It has to be like this for the icon to be loaded with transparency.

Yes, it is 32 bit, but I left out the alpha channel. I'm pretty sure it's ABGR though, checking the values in the debugger shows higher values in the third channel than the first, also opening in a text editor shows BGR somewhere at the start.

Verified to be BGRA.

Thanks! That means this is a bug in FreeImage right?

I don't know, this kind of BMP doesn't look to be super standard, maybe the header of this file are not correct/standard. We'll have to test with more 32bit BMP (both "X8R8G8B8" and "A8R8G8B8"). I would be surprised that FreeImage doesn't support the full spec.

The thumbnail in VS displays the correct image though, as do Windows Photos and Microsoft Paint

If I remember the code correctly, the channels are swapped always for 32bits bitmaps.
Try with any icon from the test assets, if it is shown correctly TextureImporter is treating every bitmap as RGBA

FreeImage gives us enough info to determine if we need to swap the
channels. I'll do a PR this weekend.

I have just run a little test on the mentioned bmp and compared its raw data with the one of the logos in the test assets.
The conclusion is that the problem lays inside FreeImage. The test texture brown area is BGRA={0, 60, 231, 255} while the icon bitmap is BGRA={255, 0 ,60 ,231}, all this after format conversion and with the channel swapping disabled. This means that the channels are shifted, but FreeImage does not recognize the difference between ABGR and BGRA formats

I'm thinking that FreeImage reads the file header as BITMAPV2INFOHEADER or BITMAPV3INFOHEADER while the file uses BITMAPV5INFOHEADER (headers can be seen here, note that v2 and v3 are undocumented, while v4 and v5 can be found at msdn, a fast overview can be seen in the following link, concretelly in this image)

That would make sense, v4/v5 are Microsoft only, I believe. It could be a design choice. Maybe we only have to check v4/v5 headers and manually sort the channels.

@KonajuGames - Did this get fixed?

I'll check tonight.

I've now confirmed that FreeImage does not support higher than BITMAPINFOHEADER. What's worse is that you can request the bitmap info header, and FreeImage has modified the biSize parameter to 0x28, replacing the 0x7c that is in the file, and it actively ignores the channel masks that are in the file. This makes it impossible to use FreeImage for this case.

My approach now will be to fix the conflict in #6008, then use StbSharp to load BMP, PNG, JPG and GIF in the content pipeline as well as Texture2D.FromStream(). This leaves FreeImage to load the more obscure and little used image formats.

Wouldn't it be better to use something that is being actively developed and maintained, like ImageSharp, for the Content Pipeline?

Wouldn't it be better

No... at least not today. Enter a new issue if we want to discuss something for the future.

I took a look at ImageSharp code. It does not support anything beyond BITMAPINFOHEADER either, same as FreeType. StbSharp does support V5.

I've got StbSharp in the TextureImporter now, and it loads the V5 BMP fine. It does not however support 1-bit monochrome BMP, which we have a unit test for, but I'm certain that no-one has ever used. 1-bit monochrome BMPs may have been used a bit in the late 80's and early 90's, but I'm of the opinion that we can drop support for them now.

PR #6218 has been submitted to fix this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Legendree picture Legendree  路  3Comments

MichaelDePiazzi picture MichaelDePiazzi  路  4Comments

griseus picture griseus  路  5Comments

dazinator picture dazinator  路  5Comments

monsieurmax picture monsieurmax  路  5Comments