mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 18:05:35 +00:00
widget: use correct color in Icon
iconvg seems to expect a linear premultiplied color. Fixes gio#132 Signed-off-by: Egon Elbre <egonelbre@gmail.com>
This commit is contained in:
@@ -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.
|
// RGBAToNRGBA converts from premultiplied sRGB color to non-premultiplied sRGB color.
|
||||||
func RGBAToNRGBA(col color.RGBA) color.NRGBA {
|
func RGBAToNRGBA(col color.RGBA) color.NRGBA {
|
||||||
if col.A == 0xFF {
|
if col.A == 0xFF {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// SPDX-License-Identifier: Unlicense OR MIT
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -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)}})
|
img := image.NewRGBA(image.Rectangle{Max: image.Point{X: sz, Y: int(float32(sz) * dy / dx)}})
|
||||||
var ico iconvg.Rasterizer
|
var ico iconvg.Rasterizer
|
||||||
ico.SetDstImage(img, img.Bounds(), draw.Src)
|
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{
|
iconvg.Decode(&ico, ic.src, &iconvg.DecodeOptions{
|
||||||
Palette: &m.Palette,
|
Palette: &m.Palette,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// SPDX-License-Identifier: Unlicense OR MIT
|
||||||
|
|
||||||
|
package widget
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gioui.org/layout"
|
||||||
|
"gioui.org/op"
|
||||||
|
"gioui.org/unit"
|
||||||
|
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIcon_Alpha(t *testing.T) {
|
||||||
|
icon, err := NewIcon(icons.ToggleCheckBox)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.Color = color.NRGBA{B: 0xff, A: 0x40}
|
||||||
|
|
||||||
|
gtx := layout.Context{
|
||||||
|
Ops: new(op.Ops),
|
||||||
|
Constraints: layout.Exact(image.Pt(100, 100)),
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = icon.Layout(gtx, unit.Sp(18))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user