// 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)