Go Home Page
The Go Programming Language

Source file src/pkg/image/color.go

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

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