1
2
3
4
5
6
7
8
9 package palette
10
11 import (
12 "image/color"
13 "math"
14 )
15
16
17
18 type HSVA struct {
19 H, S, V, A float64
20 }
21
22
23 var HSVAModel = color.ModelFunc(hsvaModel)
24
25 func hsvaModel(c color.Color) color.Color {
26 if _, ok := c.(HSVA); ok {
27 return c
28 }
29 return rgbaToHsva(c.RGBA())
30 }
31
32
33 func rgbaToHsva(r, g, b, a uint32) HSVA {
34 red := float64(r)
35 blue := float64(b)
36 green := float64(g)
37
38 max := math.Max(red, green)
39 max = math.Max(max, blue)
40 min := math.Min(red, green)
41 min = math.Min(min, blue)
42 chroma := max - min
43
44 var hue float64
45 switch {
46 case chroma == 0:
47
48
49
50 hue = 0
51 case max == red:
52 hue = math.Mod((green-blue)/chroma, 6)
53 case max == green:
54 hue = (blue-red)/chroma + 2
55 case max == blue:
56 hue = (red-green)/chroma + 4
57 }
58
59 hue /= 6
60
61 var s float64
62 if chroma != 0 {
63 s = chroma / max
64 }
65
66 return HSVA{
67 H: math.Mod(math.Mod(hue, 1)+1, 1),
68 S: s,
69 V: max / math.MaxUint16,
70 A: float64(a) / math.MaxUint16,
71 }
72 }
73
74
75 func (c HSVA) RGBA() (r, g, b, a uint32) {
76 var red, green, blue float64
77
78 a = uint32(math.MaxUint16 * c.A)
79
80 if c.V == 0 {
81 return
82 }
83
84 if c.S == 0 {
85 r, g, b = uint32(math.MaxUint16*c.V), uint32(math.MaxUint16*c.V), uint32(math.MaxUint16*c.V)
86 return
87 }
88
89 chroma := c.V * c.S
90 m := c.V - chroma
91
92 if !math.IsNaN(c.H) {
93 hue := math.Mod(c.H, 1) * 6
94 x := chroma * (1 - math.Abs(math.Mod(hue, 2)-1))
95 switch math.Floor(hue) {
96 case 0:
97 red, green = chroma, x
98 case 1:
99 red, green = x, chroma
100 case 2:
101 green, blue = chroma, x
102 case 3:
103 green, blue = x, chroma
104 case 4:
105 red, blue = x, chroma
106 case 5:
107 red, blue = chroma, x
108 }
109 } else {
110 red, green, blue = 0, 0, 0
111 }
112
113 r, g, b = uint32(math.MaxUint16*(red+m)), uint32(math.MaxUint16*(green+m)), uint32(math.MaxUint16*(blue+m))
114
115 return
116 }
117
View as plain text