// 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.typeColorinterface {// 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.typeRGBAstruct { R, G, B, A uint8}func ( RGBA) () (, , , uint32) { = uint32(.R) |= << 8 = uint32(.G) |= << 8 = uint32(.B) |= << 8 = uint32(.A) |= << 8return}// 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.typeRGBA64struct { R, G, B, A uint16}func ( RGBA64) () (, , , uint32) {returnuint32(.R), uint32(.G), uint32(.B), uint32(.A)}// NRGBA represents a non-alpha-premultiplied 32-bit color.typeNRGBAstruct { R, G, B, A uint8}func ( NRGBA) () (, , , uint32) { = uint32(.R) |= << 8 *= uint32(.A) /= 0xff = uint32(.G) |= << 8 *= uint32(.A) /= 0xff = uint32(.B) |= << 8 *= uint32(.A) /= 0xff = uint32(.A) |= << 8return}// NRGBA64 represents a non-alpha-premultiplied 64-bit color,// having 16 bits for each of red, green, blue and alpha.typeNRGBA64struct { R, G, B, A uint16}func ( NRGBA64) () (, , , uint32) { = uint32(.R) *= uint32(.A) /= 0xffff = uint32(.G) *= uint32(.A) /= 0xffff = uint32(.B) *= uint32(.A) /= 0xffff = uint32(.A)return}// Alpha represents an 8-bit alpha color.typeAlphastruct { A uint8}func ( Alpha) () (, , , uint32) { = uint32(.A) |= << 8return , , , }// Alpha16 represents a 16-bit alpha color.typeAlpha16struct { A uint16}func ( Alpha16) () (, , , uint32) { = uint32(.A)return , , , }// Gray represents an 8-bit grayscale color.typeGraystruct { Y uint8}func ( Gray) () (, , , uint32) { := uint32(.Y) |= << 8return , , , 0xffff}// Gray16 represents a 16-bit grayscale color.typeGray16struct { Y uint16}func ( Gray16) () (, , , uint32) { := uint32(.Y)return , , , 0xffff}// Model can convert any [Color] to one from its own color model. The conversion// may be lossy.typeModelinterface {Convert(c Color) Color}// ModelFunc returns a [Model] that invokes f to implement the conversion.func ( 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{}}type modelFunc struct { f func(Color) Color}func ( *modelFunc) ( Color) Color {return .f()}// Models for the standard color types.var (RGBAModelModel = ModelFunc(rgbaModel)RGBA64ModelModel = ModelFunc(rgba64Model)NRGBAModelModel = ModelFunc(nrgbaModel)NRGBA64ModelModel = ModelFunc(nrgba64Model)AlphaModelModel = ModelFunc(alphaModel)Alpha16ModelModel = ModelFunc(alpha16Model)GrayModelModel = ModelFunc(grayModel)Gray16ModelModel = ModelFunc(gray16Model))func rgbaModel( Color) Color {if , := .(RGBA); {return } , , , := .RGBA()returnRGBA{uint8( >> 8), uint8( >> 8), uint8( >> 8), uint8( >> 8)}}func rgba64Model( Color) Color {if , := .(RGBA64); {return } , , , := .RGBA()returnRGBA64{uint16(), uint16(), uint16(), uint16()}}func nrgbaModel( Color) Color {if , := .(NRGBA); {return } , , , := .RGBA()if == 0xffff {returnNRGBA{uint8( >> 8), uint8( >> 8), uint8( >> 8), 0xff} }if == 0 {returnNRGBA{0, 0, 0, 0} }// Since Color.RGBA returns an alpha-premultiplied color, we should have r <= a && g <= a && b <= a. = ( * 0xffff) / = ( * 0xffff) / = ( * 0xffff) / returnNRGBA{uint8( >> 8), uint8( >> 8), uint8( >> 8), uint8( >> 8)}}func nrgba64Model( Color) Color {if , := .(NRGBA64); {return } , , , := .RGBA()if == 0xffff {returnNRGBA64{uint16(), uint16(), uint16(), 0xffff} }if == 0 {returnNRGBA64{0, 0, 0, 0} }// Since Color.RGBA returns an alpha-premultiplied color, we should have r <= a && g <= a && b <= a. = ( * 0xffff) / = ( * 0xffff) / = ( * 0xffff) / returnNRGBA64{uint16(), uint16(), uint16(), uint16()}}func alphaModel( Color) Color {if , := .(Alpha); {return } , , , := .RGBA()returnAlpha{uint8( >> 8)}}func alpha16Model( Color) Color {if , := .(Alpha16); {return } , , , := .RGBA()returnAlpha16{uint16()}}func grayModel( Color) Color {if , := .(Gray); {return } , , , := .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. := (19595* + 38470* + 7471* + 1<<15) >> 24returnGray{uint8()}}func gray16Model( Color) Color {if , := .(Gray16); {return } , , , := .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. := (19595* + 38470* + 7471* + 1<<15) >> 16returnGray16{uint16()}}// Palette is a palette of colors.typePalette []Color// Convert returns the palette color closest to c in Euclidean R,G,B space.func ( Palette) ( Color) Color {iflen() == 0 {returnnil }return [.Index()]}// Index returns the index of the palette color closest to c in Euclidean// R,G,B,A space.func ( Palette) ( Color) int {// A batch version of this computation is in image/draw/draw.go. , , , := .RGBA() , := 0, uint32(1<<32-1)for , := range { , , , := .RGBA() := sqDiff(, ) + sqDiff(, ) + sqDiff(, ) + sqDiff(, )if < {if == 0 {return } , = , } }return}// 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(, uint32) uint32 {// The canonical code of this function looks as follows: // // var d uint32 // if x > y { // d = x - y // } else { // d = y - x // } // return (d * d) >> 2 // // Language spec guarantees the following properties of unsigned integer // values operations with respect to overflow/wrap around: // // > For unsigned integer values, the operations +, -, *, and << are // > computed modulo 2n, where n is the bit width of the unsigned // > integer's type. Loosely speaking, these unsigned integer operations // > discard high bits upon overflow, and programs may rely on ``wrap // > around''. // // Considering these properties and the fact that this function is // called in the hot paths (x,y loops), it is reduced to the below code // which is slightly faster. See TestSqDiff for correctness check. := - return ( * ) >> 2}// Standard colors.var (Black = Gray16{0}White = Gray16{0xffff}Transparent = Alpha16{0}Opaque = Alpha16{0xffff})
The pages are generated with Goldsv0.6.9-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.