From b0f2f0ffd6d383ccf5a96d8c361b51d65fbd9c8c Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sun, 31 Dec 2023 06:47:53 -0500 Subject: [PATCH] Allow fewer tRNS entries than PLTE colors (#1284) --- include/gfx/pal_sorting.hpp | 2 +- src/gfx/pal_sorting.cpp | 6 +++--- src/gfx/process.cpp | 19 ++++++++++--------- test/gfx/rgbgfx_test.cpp | 4 ++-- test/gfx/trns_lt_plte.err | 0 test/gfx/trns_lt_plte.flags | 1 + test/gfx/trns_lt_plte.png | Bin 0 -> 223 bytes 7 files changed, 17 insertions(+), 15 deletions(-) create mode 100644 test/gfx/trns_lt_plte.err create mode 100644 test/gfx/trns_lt_plte.flags create mode 100644 test/gfx/trns_lt_plte.png 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 0000000000000000000000000000000000000000..42ed9e81f73076afc403c954d61abe6181a42452 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDD3?#L31Vw-pXMj(LE08wH2y#QP;pcb8+LD$c7_nP7hTYJUQCA4`nhGTL@1Oaki99 z=u?}K)WuXBa!@2#B4YBY8(IPdtl5`Rcv%_UH)Q#(s7<&!hfknS!b4bm%3-!g2CNRL z2ip8xFCE?>q;r&`kV!nEOZ3&`sS4E!dJJBTF#@e`j`GZzm+$cGf>|CzONMm#@y)z) QK=&|sy85}Sb4q9e0Jhsj(EtDd literal 0 HcmV?d00001