-
-
Notifications
You must be signed in to change notification settings - Fork 26
/
gamut.go
117 lines (98 loc) · 2.3 KB
/
gamut.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package gamut
import (
"image/color"
"sort"
"strings"
colorful "github.com/lucasb-eyer/go-colorful"
"github.com/xrash/smetrics"
)
// A Palette is a collection of colors
type Palette struct {
colors map[color.Color]Colors
names map[string]color.Color
}
// MixedWith mixes two palettes
func (g Palette) MixedWith(p Palette) Palette {
np := Palette{}
np.AddColors(g.Colors())
np.AddColors(p.Colors())
return np
}
// AddColors adds colors to the palette
func (g *Palette) AddColors(cc Colors) {
if g.colors == nil {
g.colors = make(map[color.Color]Colors)
}
if g.names == nil {
g.names = make(map[string]color.Color)
}
for _, c := range cc {
found := false
for _, v := range g.colors[c.Color] {
if v.Name == c.Name {
found = true
break
}
}
if !found {
g.colors[c.Color] = append(g.colors[c.Color], c)
}
g.names[strings.ToUpper(c.Name)] = c.Color
}
}
// Colors returns the Palette's colors
func (g Palette) Colors() Colors {
var r Colors
for _, c := range g.colors {
r = append(r, c...)
}
return r
}
// Clamped expects a slice of colors and returns a slice of the nearest matching
// colors from the palette
func (g Palette) Clamped(cc []color.Color) Colors {
var r Colors
for _, c := range cc {
nm, _ := g.Name(c)
r = append(r, nm[0])
}
return r
}
// Color returns the color with a specific name
func (g Palette) Color(name string) (color.Color, bool) {
c, ok := g.names[strings.ToUpper(name)]
return c, ok
}
// Name returns the name of the closest matching color
func (g Palette) Name(color color.Color) (Colors, float64) {
var d float64 = -1
var m Colors
c, _ := colorful.MakeColor(color)
for _, v := range g.colors {
col, _ := colorful.MakeColor(v[0].Color)
if nd := col.DistanceLab(c); nd < d || d == -1 {
d = nd
m = Colors{}
m = append(m, v...)
}
}
return m, d
}
// Filter returns colors matching name
func (g Palette) Filter(name string) Colors {
s := strings.ToLower(name)
var c Colors
for _, v := range g.colors {
for _, vv := range v {
if strings.Contains(strings.ToLower(vv.Name), s) {
c = append(c, vv)
}
}
}
sort.Slice(c, func(i, j int) bool {
di := smetrics.WagnerFischer(strings.ToLower(c[i].Name), s, 1, 1, 2)
dj := smetrics.WagnerFischer(strings.ToLower(c[j].Name), s, 1, 1, 2)
return di < dj
})
return c
}