diff --git a/include/gfx/pal_sorting.hpp b/include/gfx/pal_sorting.hpp index ff4f2958..73957a3c 100644 --- a/include/gfx/pal_sorting.hpp +++ b/include/gfx/pal_sorting.hpp @@ -16,7 +16,7 @@ struct Palette; namespace sorting { void indexed(std::vector &palettes, int palSize, png_color const *palRGB, - png_byte *palAlpha); + int palAlphaSize, png_byte *palAlpha); void grayscale(std::vector &palettes, std::array, 0x8001> const &colors); void rgb(std::vector &palettes); diff --git a/src/gfx/pal_sorting.cpp b/src/gfx/pal_sorting.cpp index f5df6fbc..6d4c6744 100644 --- a/src/gfx/pal_sorting.cpp +++ b/src/gfx/pal_sorting.cpp @@ -14,12 +14,12 @@ namespace sorting { void indexed(std::vector &palettes, int palSize, png_color const *palRGB, - png_byte *palAlpha) { + int palAlphaSize, png_byte *palAlpha) { options.verbosePrint(Options::VERB_LOG_ACT, "Sorting palettes using embedded palette...\n"); - auto pngToRgb = [&palRGB, &palAlpha](int index) { + auto pngToRgb = [&palRGB, &palAlphaSize, &palAlpha](int index) { auto const &c = palRGB[index]; - return Rgba(c.red, c.green, c.blue, palAlpha ? palAlpha[index] : 0xFF); + return Rgba(c.red, c.green, c.blue, palAlpha && index < palAlphaSize ? palAlpha[index] : 0xFF); }; for (Palette &pal : palettes) { diff --git a/src/gfx/process.cpp b/src/gfx/process.cpp index c3929156..513211b7 100644 --- a/src/gfx/process.cpp +++ b/src/gfx/process.cpp @@ -83,6 +83,7 @@ class Png { int colorType; int nbColors; png_colorp embeddedPal = nullptr; + int nbTransparentEntries; png_bytep transparencyPal = nullptr; [[noreturn]] static void handleError(png_structp png, char const *msg) { @@ -116,8 +117,8 @@ public: int getColorType() const { return colorType; } - std::tuple getEmbeddedPal() const { - return {nbColors, embeddedPal, transparencyPal}; + std::tuple getEmbeddedPal() const { + return {nbColors, embeddedPal, nbTransparentEntries, transparencyPal}; } uint32_t getWidth() const { return width; } @@ -257,9 +258,8 @@ public: height, bitDepth, colorTypeName(), interlaceTypeName()); if (png_get_PLTE(png, info, &embeddedPal, &nbColors) != 0) { - int nbTransparentEntries; if (png_get_tRNS(png, info, &transparencyPal, &nbTransparentEntries, nullptr)) { - assert(nbTransparentEntries == nbColors); + assert(nbTransparentEntries <= nbColors); } options.verbosePrint(Options::VERB_INTERM, "Embedded palette has %d colors: [", @@ -268,7 +268,8 @@ public: auto const &color = embeddedPal[i]; options.verbosePrint( Options::VERB_INTERM, "#%02x%02x%02x%02x%s", color.red, color.green, color.blue, - transparencyPal ? transparencyPal[i] : 0xFF, i != nbColors - 1 ? ", " : "]\n"); + transparencyPal && i < nbTransparentEntries ? transparencyPal[i] : 0xFF, + i != nbColors - 1 ? ", " : "]\n"); } } else { options.verbosePrint(Options::VERB_INTERM, "No embedded palette\n"); @@ -510,7 +511,7 @@ struct AttrmapEntry { static void generatePalSpec(Png const &png) { // Generate a palette spec from the first few colors in the embedded palette - auto [embPalSize, embPalRGB, embPalAlpha] = png.getEmbeddedPal(); + auto [embPalSize, embPalRGB, embPalAlphaSize, embPalAlpha] = png.getEmbeddedPal(); if (embPalRGB == nullptr) { fatal("`-c embedded` was given, but the PNG does not have an embedded palette!"); } @@ -523,7 +524,7 @@ static void generatePalSpec(Png const &png) { } for (int i = 0; i < embPalSize; ++i) { options.palSpec[0][i] = Rgba(embPalRGB[i].red, embPalRGB[i].green, embPalRGB[i].blue, - embPalAlpha ? embPalAlpha[i] : 0xFF); + embPalAlpha && i < embPalAlphaSize ? embPalAlpha[i] : 0xFF); } } @@ -559,9 +560,9 @@ static std::tuple, std::vector> } // "Sort" colors in the generated palettes, see the man page for the flowchart - auto [embPalSize, embPalRGB, embPalAlpha] = png.getEmbeddedPal(); + auto [embPalSize, embPalRGB, embPalAlphaSize, embPalAlpha] = png.getEmbeddedPal(); if (embPalRGB != nullptr) { - sorting::indexed(palettes, embPalSize, embPalRGB, embPalAlpha); + sorting::indexed(palettes, embPalSize, embPalRGB, embPalAlphaSize, embPalAlpha); } else if (png.isSuitableForGrayscale()) { sorting::grayscale(palettes, png.getColors().raw()); } else { diff --git a/test/gfx/rgbgfx_test.cpp b/test/gfx/rgbgfx_test.cpp index c1c1bc59..b8c0650a 100644 --- a/test/gfx/rgbgfx_test.cpp +++ b/test/gfx/rgbgfx_test.cpp @@ -90,6 +90,7 @@ class Png { int colorType; int nbColors; png_colorp embeddedPal = nullptr; + int nbTransparentEntries; png_bytep transparencyPal = nullptr; [[noreturn]] static void handleError(png_structp png, char const *msg) { @@ -186,9 +187,8 @@ public: pixels.resize(static_cast(width) * static_cast(height)); if (png_get_PLTE(png, info, &embeddedPal, &nbColors) != 0) { - int nbTransparentEntries; if (png_get_tRNS(png, info, &transparencyPal, &nbTransparentEntries, nullptr)) { - assert(nbTransparentEntries == nbColors); + assert(nbTransparentEntries <= nbColors); } } diff --git a/test/gfx/trns_lt_plte.err b/test/gfx/trns_lt_plte.err new file mode 100644 index 00000000..e69de29b diff --git a/test/gfx/trns_lt_plte.flags b/test/gfx/trns_lt_plte.flags new file mode 100644 index 00000000..2e52e40e --- /dev/null +++ b/test/gfx/trns_lt_plte.flags @@ -0,0 +1 @@ +-Z diff --git a/test/gfx/trns_lt_plte.png b/test/gfx/trns_lt_plte.png new file mode 100644 index 00000000..42ed9e81 Binary files /dev/null and b/test/gfx/trns_lt_plte.png differ