/
color.go
96 lines (85 loc) · 2.09 KB
/
color.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
// Copyright 2017 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.
// Package color implements XEP-0392: Consistent Color Generation v0.4.
package color
import (
/* #nosec */
"crypto/sha1"
"encoding/binary"
"hash"
"image/color"
"math"
)
// Size is the length of the hash output.
const Size = 2
// A list of color vision deficiencies.
const (
None uint8 = iota
RedGreen
Blue
)
// Hash returns a new hash.Hash computing the Y'CbCr color.
// For more information see Sum.
func Hash(cvd uint8) hash.Hash {
return digest{
/* #nosec */
Hash: sha1.New(),
cvd: cvd,
}
}
type digest struct {
hash.Hash
cvd uint8
}
func (d digest) Size() int { return Size }
func (d digest) Sum(b []byte) []byte {
b = d.Hash.Sum(b)
i := binary.LittleEndian.Uint16(b[:2])
switch d.cvd {
case None:
case RedGreen:
i &= 0x7fff
case Blue:
i = (i & 0x7fff) | (((i & 0x4000) << 1) ^ 0x8000)
default:
panic("color: invalid color vision deficiency")
}
angle := float64(i) / 65536 * 2 * math.Pi
cr, cb := math.Sincos(angle)
factor := 0.5 / math.Max(math.Abs(cr), math.Abs(cb))
cb, cr = cb*factor, cr*factor
b[0] = uint8(math.Min(math.Max(cb+0.5, 0)*255, 255))
b[1] = uint8(math.Min(math.Max(cr+0.5, 0)*255, 255))
return b[:Size]
}
// Sum returns a color in the Y'CbCr colorspace in the form [Cb, Cr] that is
// consistent for the same inputs.
//
// If a color vision deficiency constant is provided (other than None), the
// algorithm attempts to avoid confusable colors.
func Sum(data []byte, cvd uint8) [Size]byte {
b := make([]byte, 0, Size)
h := Hash(cvd)
/* #nosec */
h.Write(data)
b = h.Sum(b)
return [Size]byte{b[0], b[1]}
}
// Bytes converts a byte slice to a color.YCbCr.
//
// For more information see Sum.
func Bytes(b []byte, luma uint8, cvd uint8) color.YCbCr {
ba := Sum(b, cvd)
return color.YCbCr{
Y: luma,
Cb: ba[0],
Cr: ba[1],
}
}
// String converts a string to a color.YCbCr.
//
// For more information see Sum.
func String(s string, luma uint8, cvd uint8) color.YCbCr {
return Bytes([]byte(s), luma, cvd)
}