blob: cae059b6daa6d7714bd1c4c7ad759ec41b104be1 [file] [log] [blame]
Nigel Taoa2846e62011-10-04 11:09:03 +11001// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package color implements a basic color library.
6package color
7
8// Color can convert itself to alpha-premultiplied 16-bits per channel RGBA.
9// The conversion may be lossy.
10type Color interface {
11 // RGBA returns the alpha-premultiplied red, green, blue and alpha values
Nigel Tao2f34e602015-03-26 09:47:24 +110012 // for the color. Each value ranges within [0, 0xffff], but is represented
13 // by a uint32 so that multiplying by a blend factor up to 0xffff will not
Nigel Taoa2846e62011-10-04 11:09:03 +110014 // overflow.
Nigel Tao25bf7922015-03-19 09:46:43 +110015 //
16 // An alpha-premultiplied color component c has been scaled by alpha (a),
17 // so has valid values 0 <= c <= a.
Nigel Taoa2846e62011-10-04 11:09:03 +110018 RGBA() (r, g, b, a uint32)
19}
20
Nigel Tao25bf7922015-03-19 09:46:43 +110021// RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
22// bits for each of red, green, blue and alpha.
23//
24// An alpha-premultiplied color component C has been scaled by alpha (A), so
25// has valid values 0 <= C <= A.
Nigel Taoa2846e62011-10-04 11:09:03 +110026type RGBA struct {
27 R, G, B, A uint8
28}
29
30func (c RGBA) RGBA() (r, g, b, a uint32) {
31 r = uint32(c.R)
32 r |= r << 8
33 g = uint32(c.G)
34 g |= g << 8
35 b = uint32(c.B)
36 b |= b << 8
37 a = uint32(c.A)
38 a |= a << 8
39 return
40}
41
Nigel Tao25bf7922015-03-19 09:46:43 +110042// RGBA64 represents a 64-bit alpha-premultiplied color, having 16 bits for
43// each of red, green, blue and alpha.
44//
45// An alpha-premultiplied color component C has been scaled by alpha (A), so
46// has valid values 0 <= C <= A.
Nigel Taoa2846e62011-10-04 11:09:03 +110047type RGBA64 struct {
48 R, G, B, A uint16
49}
50
51func (c RGBA64) RGBA() (r, g, b, a uint32) {
52 return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
53}
54
55// NRGBA represents a non-alpha-premultiplied 32-bit color.
56type NRGBA struct {
57 R, G, B, A uint8
58}
59
60func (c NRGBA) RGBA() (r, g, b, a uint32) {
61 r = uint32(c.R)
62 r |= r << 8
63 r *= uint32(c.A)
64 r /= 0xff
65 g = uint32(c.G)
66 g |= g << 8
67 g *= uint32(c.A)
68 g /= 0xff
69 b = uint32(c.B)
70 b |= b << 8
71 b *= uint32(c.A)
72 b /= 0xff
73 a = uint32(c.A)
74 a |= a << 8
75 return
76}
77
78// NRGBA64 represents a non-alpha-premultiplied 64-bit color,
79// having 16 bits for each of red, green, blue and alpha.
80type NRGBA64 struct {
81 R, G, B, A uint16
82}
83
84func (c NRGBA64) RGBA() (r, g, b, a uint32) {
85 r = uint32(c.R)
86 r *= uint32(c.A)
87 r /= 0xffff
88 g = uint32(c.G)
89 g *= uint32(c.A)
90 g /= 0xffff
91 b = uint32(c.B)
92 b *= uint32(c.A)
93 b /= 0xffff
94 a = uint32(c.A)
95 return
96}
97
98// Alpha represents an 8-bit alpha color.
99type Alpha struct {
100 A uint8
101}
102
103func (c Alpha) RGBA() (r, g, b, a uint32) {
104 a = uint32(c.A)
105 a |= a << 8
106 return a, a, a, a
107}
108
109// Alpha16 represents a 16-bit alpha color.
110type Alpha16 struct {
111 A uint16
112}
113
114func (c Alpha16) RGBA() (r, g, b, a uint32) {
115 a = uint32(c.A)
116 return a, a, a, a
117}
118
119// Gray represents an 8-bit grayscale color.
120type Gray struct {
121 Y uint8
122}
123
124func (c Gray) RGBA() (r, g, b, a uint32) {
125 y := uint32(c.Y)
126 y |= y << 8
127 return y, y, y, 0xffff
128}
129
130// Gray16 represents a 16-bit grayscale color.
131type Gray16 struct {
132 Y uint16
133}
134
135func (c Gray16) RGBA() (r, g, b, a uint32) {
136 y := uint32(c.Y)
137 return y, y, y, 0xffff
138}
139
140// Model can convert any Color to one from its own color model. The conversion
141// may be lossy.
142type Model interface {
143 Convert(c Color) Color
144}
145
Russ Coxe4e4cdb2011-12-06 10:47:42 -0500146// ModelFunc returns a Model that invokes f to implement the conversion.
147func ModelFunc(f func(Color) Color) Model {
148 // Note: using *modelFunc as the implementation
149 // means that callers can still use comparisons
150 // like m == RGBAModel. This is not possible if
151 // we use the func value directly, because funcs
152 // are no longer comparable.
153 return &modelFunc{f}
154}
Nigel Taoa2846e62011-10-04 11:09:03 +1100155
Russ Coxe4e4cdb2011-12-06 10:47:42 -0500156type modelFunc struct {
157 f func(Color) Color
158}
159
160func (m *modelFunc) Convert(c Color) Color {
161 return m.f(c)
Nigel Taoa2846e62011-10-04 11:09:03 +1100162}
163
David Crawshawcdf76542012-01-16 16:02:31 +1100164// Models for the standard color types.
165var (
166 RGBAModel Model = ModelFunc(rgbaModel)
167 RGBA64Model Model = ModelFunc(rgba64Model)
168 NRGBAModel Model = ModelFunc(nrgbaModel)
169 NRGBA64Model Model = ModelFunc(nrgba64Model)
170 AlphaModel Model = ModelFunc(alphaModel)
171 Alpha16Model Model = ModelFunc(alpha16Model)
172 GrayModel Model = ModelFunc(grayModel)
173 Gray16Model Model = ModelFunc(gray16Model)
174)
175
176func rgbaModel(c Color) Color {
Nigel Taoa2846e62011-10-04 11:09:03 +1100177 if _, ok := c.(RGBA); ok {
178 return c
179 }
180 r, g, b, a := c.RGBA()
181 return RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
David Crawshawcdf76542012-01-16 16:02:31 +1100182}
Nigel Taoa2846e62011-10-04 11:09:03 +1100183
David Crawshawcdf76542012-01-16 16:02:31 +1100184func rgba64Model(c Color) Color {
Nigel Taoa2846e62011-10-04 11:09:03 +1100185 if _, ok := c.(RGBA64); ok {
186 return c
187 }
188 r, g, b, a := c.RGBA()
189 return RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
David Crawshawcdf76542012-01-16 16:02:31 +1100190}
Nigel Taoa2846e62011-10-04 11:09:03 +1100191
David Crawshawcdf76542012-01-16 16:02:31 +1100192func nrgbaModel(c Color) Color {
Nigel Taoa2846e62011-10-04 11:09:03 +1100193 if _, ok := c.(NRGBA); ok {
194 return c
195 }
196 r, g, b, a := c.RGBA()
197 if a == 0xffff {
198 return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
199 }
200 if a == 0 {
201 return NRGBA{0, 0, 0, 0}
202 }
203 // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
204 r = (r * 0xffff) / a
205 g = (g * 0xffff) / a
206 b = (b * 0xffff) / a
207 return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
David Crawshawcdf76542012-01-16 16:02:31 +1100208}
Nigel Taoa2846e62011-10-04 11:09:03 +1100209
David Crawshawcdf76542012-01-16 16:02:31 +1100210func nrgba64Model(c Color) Color {
Nigel Taoa2846e62011-10-04 11:09:03 +1100211 if _, ok := c.(NRGBA64); ok {
212 return c
213 }
214 r, g, b, a := c.RGBA()
215 if a == 0xffff {
216 return NRGBA64{uint16(r), uint16(g), uint16(b), 0xffff}
217 }
218 if a == 0 {
219 return NRGBA64{0, 0, 0, 0}
220 }
221 // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
222 r = (r * 0xffff) / a
223 g = (g * 0xffff) / a
224 b = (b * 0xffff) / a
225 return NRGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
David Crawshawcdf76542012-01-16 16:02:31 +1100226}
Nigel Taoa2846e62011-10-04 11:09:03 +1100227
David Crawshawcdf76542012-01-16 16:02:31 +1100228func alphaModel(c Color) Color {
Nigel Taoa2846e62011-10-04 11:09:03 +1100229 if _, ok := c.(Alpha); ok {
230 return c
231 }
232 _, _, _, a := c.RGBA()
233 return Alpha{uint8(a >> 8)}
David Crawshawcdf76542012-01-16 16:02:31 +1100234}
Nigel Taoa2846e62011-10-04 11:09:03 +1100235
David Crawshawcdf76542012-01-16 16:02:31 +1100236func alpha16Model(c Color) Color {
Nigel Taoa2846e62011-10-04 11:09:03 +1100237 if _, ok := c.(Alpha16); ok {
238 return c
239 }
240 _, _, _, a := c.RGBA()
241 return Alpha16{uint16(a)}
David Crawshawcdf76542012-01-16 16:02:31 +1100242}
Nigel Taoa2846e62011-10-04 11:09:03 +1100243
David Crawshawcdf76542012-01-16 16:02:31 +1100244func grayModel(c Color) Color {
Nigel Taoa2846e62011-10-04 11:09:03 +1100245 if _, ok := c.(Gray); ok {
246 return c
247 }
248 r, g, b, _ := c.RGBA()
249 y := (299*r + 587*g + 114*b + 500) / 1000
250 return Gray{uint8(y >> 8)}
David Crawshawcdf76542012-01-16 16:02:31 +1100251}
Nigel Taoa2846e62011-10-04 11:09:03 +1100252
David Crawshawcdf76542012-01-16 16:02:31 +1100253func gray16Model(c Color) Color {
Nigel Taoa2846e62011-10-04 11:09:03 +1100254 if _, ok := c.(Gray16); ok {
255 return c
256 }
257 r, g, b, _ := c.RGBA()
258 y := (299*r + 587*g + 114*b + 500) / 1000
259 return Gray16{uint16(y)}
David Crawshawcdf76542012-01-16 16:02:31 +1100260}
Nigel Taoa2846e62011-10-04 11:09:03 +1100261
262// Palette is a palette of colors.
263type Palette []Color
264
Nigel Taoa2846e62011-10-04 11:09:03 +1100265// Convert returns the palette color closest to c in Euclidean R,G,B space.
266func (p Palette) Convert(c Color) Color {
267 if len(p) == 0 {
268 return nil
269 }
270 return p[p.Index(c)]
271}
272
273// Index returns the index of the palette color closest to c in Euclidean
Nigel Tao28388c42015-04-16 11:08:05 +1000274// R,G,B,A space.
Nigel Taoa2846e62011-10-04 11:09:03 +1100275func (p Palette) Index(c Color) int {
Nigel Taoe430eb82013-07-11 08:47:29 +1000276 // A batch version of this computation is in image/draw/draw.go.
277
Nigel Tao28388c42015-04-16 11:08:05 +1000278 cr, cg, cb, ca := c.RGBA()
279 ret, bestSum := 0, uint32(1<<32-1)
Nigel Taoa2846e62011-10-04 11:09:03 +1100280 for i, v := range p {
Nigel Tao28388c42015-04-16 11:08:05 +1000281 vr, vg, vb, va := v.RGBA()
282 sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va)
283 if sum < bestSum {
284 if sum == 0 {
Nigel Taoa2846e62011-10-04 11:09:03 +1100285 return i
286 }
Nigel Tao28388c42015-04-16 11:08:05 +1000287 ret, bestSum = i, sum
Nigel Taoa2846e62011-10-04 11:09:03 +1100288 }
289 }
290 return ret
291}
292
Nigel Tao28388c42015-04-16 11:08:05 +1000293// sqDiff returns the squared-difference of x and y, shifted by 2 so that
294// adding four of those won't overflow a uint32.
295//
296// x and y are both assumed to be in the range [0, 0xffff].
297func sqDiff(x, y uint32) uint32 {
298 var d uint32
299 if x > y {
300 d = x - y
301 } else {
302 d = y - x
303 }
304 return (d * d) >> 2
305}
306
David Crawshawcdf76542012-01-16 16:02:31 +1100307// Standard colors.
Nigel Taoa2846e62011-10-04 11:09:03 +1100308var (
David Crawshawcdf76542012-01-16 16:02:31 +1100309 Black = Gray16{0}
310 White = Gray16{0xffff}
Nigel Taoa2846e62011-10-04 11:09:03 +1100311 Transparent = Alpha16{0}
David Crawshawcdf76542012-01-16 16:02:31 +1100312 Opaque = Alpha16{0xffff}
Nigel Taoa2846e62011-10-04 11:09:03 +1100313)