Explicitly declare the NRGBA color interface.
This commit is contained in:
		
							
								
								
									
										20
									
								
								oklab.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								oklab.go
									
									
									
									
									
								
							| @ -149,6 +149,14 @@ func Distance(a, b Color) float64 { | ||||
| 	return math.Sqrt(max(sqr(dL), sqr(dL+dA)) + max(sqr(da), sqr(da+dA)) + max(sqr(db), sqr(db+dA))) | ||||
| } | ||||
|  | ||||
| // NRGBAColor represent a color that can give us non pre-multiplied RGBA components. | ||||
| // | ||||
| // This isn't a standard interface, but we implement it and check for it regardless. | ||||
| type NRGBAColor interface { | ||||
| 	color.Color | ||||
| 	NRGBA() (r, g, b, a uint32) | ||||
| } | ||||
|  | ||||
| func okLabModel(c color.Color) color.Color { | ||||
| 	switch c := c.(type) { | ||||
| 	case Color: | ||||
| @ -161,8 +169,7 @@ func okLabModel(c color.Color) color.Color { | ||||
| 	case color.NRGBA64: | ||||
| 		return FromNRGBA(uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)) | ||||
|  | ||||
| 	// This isn't a standard interface, but I'm going to check for it regardless. | ||||
| 	case interface{ NRGBA() (r, g, b, a uint32) }: | ||||
| 	case NRGBAColor: | ||||
| 		return FromNRGBA(c.NRGBA()) | ||||
|  | ||||
| 	default: | ||||
| @ -170,5 +177,10 @@ func okLabModel(c color.Color) color.Color { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Implements a color model for converting arbitrary colors to OKLab. | ||||
| var Model = color.ModelFunc(okLabModel) | ||||
| var ( | ||||
| 	// A color model for converting arbitrary colors to OKLab. | ||||
| 	Model = color.ModelFunc(okLabModel) | ||||
|  | ||||
| 	// Type assertions. | ||||
| 	_ NRGBAColor = Color{} | ||||
| ) | ||||
|  | ||||
| @ -59,7 +59,7 @@ func Test_delinearize(t *testing.T) { | ||||
| // The NRGBA and NRGBA64 models don't have sensible ways to recover transparent colors from types it | ||||
| // doesn't know about, so I'm going to help them out. | ||||
| func fixedNRGBAModel(c color.Color) color.Color { | ||||
| 	if c, ok := c.(interface{ NRGBA() (r, g, b, a uint32) }); ok { | ||||
| 	if c, ok := c.(NRGBAColor); ok { | ||||
| 		r, g, b, a := c.NRGBA() | ||||
| 		return color.NRGBA{R: uint8(r >> 8), G: uint8(g >> 8), B: uint8(b >> 8), A: uint8(a >> 8)} | ||||
| 	} | ||||
| @ -68,7 +68,7 @@ func fixedNRGBAModel(c color.Color) color.Color { | ||||
| } | ||||
|  | ||||
| func fixedNRGBA64Model(c color.Color) color.Color { | ||||
| 	if c, ok := c.(interface{ NRGBA() (r, g, b, a uint32) }); ok { | ||||
| 	if c, ok := c.(NRGBAColor); ok { | ||||
| 		r, g, b, a := c.NRGBA() | ||||
| 		return color.NRGBA64{R: uint16(r), G: uint16(g), B: uint16(b), A: uint16(a)} | ||||
| 	} | ||||
| @ -149,31 +149,38 @@ func Test_Model(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestDistance(t *testing.T) { | ||||
| 	colours := []Color{ | ||||
| 		FromNRGBA(0xffff, 0xffff, 0xffff, 0xffff), | ||||
| 		FromNRGBA(0xffff, 0xffff, 0xffff, 0x7fff), | ||||
| 		FromNRGBA(0xffff, 0xffff, 0xffff, 0x0000), | ||||
| 		FromNRGBA(0x0000, 0x0000, 0x0000, 0xffff), | ||||
| 		FromNRGBA(0x0000, 0x0000, 0x0000, 0x7fff), | ||||
| 		FromNRGBA(0x0000, 0x0000, 0x0000, 0x0000), | ||||
| 	} | ||||
| func testDistance(t *testing.T, c0, c1 Color) { | ||||
|  | ||||
| 	for i, c0 := range colours { | ||||
| 		for j, c1 := range colours { | ||||
| 	d := Distance(c0, c1) | ||||
|  | ||||
| 			if i == j || (c0.A == 0 && c1.A == 0) { | ||||
| 	if math.IsNaN(d) || math.IsInf(d, 0) { | ||||
| 		t.Errorf("Distance(%v, %v) = %f, want finite", c0, c1, d) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if d < 0 { | ||||
| 		t.Errorf("Distance(%v, %v) = %f, want %f >= 0", c0, c1, d, d) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if d2 := Distance(c1, c0); d2 != d { | ||||
| 		t.Errorf("Distance(%v, %v) != Distance(%v, %v), want %f == %f", c1, c0, c0, c1, d, d2) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if c0 == c1 || (c0.A == 0 && c1.A == 0) { | ||||
| 		// if they're the same color, or both are completely transparent, | ||||
| 		// they should be perceived as identical. | ||||
|  | ||||
| 		if d != 0 { | ||||
| 					t.Errorf("Distance(%v, %v) = %v, want 0", c0, c1, d) | ||||
| 			t.Errorf("Distance(%v, %v) = %f, want %f == 0", c0, c1, d, d) | ||||
| 			return | ||||
| 		} | ||||
| 	} else { | ||||
| 		// otherwise, there should be some kind of difference between them. | ||||
| 		if d <= 0 { | ||||
| 					t.Errorf("Distance(%v, %v) = %v, want > 0", c0, c1, d) | ||||
| 			t.Errorf("Distance(%v, %v) = %f, want %f > 0", c0, c1, d, d) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -189,7 +196,23 @@ func TestDistance(t *testing.T) { | ||||
| 	d2 := Distance(c0, mid) + Distance(mid, c1) | ||||
| 	if d2 < d { | ||||
| 		t.Errorf("Distance(%v, %v)+Distance(%v, %v) < Distance(%v, %v), want %f >= %f", c0, mid, mid, c1, c0, c1, d2, d) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestDistance(t *testing.T) { | ||||
| 	colours := []Color{ | ||||
| 		FromNRGBA(0xffff, 0xffff, 0xffff, 0xffff), | ||||
| 		FromNRGBA(0xffff, 0xffff, 0xffff, 0x7fff), | ||||
| 		FromNRGBA(0xffff, 0xffff, 0xffff, 0x0000), | ||||
| 		FromNRGBA(0x0000, 0x0000, 0x0000, 0xffff), | ||||
| 		FromNRGBA(0x0000, 0x0000, 0x0000, 0x7fff), | ||||
| 		FromNRGBA(0x0000, 0x0000, 0x0000, 0x0000), | ||||
| 	} | ||||
|  | ||||
| 	for _, c0 := range colours { | ||||
| 		for _, c1 := range colours { | ||||
| 			testDistance(t, c0, c1) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user