PB5.71b2 SaveImage() writes strange BMP files

Post bugreports for the Windows version here
User avatar
Regenduft
Enthusiast
Enthusiast
Posts: 121
Joined: Mon Mar 02, 2009 9:20 pm
Location: Germany

PB5.71b2 SaveImage() writes strange BMP files

Post by Regenduft »

PureBasic 5.71b2 (x86 and x64) on Windows 7 (x64)

SaveImage() often writes very strange BMPs. What "strange" actually means differs and is based on the color depth of the source image and the target color depth.

Let's start creating some test images in "%TMP%\PureBasic_BMP_Bug\":

Code: Select all

UsePNGImageEncoder()

CreateImage(0,32,32,32)
CreateImage(1,32,32,24)

For image = 0 To 1
  StartDrawing(ImageOutput(image))
  DrawingMode(#PB_2DDrawing_AllChannels)
  c = $11111111
  For y = 31 To 0 Step -1 ; BMPs are stored "bottom line first", so "Step -1" makes hex code inspection easier
    For x = 0 To 31
      Plot(x, y, c)
      If c <> $FFFFFFFF
        c + $11111111
      Else
        c = $11111111
      EndIf
    Next
  Next
  StopDrawing()
Next

dir$ = GetTemporaryDirectory() + "PureBasic_BMP_Bug" + #PS$
CreateDirectory( dir$ )

SaveImage(0,dir$+"bmp_32-to-32.bmp", #PB_ImagePlugin_BMP, 0, 32)
SaveImage(0,dir$+"bmp_32-to-24.bmp", #PB_ImagePlugin_BMP, 0, 24)
SaveImage(0,dir$+"bmp_32-to-8.bmp" , #PB_ImagePlugin_BMP, 0, 8)
SaveImage(0,dir$+"bmp_32-to-4.bmp" , #PB_ImagePlugin_BMP, 0, 4)
SaveImage(0,dir$+"bmp_32-to-1.bmp" , #PB_ImagePlugin_BMP, 0, 1)

SaveImage(1,dir$+"bmp_24-to-32.bmp", #PB_ImagePlugin_BMP, 0, 32)
SaveImage(1,dir$+"bmp_24-to-24.bmp", #PB_ImagePlugin_BMP, 0, 24)
SaveImage(1,dir$+"bmp_24-to-8.bmp" , #PB_ImagePlugin_BMP, 0, 8)
SaveImage(1,dir$+"bmp_24-to-4.bmp" , #PB_ImagePlugin_BMP, 0, 4)
SaveImage(1,dir$+"bmp_24-to-1.bmp" , #PB_ImagePlugin_BMP, 0, 1)
For me the results look like this:
Image

Although "bmp_32-to-32.bmp" looks good, as well as all the "bmp_24-to-*.bmp" files, if you take a deeper look, then ONLY "bmp_24-to-24.bmp" and "bmp_24-to-32.bmp" are actually completely correct. The Rest is in one or another way messed up...

So let's brake it down and inspect the files with any hex editor (but I won't mention the obvious wrong colors).


bmp_32-to-32.bmp

The alpha channel is saved, although (by specification) the 4th byte is "reserved" and "should be 0".
The funny thing is, that the alpha channel is stored when using SaveImage(), but gets stripped away when using LoadImage().

Since you can find some 32bit BMPs in the wild, that use the "reserved" byte for alpha channel (although this is against the specification), I personally would prefer to simply allow LoadImage() also to treat the "reserved" byte as the alpha channel, as long as the "reserved" bytes are not all together zeroes (This is exactly how MS handles 32bit bitmaps inside ICO files! Follow this link and see line 6).


bmp_32-to-24

This is completely nuts...

The pixel data start with this:
EF EF EF E1 E1 E1 D6 D6 D6 ...

While it should start like this:
11 11 11 22 22 22 33 33 33 ...


bmp_32-to-1

The color palette looks like this:
00 00 00 77 FF FF FF 00

So the first color again has $77 written in the "reserved" byte, while the second color looks as expected.
The pixel array is also very strange: It consists of %1 from beginning to end. So only the second color is used.


bmp_32-to-4

The color palette looks like this:
C3 C3 C3 77
C5 C5 C5 00
C5 C5 C5 00
C5 C5 C5 00
C7 C7 C7 00
D2 D2 D2 00
D4 D4 D4 00
D5 D5 D5 00
D7 D7 D7 00
E0 E0 E0 00
E4 E4 E4 00
E6 E6 E6 00
F0 F0 F0 77
F0 F0 F0 00
F8 F8 F8 00
FC FC FC 00

The source image was composed out of 15 colors ($11111111, $22222222, ..., $FFFFFFFF). So each palette color should have a distinct value, except a single one (the unused 16th color) which could basically have any random value. In reality some palette colors have multiple "twins".

Also very strange is that two palette colors have the "reserved" byte set to $77, while the rest has the expected $00.


bmp_32-to-8

Similar problems as with "bmp_32-to-4". The color palette has some non-zero "reserved" bytes, while most values are correctly zeroes. The distribution of these non-zero bytes seem completely random.


bmp_24-to-32

Everything's OK here! All "reserved" bytes have a value of zero and the actual color values are correct!


bmp_24-to-24

Everything's OK here! Three byte per color and every color value is correct!


bmp_24-to-1

Same wrong color palette as in "bmp_32-to-1", but the pixel array correctly refers to both colors in the palette!

The color palette looks like this:
00 00 00 77 FF FF FF 00

So the first color again has $77 written in the "reserved" byte, while the second color looks as expected.


bmp_24-to-4

The color palette looks like this:
19 19 19 77
1B 1B 1B 00
25 25 25 00
30 30 30 00
46 46 46 00
54 54 54 00
66 66 66 00
77 77 77 00
88 88 88 00
99 99 99 00
AA AA AA 00
BC BC BC 00
D0 D0 D0 77
DD DD DD 00
EE EE EE 00
F3 F3 F3 00

Again, you have the "reserved" byte set to $77 for two colors.

The color distribution also seems quite strange. The source image was composed out of 15 colors ($111111, $222222, ..., $FFFFFF). So each palette color should have a distinct value, except a single one (the unused 16th color) which could basically have any random value. In reality the darkest color starts with $191919 and the lightest color ends at $F3F3F3. So the 15 source colors are distributed over 16 palette colors, while start and endpoint are slightly off.


bmp_24-to-8

As always you have some "reserved" byte set to $77, but this time you have some other strange values like $65, $10 or $E0 mixed in, while still most palette colors have the correct $00.

The palette has all of the 15 source colors. But in addition on one hand it has a lot of redundancies (e.g. 20 times the color $111111) and some strange "inbetween" values (e.g. the following in a row: $111111, $121212, $141414, $171717).