Allow fewer tRNS entries than PLTE colors (#1284)

This commit is contained in:
Rangi
2023-12-31 06:47:53 -05:00
committed by GitHub
parent 528a4c0b70
commit b0f2f0ffd6
7 changed files with 17 additions and 15 deletions

View File

@@ -16,7 +16,7 @@ struct Palette;
namespace sorting { namespace sorting {
void indexed(std::vector<Palette> &palettes, int palSize, png_color const *palRGB, void indexed(std::vector<Palette> &palettes, int palSize, png_color const *palRGB,
png_byte *palAlpha); int palAlphaSize, png_byte *palAlpha);
void grayscale(std::vector<Palette> &palettes, void grayscale(std::vector<Palette> &palettes,
std::array<std::optional<Rgba>, 0x8001> const &colors); std::array<std::optional<Rgba>, 0x8001> const &colors);
void rgb(std::vector<Palette> &palettes); void rgb(std::vector<Palette> &palettes);

View File

@@ -14,12 +14,12 @@
namespace sorting { namespace sorting {
void indexed(std::vector<Palette> &palettes, int palSize, png_color const *palRGB, void indexed(std::vector<Palette> &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"); 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]; 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) { for (Palette &pal : palettes) {

View File

@@ -83,6 +83,7 @@ class Png {
int colorType; int colorType;
int nbColors; int nbColors;
png_colorp embeddedPal = nullptr; png_colorp embeddedPal = nullptr;
int nbTransparentEntries;
png_bytep transparencyPal = nullptr; png_bytep transparencyPal = nullptr;
[[noreturn]] static void handleError(png_structp png, char const *msg) { [[noreturn]] static void handleError(png_structp png, char const *msg) {
@@ -116,8 +117,8 @@ public:
int getColorType() const { return colorType; } int getColorType() const { return colorType; }
std::tuple<int, png_const_colorp, png_bytep> getEmbeddedPal() const { std::tuple<int, png_const_colorp, int, png_bytep> getEmbeddedPal() const {
return {nbColors, embeddedPal, transparencyPal}; return {nbColors, embeddedPal, nbTransparentEntries, transparencyPal};
} }
uint32_t getWidth() const { return width; } uint32_t getWidth() const { return width; }
@@ -257,9 +258,8 @@ public:
height, bitDepth, colorTypeName(), interlaceTypeName()); height, bitDepth, colorTypeName(), interlaceTypeName());
if (png_get_PLTE(png, info, &embeddedPal, &nbColors) != 0) { if (png_get_PLTE(png, info, &embeddedPal, &nbColors) != 0) {
int nbTransparentEntries;
if (png_get_tRNS(png, info, &transparencyPal, &nbTransparentEntries, nullptr)) { 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: [", options.verbosePrint(Options::VERB_INTERM, "Embedded palette has %d colors: [",
@@ -268,7 +268,8 @@ public:
auto const &color = embeddedPal[i]; auto const &color = embeddedPal[i];
options.verbosePrint( options.verbosePrint(
Options::VERB_INTERM, "#%02x%02x%02x%02x%s", color.red, color.green, color.blue, 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 { } else {
options.verbosePrint(Options::VERB_INTERM, "No embedded palette\n"); options.verbosePrint(Options::VERB_INTERM, "No embedded palette\n");
@@ -510,7 +511,7 @@ struct AttrmapEntry {
static void generatePalSpec(Png const &png) { static void generatePalSpec(Png const &png) {
// Generate a palette spec from the first few colors in the embedded palette // 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) { if (embPalRGB == nullptr) {
fatal("`-c embedded` was given, but the PNG does not have an embedded palette!"); 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) { for (int i = 0; i < embPalSize; ++i) {
options.palSpec[0][i] = Rgba(embPalRGB[i].red, embPalRGB[i].green, embPalRGB[i].blue, 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<DefaultInitVec<size_t>, std::vector<Palette>>
} }
// "Sort" colors in the generated palettes, see the man page for the flowchart // "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) { if (embPalRGB != nullptr) {
sorting::indexed(palettes, embPalSize, embPalRGB, embPalAlpha); sorting::indexed(palettes, embPalSize, embPalRGB, embPalAlphaSize, embPalAlpha);
} else if (png.isSuitableForGrayscale()) { } else if (png.isSuitableForGrayscale()) {
sorting::grayscale(palettes, png.getColors().raw()); sorting::grayscale(palettes, png.getColors().raw());
} else { } else {

View File

@@ -90,6 +90,7 @@ class Png {
int colorType; int colorType;
int nbColors; int nbColors;
png_colorp embeddedPal = nullptr; png_colorp embeddedPal = nullptr;
int nbTransparentEntries;
png_bytep transparencyPal = nullptr; png_bytep transparencyPal = nullptr;
[[noreturn]] static void handleError(png_structp png, char const *msg) { [[noreturn]] static void handleError(png_structp png, char const *msg) {
@@ -186,9 +187,8 @@ public:
pixels.resize(static_cast<size_t>(width) * static_cast<size_t>(height)); pixels.resize(static_cast<size_t>(width) * static_cast<size_t>(height));
if (png_get_PLTE(png, info, &embeddedPal, &nbColors) != 0) { if (png_get_PLTE(png, info, &embeddedPal, &nbColors) != 0) {
int nbTransparentEntries;
if (png_get_tRNS(png, info, &transparencyPal, &nbTransparentEntries, nullptr)) { if (png_get_tRNS(png, info, &transparencyPal, &nbTransparentEntries, nullptr)) {
assert(nbTransparentEntries == nbColors); assert(nbTransparentEntries <= nbColors);
} }
} }

View File

View File

@@ -0,0 +1 @@
-Z

BIN
test/gfx/trns_lt_plte.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B