github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/image/color/color.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package color implements a basic color library.
     6  package color
     7  
     8  // Color can convert itself to alpha-premultiplied 16-bits per channel RGBA.
     9  // The conversion may be lossy.
    10  type Color interface {
    11  	// RGBA returns the alpha-premultiplied red, green, blue and alpha values
    12  	// for the color. Each value ranges within [0, 0xFFFF], but is represented
    13  	// by a uint32 so that multiplying by a blend factor up to 0xFFFF will not
    14  	// overflow.
    15  	RGBA() (r, g, b, a uint32)
    16  }
    17  
    18  // RGBA represents a traditional 32-bit alpha-premultiplied color,
    19  // having 8 bits for each of red, green, blue and alpha.
    20  type RGBA struct {
    21  	R, G, B, A uint8
    22  }
    23  
    24  func (c RGBA) RGBA() (r, g, b, a uint32) {
    25  	r = uint32(c.R)
    26  	r |= r << 8
    27  	g = uint32(c.G)
    28  	g |= g << 8
    29  	b = uint32(c.B)
    30  	b |= b << 8
    31  	a = uint32(c.A)
    32  	a |= a << 8
    33  	return
    34  }
    35  
    36  // RGBA64 represents a 64-bit alpha-premultiplied color,
    37  // having 16 bits for each of red, green, blue and alpha.
    38  type RGBA64 struct {
    39  	R, G, B, A uint16
    40  }
    41  
    42  func (c RGBA64) RGBA() (r, g, b, a uint32) {
    43  	return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
    44  }
    45  
    46  // NRGBA represents a non-alpha-premultiplied 32-bit color.
    47  type NRGBA struct {
    48  	R, G, B, A uint8
    49  }
    50  
    51  func (c NRGBA) RGBA() (r, g, b, a uint32) {
    52  	r = uint32(c.R)
    53  	r |= r << 8
    54  	r *= uint32(c.A)
    55  	r /= 0xff
    56  	g = uint32(c.G)
    57  	g |= g << 8
    58  	g *= uint32(c.A)
    59  	g /= 0xff
    60  	b = uint32(c.B)
    61  	b |= b << 8
    62  	b *= uint32(c.A)
    63  	b /= 0xff
    64  	a = uint32(c.A)
    65  	a |= a << 8
    66  	return
    67  }
    68  
    69  // NRGBA64 represents a non-alpha-premultiplied 64-bit color,
    70  // having 16 bits for each of red, green, blue and alpha.
    71  type NRGBA64 struct {
    72  	R, G, B, A uint16
    73  }
    74  
    75  func (c NRGBA64) RGBA() (r, g, b, a uint32) {
    76  	r = uint32(c.R)
    77  	r *= uint32(c.A)
    78  	r /= 0xffff
    79  	g = uint32(c.G)
    80  	g *= uint32(c.A)
    81  	g /= 0xffff
    82  	b = uint32(c.B)
    83  	b *= uint32(c.A)
    84  	b /= 0xffff
    85  	a = uint32(c.A)
    86  	return
    87  }
    88  
    89  // Alpha represents an 8-bit alpha color.
    90  type Alpha struct {
    91  	A uint8
    92  }
    93  
    94  func (c Alpha) RGBA() (r, g, b, a uint32) {
    95  	a = uint32(c.A)
    96  	a |= a << 8
    97  	return a, a, a, a
    98  }
    99  
   100  // Alpha16 represents a 16-bit alpha color.
   101  type Alpha16 struct {
   102  	A uint16
   103  }
   104  
   105  func (c Alpha16) RGBA() (r, g, b, a uint32) {
   106  	a = uint32(c.A)
   107  	return a, a, a, a
   108  }
   109  
   110  // Gray represents an 8-bit grayscale color.
   111  type Gray struct {
   112  	Y uint8
   113  }
   114  
   115  func (c Gray) RGBA() (r, g, b, a uint32) {
   116  	y := uint32(c.Y)
   117  	y |= y << 8
   118  	return y, y, y, 0xffff
   119  }
   120  
   121  // Gray16 represents a 16-bit grayscale color.
   122  type Gray16 struct {
   123  	Y uint16
   124  }
   125  
   126  func (c Gray16) RGBA() (r, g, b, a uint32) {
   127  	y := uint32(c.Y)
   128  	return y, y, y, 0xffff
   129  }
   130  
   131  // Model can convert any Color to one from its own color model. The conversion
   132  // may be lossy.
   133  type Model interface {
   134  	Convert(c Color) Color
   135  }
   136  
   137  // ModelFunc returns a Model that invokes f to implement the conversion.
   138  func ModelFunc(f func(Color) Color) Model {
   139  	// Note: using *modelFunc as the implementation
   140  	// means that callers can still use comparisons
   141  	// like m == RGBAModel.  This is not possible if
   142  	// we use the func value directly, because funcs
   143  	// are no longer comparable.
   144  	return &modelFunc{f}
   145  }
   146  
   147  type modelFunc struct {
   148  	f func(Color) Color
   149  }
   150  
   151  func (m *modelFunc) Convert(c Color) Color {
   152  	return m.f(c)
   153  }
   154  
   155  // Models for the standard color types.
   156  var (
   157  	RGBAModel    Model = ModelFunc(rgbaModel)
   158  	RGBA64Model  Model = ModelFunc(rgba64Model)
   159  	NRGBAModel   Model = ModelFunc(nrgbaModel)
   160  	NRGBA64Model Model = ModelFunc(nrgba64Model)
   161  	AlphaModel   Model = ModelFunc(alphaModel)
   162  	Alpha16Model Model = ModelFunc(alpha16Model)
   163  	GrayModel    Model = ModelFunc(grayModel)
   164  	Gray16Model  Model = ModelFunc(gray16Model)
   165  )
   166  
   167  func rgbaModel(c Color) Color {
   168  	if _, ok := c.(RGBA); ok {
   169  		return c
   170  	}
   171  	r, g, b, a := c.RGBA()
   172  	return RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
   173  }
   174  
   175  func rgba64Model(c Color) Color {
   176  	if _, ok := c.(RGBA64); ok {
   177  		return c
   178  	}
   179  	r, g, b, a := c.RGBA()
   180  	return RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
   181  }
   182  
   183  func nrgbaModel(c Color) Color {
   184  	if _, ok := c.(NRGBA); ok {
   185  		return c
   186  	}
   187  	r, g, b, a := c.RGBA()
   188  	if a == 0xffff {
   189  		return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
   190  	}
   191  	if a == 0 {
   192  		return NRGBA{0, 0, 0, 0}
   193  	}
   194  	// Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
   195  	r = (r * 0xffff) / a
   196  	g = (g * 0xffff) / a
   197  	b = (b * 0xffff) / a
   198  	return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
   199  }
   200  
   201  func nrgba64Model(c Color) Color {
   202  	if _, ok := c.(NRGBA64); ok {
   203  		return c
   204  	}
   205  	r, g, b, a := c.RGBA()
   206  	if a == 0xffff {
   207  		return NRGBA64{uint16(r), uint16(g), uint16(b), 0xffff}
   208  	}
   209  	if a == 0 {
   210  		return NRGBA64{0, 0, 0, 0}
   211  	}
   212  	// Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
   213  	r = (r * 0xffff) / a
   214  	g = (g * 0xffff) / a
   215  	b = (b * 0xffff) / a
   216  	return NRGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
   217  }
   218  
   219  func alphaModel(c Color) Color {
   220  	if _, ok := c.(Alpha); ok {
   221  		return c
   222  	}
   223  	_, _, _, a := c.RGBA()
   224  	return Alpha{uint8(a >> 8)}
   225  }
   226  
   227  func alpha16Model(c Color) Color {
   228  	if _, ok := c.(Alpha16); ok {
   229  		return c
   230  	}
   231  	_, _, _, a := c.RGBA()
   232  	return Alpha16{uint16(a)}
   233  }
   234  
   235  func grayModel(c Color) Color {
   236  	if _, ok := c.(Gray); ok {
   237  		return c
   238  	}
   239  	r, g, b, _ := c.RGBA()
   240  	y := (299*r + 587*g + 114*b + 500) / 1000
   241  	return Gray{uint8(y >> 8)}
   242  }
   243  
   244  func gray16Model(c Color) Color {
   245  	if _, ok := c.(Gray16); ok {
   246  		return c
   247  	}
   248  	r, g, b, _ := c.RGBA()
   249  	y := (299*r + 587*g + 114*b + 500) / 1000
   250  	return Gray16{uint16(y)}
   251  }
   252  
   253  // Palette is a palette of colors.
   254  type Palette []Color
   255  
   256  // Convert returns the palette color closest to c in Euclidean R,G,B space.
   257  func (p Palette) Convert(c Color) Color {
   258  	if len(p) == 0 {
   259  		return nil
   260  	}
   261  	return p[p.Index(c)]
   262  }
   263  
   264  // Index returns the index of the palette color closest to c in Euclidean
   265  // R,G,B space.
   266  func (p Palette) Index(c Color) int {
   267  	// A batch version of this computation is in image/draw/draw.go.
   268  
   269  	cr, cg, cb, _ := c.RGBA()
   270  	ret, bestSSD := 0, uint32(1<<32-1)
   271  	for i, v := range p {
   272  		vr, vg, vb, _ := v.RGBA()
   273  		// We shift by 1 bit to avoid potential uint32 overflow in
   274  		// sum-squared-difference.
   275  		delta := (int32(cr) - int32(vr)) >> 1
   276  		ssd := uint32(delta * delta)
   277  		delta = (int32(cg) - int32(vg)) >> 1
   278  		ssd += uint32(delta * delta)
   279  		delta = (int32(cb) - int32(vb)) >> 1
   280  		ssd += uint32(delta * delta)
   281  		if ssd < bestSSD {
   282  			if ssd == 0 {
   283  				return i
   284  			}
   285  			ret, bestSSD = i, ssd
   286  		}
   287  	}
   288  	return ret
   289  }
   290  
   291  // Standard colors.
   292  var (
   293  	Black       = Gray16{0}
   294  	White       = Gray16{0xffff}
   295  	Transparent = Alpha16{0}
   296  	Opaque      = Alpha16{0xffff}
   297  )