// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package image
// TODO(nigeltao): Think about how floating-point color models work.
// All Colors can convert themselves, with a possible loss of precision, to 128-bit alpha-premultiplied RGBA.
type Color interface {
RGBA() (r, g, b, a uint32);
}
// An RGBAColor represents a traditional 32-bit alpha-premultiplied color, having 8 bits for each of red, green, blue and alpha.
type RGBAColor struct {
R, G, B, A uint8;
}
func (c RGBAColor) RGBA() (r, g, b, a uint32) {
r = uint32(c.R);
r |= r << 8;
r |= r << 16;
g = uint32(c.G);
g |= g << 8;
g |= g << 16;
b = uint32(c.B);
b |= b << 8;
b |= b << 16;
a = uint32(c.A);
a |= a << 8;
a |= a << 16;
return;
}
// An RGBA64Color represents a 64-bit alpha-premultiplied color, having 16 bits for each of red, green, blue and alpha.
type RGBA64Color struct {
R, G, B, A uint16;
}
func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
r = uint32(c.R);
r |= r << 16;
g = uint32(c.G);
g |= g << 16;
b = uint32(c.B);
b |= b << 16;
a = uint32(c.A);
a |= a << 16;
return;
}
// An NRGBAColor represents a non-alpha-premultiplied 32-bit color.
type NRGBAColor struct {
R, G, B, A uint8;
}
func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
r = uint32(c.R);
r |= r << 8;
r *= uint32(c.A);
r /= 0xff;
r |= r << 16;
g = uint32(c.G);
g |= g << 8;
g *= uint32(c.A);
g /= 0xff;
g |= g << 16;
b = uint32(c.B);
b |= b << 8;
b *= uint32(c.A);
b /= 0xff;
b |= b << 16;
a = uint32(c.A);
a |= a << 8;
a |= a << 16;
return;
}
// An NRGBA64Color represents a non-alpha-premultiplied 64-bit color, having 16 bits for each of red, green, blue and alpha.
type NRGBA64Color struct {
R, G, B, A uint16;
}
func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
r = uint32(c.R);
r *= uint32(c.A);
r /= 0xffff;
r |= r << 16;
g = uint32(c.G);
g *= uint32(c.A);
g /= 0xffff;
g |= g << 16;
b = uint32(c.B);
b *= uint32(c.A);
b /= 0xffff;
b |= b << 16;
a = uint32(c.A);
a |= a << 8;
a |= a << 16;
return;
}
// A ColorModel can convert foreign Colors, with a possible loss of precision, to a Color
// from its own color model.
type ColorModel interface {
Convert(c Color) Color;
}
// The ColorModelFunc type is an adapter to allow the use of an ordinary
// color conversion function as a ColorModel. If f is such a function,
// ColorModelFunc(f) is a ColorModel object that invokes f to implement
// the conversion.
type ColorModelFunc func(Color) Color
func (f ColorModelFunc) Convert(c Color) Color {
return f(c)
}
func toRGBAColor(c Color) Color {
if _, ok := c.(RGBAColor); ok { // no-op conversion
return c
}
r, g, b, a := c.RGBA();
return RGBAColor{uint8(r >> 24), uint8(g >> 24), uint8(b >> 24), uint8(a >> 24)};
}
func toRGBA64Color(c Color) Color {
if _, ok := c.(RGBA64Color); ok { // no-op conversion
return c
}
r, g, b, a := c.RGBA();
return RGBA64Color{uint16(r >> 16), uint16(g >> 16), uint16(b >> 16), uint16(a >> 16)};
}
func toNRGBAColor(c Color) Color {
if _, ok := c.(NRGBAColor); ok { // no-op conversion
return c
}
r, g, b, a := c.RGBA();
a >>= 16;
if a == 0xffff {
return NRGBAColor{uint8(r >> 24), uint8(g >> 24), uint8(b >> 24), 0xff}
}
if a == 0 {
return NRGBAColor{0, 0, 0, 0}
}
r >>= 16;
g >>= 16;
b >>= 16;
// Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
r = (r * 0xffff) / a;
g = (g * 0xffff) / a;
b = (b * 0xffff) / a;
return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)};
}
func toNRGBA64Color(c Color) Color {
if _, ok := c.(NRGBA64Color); ok { // no-op conversion
return c
}
r, g, b, a := c.RGBA();
a >>= 16;
r >>= 16;
g >>= 16;
b >>= 16;
if a == 0xffff {
return NRGBA64Color{uint16(r), uint16(g), uint16(b), 0xffff}
}
if a == 0 {
return NRGBA64Color{0, 0, 0, 0}
}
// Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
r = (r * 0xffff) / a;
g = (g * 0xffff) / a;
b = (b * 0xffff) / a;
return NRGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)};
}
// The ColorModel associated with RGBAColor.
var RGBAColorModel ColorModel = ColorModelFunc(toRGBAColor)
// The ColorModel associated with RGBA64Color.
var RGBA64ColorModel ColorModel = ColorModelFunc(toRGBA64Color)
// The ColorModel associated with NRGBAColor.
var NRGBAColorModel ColorModel = ColorModelFunc(toNRGBAColor)
// The ColorModel associated with NRGBA64Color.
var NRGBA64ColorModel ColorModel = ColorModelFunc(toNRGBA64Color)
|