image/color: have Palette.Index honor alpha for closest match, not just
red, green and blue.
Fixes #9902
Change-Id: Ibffd0aa2f98996170e39a919296f69e9d5c71545
Reviewed-on: https://go-review.googlesource.com/8907
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/image/color/color.go b/src/image/color/color.go
index 00bd8fd..cae059b 100644
--- a/src/image/color/color.go
+++ b/src/image/color/color.go
@@ -271,32 +271,39 @@
}
// Index returns the index of the palette color closest to c in Euclidean
-// R,G,B space.
+// R,G,B,A space.
func (p Palette) Index(c Color) int {
// A batch version of this computation is in image/draw/draw.go.
- cr, cg, cb, _ := c.RGBA()
- ret, bestSSD := 0, uint32(1<<32-1)
+ cr, cg, cb, ca := c.RGBA()
+ ret, bestSum := 0, uint32(1<<32-1)
for i, v := range p {
- vr, vg, vb, _ := v.RGBA()
- // We shift by 1 bit to avoid potential uint32 overflow in
- // sum-squared-difference.
- delta := (int32(cr) - int32(vr)) >> 1
- ssd := uint32(delta * delta)
- delta = (int32(cg) - int32(vg)) >> 1
- ssd += uint32(delta * delta)
- delta = (int32(cb) - int32(vb)) >> 1
- ssd += uint32(delta * delta)
- if ssd < bestSSD {
- if ssd == 0 {
+ vr, vg, vb, va := v.RGBA()
+ sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va)
+ if sum < bestSum {
+ if sum == 0 {
return i
}
- ret, bestSSD = i, ssd
+ ret, bestSum = i, sum
}
}
return ret
}
+// sqDiff returns the squared-difference of x and y, shifted by 2 so that
+// adding four of those won't overflow a uint32.
+//
+// x and y are both assumed to be in the range [0, 0xffff].
+func sqDiff(x, y uint32) uint32 {
+ var d uint32
+ if x > y {
+ d = x - y
+ } else {
+ d = y - x
+ }
+ return (d * d) >> 2
+}
+
// Standard colors.
var (
Black = Gray16{0}