gbdev/rgbds

RGBGFX bug

Closed this issue · 4 comments

This image of white text on a transparent background (reported in this Discord post):

font_nums.png

With rgbgfx -o font_nums.2bpp font_nums.png, it should be outputting gray text on a white background. Instead, it may output solid white (all $00s), or may just segfault with an assertion failure (assume(index < palette.size()); in TileData::rowBitplanes).

Note that this bug does not occur with the Rust rewrite; it gives this output (reconverted back to PNG):

font_nums_rust

This is the verbose output:

% ./rgbgfx -vvvvv -o /dev/null font_nums.png
rgbgfx v0.9.1-16-g0150eb4b
Options:
	Bit depth: 2bpp
	Maximum 8 palettes
	Palettes contain 4 colors
	No palette spec
	Input image slice: 0x0 pixels starting at (0, 0)
	Base tile IDs: [0, 0]
	Maximum 65535 tiles in bank 0, 0 in bank 1
	Input image: font_nums.png
	Output tile data: /dev/null
Ready.
Using libpng 1.6.45
Reading tiles...
Opened input file
PNG header signature is OK
Input image: 40x16 pixels, 8bpp RGB + alpha, not interlaced
No embedded palette
Image colors: [ #ffffffff, #00000000, ]
Image contains 1 proto-palette
[ $7fff, ]
Paginating palettes using "overload-and-remove" strategy...
Handling proto-palette 0
Assigning proto-palette 0 to new palette 0
{ [0] 7fff, } (volume = 1)
1 palettes before decanting
1 palettes after decanting on palettes
1 palettes after decanting on "components"
1 palettes after decanting on proto-palettes
{ [0] 7fff, } (volume = 1)
Proto-palette mappings: (1 palette)
0 -> 0
Sorting palette by grayscale bins...
{ 8000, 8000, 8000, }
Generating unoptimized tile data...
Assertion failed: (index < palette.size()), function rowBitplanes, file process.cpp, line 735.

Note, check whether the PNG's alpha indexes are valid within the palette. (See aaaaaa123456789/libplum@67a942f)

This change to Rgba::grayIndex in rgba.cpp is sufficient:

-       // Convert from [0; 256[ to [0; maxOpaqueColors[
-       return static_cast<uint16_t>(255 - red) * options.maxOpaqueColors() / 256;
+       // Convert from [0; 256[ to [hasTransparentPixels; nbColorsPerPal[
+       return static_cast<uint16_t>(255 - red) * options.maxOpaqueColors() / 256
+              + options.hasTransparentPixels;