137 lines
4.5 KiB
Go
137 lines
4.5 KiB
Go
package helper
|
|
|
|
import (
|
|
"fmt"
|
|
"image/color"
|
|
"math"
|
|
"testing"
|
|
)
|
|
|
|
func TestLMSToXYZ(t *testing.T) {
|
|
for c := range Enum(false, true) {
|
|
want := collect3(LRGBtoXYZ(RGBtoLRGB(uint32(c.R), uint32(c.G), uint32(c.B))))
|
|
|
|
if got := collect3(LMStoXYZ(XYZtoLMS(want[0], want[1], want[2]))); !EqFloat64SliceFuzzy(want[:], got[:]) {
|
|
t.Errorf("LMStoXYZ(XYZtoLMS(%v)) = %v, want unchanged", want, got)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLMSToLRGB(t *testing.T) {
|
|
for c := range Enum(false, true) {
|
|
want := collect3(RGBtoLRGB(uint32(c.R), uint32(c.G), uint32(c.B)))
|
|
|
|
l, m, s := LRGBtoLMS(want[0], want[1], want[2])
|
|
|
|
// test via the optimized LMStoLRGB function.
|
|
if got := collect3(LMStoLRGB(l, m, s)); !EqFloat64SliceFuzzy(want[:], got[:]) {
|
|
t.Errorf("LMStoLRGB(LRGBtoLMS(%v)) = %v, want unchanged", want, got)
|
|
return
|
|
}
|
|
|
|
// make sure this is equivalent to going through the XYZ colourspace.
|
|
if got := collect3(XYZtoLRGB(LMStoXYZ(l, m, s))); !EqFloat64SliceFuzzy(want[:], got[:]) {
|
|
t.Errorf("XYZtoLRGB(LMStoXYZ(LRGBtoLMS(%v))) = %v, want unchanged", want, got)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOKLabToLMS(t *testing.T) {
|
|
for c := range Enum(false, true) {
|
|
want := collect3(LRGBtoLMS(RGBtoLRGB(uint32(c.R), uint32(c.G), uint32(c.B))))
|
|
if got := collect3(OkLabToLMS(LMStoOkLab(want[0], want[1], want[2]))); !EqFloat64SliceFuzzy(want[:], got[:]) {
|
|
t.Errorf("OkLabToLMS(LMStoOKLab(%v)) = %v, want unchanged", want, got)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOkLabExamplePairs(t *testing.T) {
|
|
// The page https://bottosson.github.io/posts/oklab/ lists example XYZ and OkLab pairs,
|
|
// with the results rounded to three decimal places.
|
|
examples := []struct{ xyz, lab [3]float64 }{
|
|
{[3]float64{0.950, 1.000, 1.089}, [3]float64{1.000, 0.000, 0.000}},
|
|
{[3]float64{1.000, 0.000, 0.000}, [3]float64{0.450, 1.236, -0.019}},
|
|
{[3]float64{0.000, 1.000, 0.000}, [3]float64{0.922, -0.671, 0.263}},
|
|
{[3]float64{0.000, 0.000, 1.000}, [3]float64{0.153, -1.415, -0.449}},
|
|
}
|
|
|
|
round := func(x float64) float64 {
|
|
return math.Round(x*1000) / 1000
|
|
}
|
|
|
|
round3 := func(a, b, c float64) [3]float64 {
|
|
return [3]float64{round(a), round(b), round(c)}
|
|
}
|
|
|
|
for i, e := range examples {
|
|
if gotLab := round3(LMStoOkLab(XYZtoLMS(e.xyz[0], e.xyz[1], e.xyz[2]))); gotLab != e.lab {
|
|
t.Errorf("pair %d: computed lab=%v, want=%v", i+1, gotLab, e.lab)
|
|
}
|
|
|
|
// note that the example table isn't suitable fo testing OkLab to XYZ conversion due to
|
|
// the errors introduced by rounding.
|
|
//
|
|
// we are depending the round trip conversions being correct, which is verified by TestLMSToXYZ and TestOKLabToLMS.
|
|
}
|
|
}
|
|
|
|
type testNXYZAColor [4]float64
|
|
|
|
func (c testNXYZAColor) RGBA() (_, _, _, _ uint32) {
|
|
panic("should not be called")
|
|
}
|
|
|
|
func (c testNXYZAColor) NXYZA() (_, _, _, _ float64) {
|
|
return c[0], c[1], c[2], c[3]
|
|
}
|
|
|
|
type testNOkLabAColor [4]float64
|
|
|
|
func (c testNOkLabAColor) RGBA() (_, _, _, _ uint32) {
|
|
panic("should not be called")
|
|
}
|
|
|
|
func (c testNOkLabAColor) NOkLabA() (_, _, _, _ float64) {
|
|
return c[0], c[1], c[2], c[3]
|
|
}
|
|
|
|
func TestColorToNOkLabA(t *testing.T) {
|
|
tests := []struct {
|
|
input color.Color
|
|
want [4]float64
|
|
}{
|
|
{
|
|
// test special NRGBA handling.
|
|
color.NRGBA{0x01, 0x23, 0x45, 0x67},
|
|
[4]float64{0.25462381167525894, -0.02293028913883799, -0.07098467472369072, float64(0x6767) / 0xffff},
|
|
}, {
|
|
// test special NRGBA64 handling.
|
|
color.NRGBA64{0x0123, 0x4567, 0x89ab, 0},
|
|
[4]float64{0.39601873251000413, -0.03369278598612779, -0.12401844116020128, 0},
|
|
}, {
|
|
// test a colour that can return its linear NRGBA values directly.
|
|
testNLRGBA{color.NRGBA64{0x0123, 0x4567, 0x89ab, 0xcdef}},
|
|
[4]float64{0.39601873251000413, -0.03369278598612779, -0.12401844116020128, float64(0xcdef) / 0xffff},
|
|
}, {
|
|
// test conversion of the values from a a colour that can return NXYZA values directly.
|
|
testNXYZAColor{0.95, 1., 1.089, .5},
|
|
// these were from the canonical test pairs, these values are 1, 0, 0 when rounded to the nearest thousandth.
|
|
[4]float64{0.9999686754143632, -0.0002580058168537569, -0.00011499756458199784, .5},
|
|
}, {
|
|
// test that we get the values from a colour that can return NOkLabA directly.
|
|
testNOkLabAColor{math.Inf(1), math.NaN(), math.Inf(-1), -1},
|
|
[4]float64{math.Inf(1), math.NaN(), math.Inf(-1), -1},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(fmt.Sprintf("%#+v", tt.input), func(t *testing.T) {
|
|
if got := collect4(ColorToNOkLabA(tt.input)); !EqFloat64SliceFuzzy(got[:], tt.want[:]) {
|
|
t.Errorf("ColorToNOkLabA(%#+v) = %v, want %v", tt.input, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|