Fix but deprecate an implicit transparent color #0

This commit is contained in:
Rangi
2026-09-10 19:32:00 +02:00
committed by Eldred Habert
parent 3112239174
commit 25240e9fc0
9 changed files with 42 additions and 10 deletions
+1
View File
@@ -52,6 +52,7 @@ struct Rgba {
bool isTransparent() const { return alpha < transparency_threshold; }
static constexpr uint8_t opacity_threshold = 0xF0;
bool isOpaque() const { return alpha >= opacity_threshold; }
bool isAmbiguous() const { return isTransparent() == isOpaque(); }
// Computes the equivalent CGB color, respects the color curve depending on options
uint16_t cgbColor() const;
+3 -7
View File
@@ -585,15 +585,11 @@ for example because you want to use palette swaps, please use
.Fl c
to specify the palette explicitly.
.Pp
First, if the image contains
Note that if the image contains
.Em any
transparent pixel, color #0 of
transparent pixels, color #0 of
.Em all
palettes will be allocated to it.
This is done
.Sy even if palettes were explicitly specified using Fl c ;
then the specification only covers color #1 onwards.
.Pq If you do not want this, ask your image editor to remove the alpha channel.
palettes will be transparent.
.Pp
After generating palettes,
.Nm
+32 -3
View File
@@ -181,7 +181,7 @@ struct Image {
// Register colors from `png` into `colors`
for (uint32_t y = 0; y < png.height; ++y) {
for (uint32_t x = 0; x < png.width; ++x) {
if (Rgba const &color = pixel(x, y); color.isTransparent() == color.isOpaque()) {
if (Rgba const &color = pixel(x, y); color.isAmbiguous()) {
// Report ambiguously transparent or opaque colors
if (uint32_t css = color.toCSS(); ambiguous.find(css) == ambiguous.end()) {
error(
@@ -402,12 +402,41 @@ static std::pair<std::vector<size_t>, std::vector<Palette>>
makePalsAsSpecified(std::vector<ColorSet> const &colorSets) {
// Convert the palette spec to actual palettes
std::vector<Palette> palettes(options.palSpec.size());
bool gaveDeprecationWarning = false;
for (auto [spec, pal] : zip(options.palSpec, palettes)) {
bool skipFirst = false;
// If the image contains any transparent pixels, color #0 of all palettes is transparent.
// Thus, all explicit palette specs should leave color #0 as "#none" or transparent.
// If they specify an opaque color #0, we have legacy behavior of implicitly inserting
// a transparent color #0, and expecting the spec to only cover the subsequent colors.
if (options.hasTransparentPixels && spec.front().has_value() && spec.front()->isOpaque()) {
skipFirst = true;
if (!gaveDeprecationWarning) {
warning(
WARNING_OBSOLETE,
"Implicit transparent color #0 is deprecated; leave an explicit gap in the "
"palette specs"
);
gaveDeprecationWarning = true;
}
}
for (size_t i = 0; i < options.nbColorsPerPal; ++i) {
// If the spec has a gap, there's no need to copy anything.
if (spec[i].has_value() && spec[i]->isOpaque()) {
pal[i] = spec[i]->cgbColor();
if (!spec[i].has_value() || !spec[i]->isOpaque()) {
continue;
}
// If we're skipping color #0 as implicitly transparent, a full spec
// plus the implicit transparent color will be too large for a palette.
if (i + skipFirst >= options.nbColorsPerPal) {
error(
"Each palette spec can only contain up to %" PRIu8
" color%s plus the implict transparent color",
options.nbColorsPerPal - 1,
options.nbColorsPerPal - 1 == 1 ? "" : "s"
);
giveUp();
}
pal[i + skipFirst] = spec[i]->cgbColor();
}
}
+3
View File
@@ -0,0 +1,3 @@
warning: Implicit transparent color #0 is deprecated; leave an explicit gap in the palette specs [-Wobsolete]
error: Each palette spec can only contain up to 1 color plus the implict transparent color
Conversion aborted after 1 error
+1
View File
@@ -0,0 +1 @@
-c #0000FF,#FF0000 -s 2
Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

+1
View File
@@ -0,0 +1 @@
warning: Implicit transparent color #0 is deprecated; leave an explicit gap in the palette specs [-Wobsolete]
+1
View File
@@ -0,0 +1 @@
-c #0000FF,#FF0000
Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B