package internal type HSVA struct { H float64 S float64 V float64 A uint8 } func (hsva HSVA) RGBA () (r, g, b, a uint32) { // Adapted from: // https://www.cs.rit.edu/~ncs/color/t_convert.html component := func (x float64) uint32 { return uint32(float64(0xFFFF) * x) } ca := uint32(hsva.A) << 8 s := clamp01(hsva.S) v := clamp01(hsva.V) if s == 0 { light := component(v) return light, light, light, ca } h := clamp01(hsva.H) * 360 sector := int(h / 60) offset := (h / 60) - float64(sector) fac := float64(hsva.A) / 255 p := component(fac * v * (1 - s)) q := component(fac * v * (1 - s * offset)) t := component(fac * v * (1 - s * (1 - offset))) va := component(v) switch sector { case 0: return va, t, p, ca case 1: return q, va, p, ca case 2: return p, va, t, ca case 3: return p, q, va, ca case 4: return t, p, va, ca default: return va, p, q, ca } } // Canon returns the color but with the H, S, and V fields are constrained to // the range 0.0-1.0 func (hsva HSVA) Canon () HSVA { hsva.H = clamp01(hsva.H) hsva.S = clamp01(hsva.S) hsva.V = clamp01(hsva.V) return hsva } func clamp01 (x float64) float64 { if x > 1.0 { return 1.0 } if x < 0.0 { return 0.0 } return x } func RGBAToHSVA (r, g, b, a uint32) HSVA { // Adapted from: // https://www.cs.rit.edu/~ncs/color/t_convert.html component := func (x uint32) float64 { return clamp01(float64(x) / 0xFFFF) } cr := component(r) cg := component(g) cb := component(b) var maxComponent float64 if cr > maxComponent { maxComponent = cr } if cg > maxComponent { maxComponent = cg } if cb > maxComponent { maxComponent = cb } var minComponent = 1.0 if cr < minComponent { minComponent = cr } if cg < minComponent { minComponent = cg } if cb < minComponent { minComponent = cb } hsva := HSVA { V: maxComponent, A: uint8(a >> 8), } delta := maxComponent - minComponent if delta == 0 { // hsva.S is undefined, so hue doesn't matter return hsva } hsva.S = delta / maxComponent switch { case cr == maxComponent: hsva.H = (cg - cb) / delta case cg == maxComponent: hsva.H = 2 + (cb - cr) / delta case cb == maxComponent: hsva.H = 4 + (cr - cg) / delta } hsva.H *= 60 if hsva.H < 0 { hsva.H += 360 } hsva.H /= 360 return hsva }