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))) | 	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 { | func okLabModel(c color.Color) color.Color { | ||||||
| 	switch c := c.(type) { | 	switch c := c.(type) { | ||||||
| 	case Color: | 	case Color: | ||||||
| @ -161,8 +169,7 @@ func okLabModel(c color.Color) color.Color { | |||||||
| 	case color.NRGBA64: | 	case color.NRGBA64: | ||||||
| 		return FromNRGBA(uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)) | 		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 NRGBAColor: | ||||||
| 	case interface{ NRGBA() (r, g, b, a uint32) }: |  | ||||||
| 		return FromNRGBA(c.NRGBA()) | 		return FromNRGBA(c.NRGBA()) | ||||||
|  |  | ||||||
| 	default: | 	default: | ||||||
| @ -170,5 +177,10 @@ func okLabModel(c color.Color) color.Color { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // Implements a color model for converting arbitrary colors to OKLab. | var ( | ||||||
| var Model = color.ModelFunc(okLabModel) | 	// 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 | // 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. | // doesn't know about, so I'm going to help them out. | ||||||
| func fixedNRGBAModel(c color.Color) color.Color { | 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() | 		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)} | 		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 { | 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() | 		r, g, b, a := c.NRGBA() | ||||||
| 		return color.NRGBA64{R: uint16(r), G: uint16(g), B: uint16(b), A: uint16(a)} | 		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) { | func testDistance(t *testing.T, c0, c1 Color) { | ||||||
| 	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 i, c0 := range colours { |  | ||||||
| 		for j, c1 := range colours { |  | ||||||
| 	d := Distance(c0, c1) | 	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, | 		// if they're the same color, or both are completely transparent, | ||||||
| 		// they should be perceived as identical. | 		// they should be perceived as identical. | ||||||
|  |  | ||||||
| 		if d != 0 { | 		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 { | 	} else { | ||||||
| 		// otherwise, there should be some kind of difference between them. | 		// otherwise, there should be some kind of difference between them. | ||||||
| 		if d <= 0 { | 		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) | 	d2 := Distance(c0, mid) + Distance(mid, c1) | ||||||
| 	if d2 < d { | 	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) | 		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