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
118
119
|
package libtgsconverter
import "image/color"
type colorAxis uint8
// Color axis constants
const (
red colorAxis = iota
green
blue
)
type colorPriority struct {
p uint32
color.RGBA
}
func (c colorPriority) axis(span colorAxis) uint8 {
switch span {
case red:
return c.R
case green:
return c.G
default:
return c.B
}
}
type colorBucket []colorPriority
func (cb colorBucket) partition() (colorBucket, colorBucket) {
mean, span := cb.span()
left, right := 0, len(cb)-1
for left < right {
cb[left], cb[right] = cb[right], cb[left]
for cb[left].axis(span) < mean && left < right {
left++
}
for cb[right].axis(span) >= mean && left < right {
right--
}
}
if left == 0 {
return cb[:1], cb[1:]
}
if left == len(cb)-1 {
return cb[:len(cb)-1], cb[len(cb)-1:]
}
return cb[:left], cb[left:]
}
func (cb colorBucket) mean() color.RGBA {
var r, g, b uint64
var p uint64
for _, c := range cb {
p += uint64(c.p)
r += uint64(c.R) * uint64(c.p)
g += uint64(c.G) * uint64(c.p)
b += uint64(c.B) * uint64(c.p)
}
return color.RGBA{uint8(r / p), uint8(g / p), uint8(b / p), 255}
}
type constraint struct {
min uint8
max uint8
vals [256]uint64
}
func (c *constraint) update(index uint8, p uint32) {
if index < c.min {
c.min = index
}
if index > c.max {
c.max = index
}
c.vals[index] += uint64(p)
}
func (c *constraint) span() uint8 {
return c.max - c.min
}
func (cb colorBucket) span() (uint8, colorAxis) {
var R, G, B constraint
R.min = 255
G.min = 255
B.min = 255
var p uint64
for _, c := range cb {
R.update(c.R, c.p)
G.update(c.G, c.p)
B.update(c.B, c.p)
p += uint64(c.p)
}
var toCount *constraint
var span colorAxis
if R.span() > G.span() && R.span() > B.span() {
span = red
toCount = &R
} else if G.span() > B.span() {
span = green
toCount = &G
} else {
span = blue
toCount = &B
}
var counted uint64
var i int
var c uint64
for i, c = range toCount.vals {
if counted > p/2 || counted+c == p {
break
}
counted += c
}
return uint8(i), span
}
|