...
Run Format

Source file src/image/color/color.go

  // Copyright 2011 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 color implements a basic color library.
  package color
  
  // Color can convert itself to alpha-premultiplied 16-bits per channel RGBA.
  // The conversion may be lossy.
  type Color interface {
  	// RGBA returns the alpha-premultiplied red, green, blue and alpha values
  	// for the color. Each value ranges within [0, 0xffff], but is represented
  	// by a uint32 so that multiplying by a blend factor up to 0xffff will not
  	// overflow.
  	//
  	// An alpha-premultiplied color component c has been scaled by alpha (a),
  	// so has valid values 0 <= c <= a.
  	RGBA() (r, g, b, a uint32)
  }
  
  // RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
  // bits for each of red, green, blue and alpha.
  //
  // An alpha-premultiplied color component C has been scaled by alpha (A), so
  // has valid values 0 <= C <= A.
  type RGBA struct {
  	R, G, B, A uint8
  }
  
  func (c RGBA) 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
  }
  
  // RGBA64 represents a 64-bit alpha-premultiplied color, having 16 bits for
  // each of red, green, blue and alpha.
  //
  // An alpha-premultiplied color component C has been scaled by alpha (A), so
  // has valid values 0 <= C <= A.
  type RGBA64 struct {
  	R, G, B, A uint16
  }
  
  func (c RGBA64) RGBA() (r, g, b, a uint32) {
  	return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
  }
  
  // NRGBA represents a non-alpha-premultiplied 32-bit color.
  type NRGBA struct {
  	R, G, B, A uint8
  }
  
  func (c NRGBA) 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
  }
  
  // NRGBA64 represents a non-alpha-premultiplied 64-bit color,
  // having 16 bits for each of red, green, blue and alpha.
  type NRGBA64 struct {
  	R, G, B, A uint16
  }
  
  func (c NRGBA64) 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
  }
  
  // Alpha represents an 8-bit alpha color.
  type Alpha struct {
  	A uint8
  }
  
  func (c Alpha) RGBA() (r, g, b, a uint32) {
  	a = uint32(c.A)
  	a |= a << 8
  	return a, a, a, a
  }
  
  // Alpha16 represents a 16-bit alpha color.
  type Alpha16 struct {
  	A uint16
  }
  
  func (c Alpha16) RGBA() (r, g, b, a uint32) {
  	a = uint32(c.A)
  	return a, a, a, a
  }
  
  // Gray represents an 8-bit grayscale color.
  type Gray struct {
  	Y uint8
  }
  
  func (c Gray) RGBA() (r, g, b, a uint32) {
  	y := uint32(c.Y)
  	y |= y << 8
  	return y, y, y, 0xffff
  }
  
  // Gray16 represents a 16-bit grayscale color.
  type Gray16 struct {
  	Y uint16
  }
  
  func (c Gray16) RGBA() (r, g, b, a uint32) {
  	y := uint32(c.Y)
  	return y, y, y, 0xffff
  }
  
  // Model can convert any Color to one from its own color model. The conversion
  // may be lossy.
  type Model interface {
  	Convert(c Color) Color
  }
  
  // ModelFunc returns a Model that invokes f to implement the conversion.
  func ModelFunc(f func(Color) Color) Model {
  	// Note: using *modelFunc as the implementation
  	// means that callers can still use comparisons
  	// like m == RGBAModel. This is not possible if
  	// we use the func value directly, because funcs
  	// are no longer comparable.
  	return &modelFunc{f}
  }
  
  type modelFunc struct {
  	f func(Color) Color
  }
  
  func (m *modelFunc) Convert(c Color) Color {
  	return m.f(c)
  }
  
  // Models for the standard color types.
  var (
  	RGBAModel    Model = ModelFunc(rgbaModel)
  	RGBA64Model  Model = ModelFunc(rgba64Model)
  	NRGBAModel   Model = ModelFunc(nrgbaModel)
  	NRGBA64Model Model = ModelFunc(nrgba64Model)
  	AlphaModel   Model = ModelFunc(alphaModel)
  	Alpha16Model Model = ModelFunc(alpha16Model)
  	GrayModel    Model = ModelFunc(grayModel)
  	Gray16Model  Model = ModelFunc(gray16Model)
  )
  
  func rgbaModel(c Color) Color {
  	if _, ok := c.(RGBA); ok {
  		return c
  	}
  	r, g, b, a := c.RGBA()
  	return RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
  }
  
  func rgba64Model(c Color) Color {
  	if _, ok := c.(RGBA64); ok {
  		return c
  	}
  	r, g, b, a := c.RGBA()
  	return RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
  }
  
  func nrgbaModel(c Color) Color {
  	if _, ok := c.(NRGBA); ok {
  		return c
  	}
  	r, g, b, a := c.RGBA()
  	if a == 0xffff {
  		return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
  	}
  	if a == 0 {
  		return NRGBA{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 NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
  }
  
  func nrgba64Model(c Color) Color {
  	if _, ok := c.(NRGBA64); ok {
  		return c
  	}
  	r, g, b, a := c.RGBA()
  	if a == 0xffff {
  		return NRGBA64{uint16(r), uint16(g), uint16(b), 0xffff}
  	}
  	if a == 0 {
  		return NRGBA64{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 NRGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
  }
  
  func alphaModel(c Color) Color {
  	if _, ok := c.(Alpha); ok {
  		return c
  	}
  	_, _, _, a := c.RGBA()
  	return Alpha{uint8(a >> 8)}
  }
  
  func alpha16Model(c Color) Color {
  	if _, ok := c.(Alpha16); ok {
  		return c
  	}
  	_, _, _, a := c.RGBA()
  	return Alpha16{uint16(a)}
  }
  
  func grayModel(c Color) Color {
  	if _, ok := c.(Gray); ok {
  		return c
  	}
  	r, g, b, _ := c.RGBA()
  
  	// These coefficients (the fractions 0.299, 0.587 and 0.114) are the same
  	// as those given by the JFIF specification and used by func RGBToYCbCr in
  	// ycbcr.go.
  	//
  	// Note that 19595 + 38470 + 7471 equals 65536.
  	//
  	// The 24 is 16 + 8. The 16 is the same as used in RGBToYCbCr. The 8 is
  	// because the return value is 8 bit color, not 16 bit color.
  	y := (19595*r + 38470*g + 7471*b + 1<<15) >> 24
  
  	return Gray{uint8(y)}
  }
  
  func gray16Model(c Color) Color {
  	if _, ok := c.(Gray16); ok {
  		return c
  	}
  	r, g, b, _ := c.RGBA()
  
  	// These coefficients (the fractions 0.299, 0.587 and 0.114) are the same
  	// as those given by the JFIF specification and used by func RGBToYCbCr in
  	// ycbcr.go.
  	//
  	// Note that 19595 + 38470 + 7471 equals 65536.
  	y := (19595*r + 38470*g + 7471*b + 1<<15) >> 16
  
  	return Gray16{uint16(y)}
  }
  
  // Palette is a palette of colors.
  type Palette []Color
  
  // Convert returns the palette color closest to c in Euclidean R,G,B space.
  func (p Palette) Convert(c Color) Color {
  	if len(p) == 0 {
  		return nil
  	}
  	return p[p.Index(c)]
  }
  
  // Index returns the index of the palette color closest to c in Euclidean
  // R,G,B,A space.
  func (p Palette) Index(c Color) int {
  	// A batch version of this computation is in image/draw/draw.go.
  
  	cr, cg, cb, ca := c.RGBA()
  	ret, bestSum := 0, uint32(1<<32-1)
  	for i, v := range p {
  		vr, vg, vb, va := v.RGBA()
  		sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va)
  		if sum < bestSum {
  			if sum == 0 {
  				return i
  			}
  			ret, bestSum = i, sum
  		}
  	}
  	return ret
  }
  
  // sqDiff returns the squared-difference of x and y, shifted by 2 so that
  // adding four of those won't overflow a uint32.
  //
  // x and y are both assumed to be in the range [0, 0xffff].
  func sqDiff(x, y uint32) uint32 {
  	var d uint32
  	if x > y {
  		d = x - y
  	} else {
  		d = y - x
  	}
  	return (d * d) >> 2
  }
  
  // Standard colors.
  var (
  	Black       = Gray16{0}
  	White       = Gray16{0xffff}
  	Transparent = Alpha16{0}
  	Opaque      = Alpha16{0xffff}
  )
  

View as plain text