// 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 // All Colors can convert themselves, with a possible loss of precision, // to 64-bit alpha-premultiplied RGBA. Each channel value ranges within // [0, 0xFFFF]. 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 g = uint32(c.G) g |= g << 8 b = uint32(c.B) b |= b << 8 a = uint32(c.A) a |= a << 8 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) { return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A) } // 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 g = uint32(c.G) g |= g << 8 g *= uint32(c.A) g /= 0xff b = uint32(c.B) b |= b << 8 b *= uint32(c.A) b /= 0xff a = uint32(c.A) a |= a << 8 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 g = uint32(c.G) g *= uint32(c.A) g /= 0xffff b = uint32(c.B) b *= uint32(c.A) b /= 0xffff a = uint32(c.A) return } // An AlphaColor represents an 8-bit alpha. type AlphaColor struct { A uint8 } func (c AlphaColor) RGBA() (r, g, b, a uint32) { a = uint32(c.A) a |= a << 8 return a, a, a, a } // An Alpha16Color represents a 16-bit alpha. type Alpha16Color struct { A uint16 } func (c Alpha16Color) RGBA() (r, g, b, a uint32) { a = uint32(c.A) return a, a, a, a } // A GrayColor represents an 8-bit grayscale color. type GrayColor struct { Y uint8 } func (c GrayColor) RGBA() (r, g, b, a uint32) { y := uint32(c.Y) y |= y << 8 return y, y, y, 0xffff } // A Gray16Color represents a 16-bit grayscale color. type Gray16Color struct { Y uint16 } func (c Gray16Color) RGBA() (r, g, b, a uint32) { y := uint32(c.Y) return y, y, y, 0xffff } // 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 { return c } r, g, b, a := c.RGBA() return RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} } func toRGBA64Color(c Color) Color { if _, ok := c.(RGBA64Color); ok { return c } r, g, b, a := c.RGBA() return RGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)} } func toNRGBAColor(c Color) Color { if _, ok := c.(NRGBAColor); ok { return c } r, g, b, a := c.RGBA() if a == 0xffff { return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff} } if a == 0 { return NRGBAColor{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 NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} } func toNRGBA64Color(c Color) Color { if _, ok := c.(NRGBA64Color); ok { return c } r, g, b, a := c.RGBA() 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)} } func toAlphaColor(c Color) Color { if _, ok := c.(AlphaColor); ok { return c } _, _, _, a := c.RGBA() return AlphaColor{uint8(a >> 8)} } func toAlpha16Color(c Color) Color { if _, ok := c.(Alpha16Color); ok { return c } _, _, _, a := c.RGBA() return Alpha16Color{uint16(a)} } func toGrayColor(c Color) Color { if _, ok := c.(GrayColor); ok { return c } r, g, b, _ := c.RGBA() y := (299*r + 587*g + 114*b + 500) / 1000 return GrayColor{uint8(y >> 8)} } func toGray16Color(c Color) Color { if _, ok := c.(Gray16Color); ok { return c } r, g, b, _ := c.RGBA() y := (299*r + 587*g + 114*b + 500) / 1000 return Gray16Color{uint16(y)} } // 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) // The ColorModel associated with AlphaColor. var AlphaColorModel ColorModel = ColorModelFunc(toAlphaColor) // The ColorModel associated with Alpha16Color. var Alpha16ColorModel ColorModel = ColorModelFunc(toAlpha16Color) // The ColorModel associated with GrayColor. var GrayColorModel ColorModel = ColorModelFunc(toGrayColor) // The ColorModel associated with Gray16Color. var Gray16ColorModel ColorModel = ColorModelFunc(toGray16Color)