~samwhited/xmpp

ref: a2ffaf710170d692a9289c2b428a4efa90c8e703 xmpp/color/color.go -rw-r--r-- 2.0 KiB
a2ffaf71Sam Whited all: update deps 3 years ago
                                                                                
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
// Copyright 2017 Sam Whited.
// 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.
package color

import (
	"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{
		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)
	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)
}