[PATCH gio] widget: use correct color in Icon
Export this patch
From: Egon Elbre <egonelbre@gmail.com>
iconvg seems to expect a linear premultiplied color.
Thanks. Is it easy to add a test that triggers
https://github.com/golang/go/issues/39526 without your change?
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
---
internal/f32color/rgba.go | 34 ++++++++++++++++++++++++++++++++
internal/f32color/rgba_test.go | 36 ++++++++++++++++++++++++++++++++++
widget/icon.go | 2 +-
3 files changed, 71 insertions(+), 1 deletion(-)
create mode 100644 internal/f32color/rgba_test.go
diff --git a/internal/f32color/rgba.go b/internal/f32color/rgba.go
index d1b7564..4fc2742 100644
--- a/internal/f32color/rgba.go
+++ b/internal/f32color/rgba.go
@@ -77,6 +77,40 @@ func NRGBAToRGBA(col color.NRGBA) color.RGBA {
}
}
+// NRGBAToLinearRGBA converts from non-premultiplied sRGB color to premultiplied linear RGBA color.
+//
+// Each component in the result is `c * alpha`, where `c` is the linear color.
+func NRGBAToLinearRGBA(col color.NRGBA) color.RGBA {
+ if col.A == 0xFF {
+ return color.RGBA(col)
+ }
+ c := LinearFromSRGB(col)
+ return color.RGBA{
+ R: uint8(c.R*255 + .5),
+ G: uint8(c.G*255 + .5),
+ B: uint8(c.B*255 + .5),
+ A: col.A,
+ }
+}
+
+// NRGBAToRGBA_PostAlpha converts from non-premultiplied sRGB color to premultiplied sRGB color.
+//
+// Each component in the result is `sRGBToLinear(c) * alpha`, where `c`
+// is the linear color.
+func NRGBAToRGBA_PostAlpha(col color.NRGBA) color.RGBA {
+ if col.A == 0xFF {
+ return color.RGBA(col)
+ } else if col.A == 0x00 {
+ return color.RGBA{}
+ }
+ return color.RGBA{
+ R: uint8(uint32(col.R) * uint32(col.A) / 0xFF),
+ G: uint8(uint32(col.G) * uint32(col.A) / 0xFF),
+ B: uint8(uint32(col.B) * uint32(col.A) / 0xFF),
+ A: col.A,
+ }
+}
+
// RGBAToNRGBA converts from premultiplied sRGB color to non-premultiplied sRGB color.
func RGBAToNRGBA(col color.RGBA) color.NRGBA {
if col.A == 0xFF {
diff --git a/internal/f32color/rgba_test.go b/internal/f32color/rgba_test.go
new file mode 100644
index 0000000..eba1262
--- /dev/null
+++ b/internal/f32color/rgba_test.go
@@ -0,0 +1,36 @@
+package f32color
+
+import (
+ "image/color"
+ "testing"
+)
+
+func TestNRGBAToRGBA_PostAlpha_Boundary(t *testing.T) {
+ for col := 0; col <= 0xFF; col++ {
+ for alpha := 0; alpha <= 0xFF; alpha++ {
+ in := color.NRGBA{R: uint8(col), A: uint8(alpha)}
+ premul := NRGBAToRGBA_PostAlpha(in)
+ if premul.A != uint8(alpha) {
+ t.Errorf("%v: got %v expected %v", in, premul.A, alpha)
+ }
+ if premul.R > premul.A {
+ t.Errorf("%v: R=%v > A=%v", in, premul.R, premul.A)
+ }
+ }
+ }
+}
+
+func TestNRGBAToLinearRGBA_Boundary(t *testing.T) {
+ for col := 0; col <= 0xFF; col++ {
+ for alpha := 0; alpha <= 0xFF; alpha++ {
+ in := color.NRGBA{R: uint8(col), A: uint8(alpha)}
+ premul := NRGBAToLinearRGBA(in)
+ if premul.A != uint8(alpha) {
+ t.Errorf("%v: got %v expected %v", in, premul.A, alpha)
+ }
+ if premul.R > premul.A {
+ t.Errorf("%v: R=%v > A=%v", in, premul.R, premul.A)
+ }
+ }
+ }
+}
diff --git a/widget/icon.go b/widget/icon.go
index f6f88d3..4e6350d 100644
--- a/widget/icon.go
+++ b/widget/icon.go
@@ -51,7 +51,7 @@ func (ic *Icon) image(sz int) paint.ImageOp {
img := image.NewRGBA(image.Rectangle{Max: image.Point{X: sz, Y: int(float32(sz) * dy / dx)}})
var ico iconvg.Rasterizer
ico.SetDstImage(img, img.Bounds(), draw.Src)
- m.Palette[0] = f32color.NRGBAToRGBA(ic.Color)
+ m.Palette[0] = f32color.NRGBAToLinearRGBA(ic.Color)
iconvg.Decode(&ico, ic.src, &iconvg.DecodeOptions{
Palette: &m.Palette,
})
--
2.26.2