2016-12-23 13:25:47 -06:00
|
|
|
package pixel
|
|
|
|
|
|
|
|
import "image/color"
|
|
|
|
|
|
|
|
// NRGBA represents a non-alpha-premultiplied RGBA color with components within range [0, 1].
|
|
|
|
//
|
|
|
|
// The difference between color.NRGBA is that the value range is [0, 1] and the values are floats.
|
|
|
|
type NRGBA struct {
|
|
|
|
R, G, B, A float64
|
|
|
|
}
|
|
|
|
|
2016-12-30 10:43:26 -06:00
|
|
|
// Add adds color d to color c component-wise and returns the result (the components are not
|
|
|
|
// clamped).
|
2016-12-23 13:25:47 -06:00
|
|
|
func (c NRGBA) Add(d NRGBA) NRGBA {
|
|
|
|
return NRGBA{
|
|
|
|
R: c.R + d.R,
|
|
|
|
G: c.G + d.G,
|
|
|
|
B: c.B + d.B,
|
|
|
|
A: c.A + d.A,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-30 10:43:26 -06:00
|
|
|
// Sub subtracts color d from color c component-wise and returns the result (the components
|
|
|
|
// are not clamped).
|
2016-12-23 13:25:47 -06:00
|
|
|
func (c NRGBA) Sub(d NRGBA) NRGBA {
|
|
|
|
return NRGBA{
|
|
|
|
R: c.R - d.R,
|
|
|
|
G: c.G - d.G,
|
|
|
|
B: c.B - d.B,
|
|
|
|
A: c.A - d.A,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mul multiplies color c by color d component-wise (the components are not clamped).
|
|
|
|
func (c NRGBA) Mul(d NRGBA) NRGBA {
|
|
|
|
return NRGBA{
|
|
|
|
R: c.R * d.R,
|
|
|
|
G: c.G * d.G,
|
|
|
|
B: c.B * d.B,
|
|
|
|
A: c.A * d.A,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-30 10:43:26 -06:00
|
|
|
// Scaled multiplies each component of color c by scale and returns the result (the components
|
|
|
|
// are not clamped).
|
2016-12-23 13:25:47 -06:00
|
|
|
func (c NRGBA) Scaled(scale float64) NRGBA {
|
|
|
|
return NRGBA{
|
|
|
|
R: c.R * scale,
|
|
|
|
G: c.G * scale,
|
|
|
|
B: c.B * scale,
|
|
|
|
A: c.A * scale,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-25 11:55:17 -06:00
|
|
|
// RGBA returns alpha-premultiplied red, green, blue and alpha components of the NRGBA color.
|
2016-12-23 13:25:47 -06:00
|
|
|
func (c NRGBA) RGBA() (r, g, b, a uint32) {
|
|
|
|
c.R = clamp(c.R, 0, 1)
|
|
|
|
c.G = clamp(c.G, 0, 1)
|
|
|
|
c.B = clamp(c.B, 0, 1)
|
|
|
|
c.A = clamp(c.A, 0, 1)
|
|
|
|
r = uint32(0xffff * c.R * c.A)
|
|
|
|
g = uint32(0xffff * c.G * c.A)
|
|
|
|
b = uint32(0xffff * c.B * c.A)
|
|
|
|
a = uint32(0xffff * c.A)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-03-06 12:59:02 -06:00
|
|
|
func clamp(x, low, high float64) float64 {
|
|
|
|
if x < low {
|
|
|
|
return low
|
|
|
|
}
|
|
|
|
if x > high {
|
|
|
|
return high
|
|
|
|
}
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
2017-03-23 17:03:07 -05:00
|
|
|
// ToNRGBA converts a color to NRGBA format. Using this function is preferred to using NRGBAModel,
|
|
|
|
// for performance (using NRGBAModel introduced additional unnecessary allocations).
|
|
|
|
func ToNRGBA(c color.Color) NRGBA {
|
2017-01-04 12:02:12 -06:00
|
|
|
if c, ok := c.(NRGBA); ok {
|
|
|
|
return c
|
|
|
|
}
|
2017-03-19 14:09:05 -05:00
|
|
|
if c, ok := c.(color.NRGBA); ok {
|
|
|
|
return NRGBA{
|
|
|
|
R: float64(c.R) / 255,
|
|
|
|
G: float64(c.G) / 255,
|
|
|
|
B: float64(c.B) / 255,
|
|
|
|
A: float64(c.A) / 255,
|
|
|
|
}
|
|
|
|
}
|
2016-12-23 13:25:47 -06:00
|
|
|
r, g, b, a := c.RGBA()
|
|
|
|
if a == 0 {
|
|
|
|
return NRGBA{0, 0, 0, 0}
|
|
|
|
}
|
|
|
|
return NRGBA{
|
|
|
|
float64(r) / float64(a),
|
|
|
|
float64(g) / float64(a),
|
|
|
|
float64(b) / float64(a),
|
|
|
|
float64(a) / 0xffff,
|
|
|
|
}
|
2017-01-05 07:50:09 -06:00
|
|
|
}
|
2017-03-23 17:03:07 -05:00
|
|
|
|
|
|
|
// NRGBAModel converts colors to NRGBA format.
|
|
|
|
var NRGBAModel = color.ModelFunc(nrgbaModel)
|
|
|
|
|
|
|
|
func nrgbaModel(c color.Color) color.Color {
|
|
|
|
return ToNRGBA(c)
|
|
|
|
}
|