color

package module
v0.0.0-...-730babc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 2, 2024 License: MIT Imports: 8 Imported by: 3

Documentation

Overview

Package color provides types and functions for working with colors.

Color

The core type is Color, a color space-aware type for representing colors in any 3-axis coordinate system. For example, one color may be represented in a cartesian sRGB color space, while another is represented in the cylindrical Oklch. Colors can be instantiated directly or created with the Make helper. Additionally, the CSS 'color()' syntax is supported and can be parsed by Parse. The package provides numerous color spaces, as variables of type Space.

Colors can be freely converted between any two color spaces, with optional gamut mapping. To convert a Color without gamut mapping, use Color.Convert. If the destination color space is narrower than the source space (for example, when converting from Display P3 to sRGB), the new Color might not be in gamut and have values outside the expected range. Package color does not apply gamut mapping automatically for two reasons:

  1. No gamut mapping approach is perfect and we leave the choice of which algorithm to use up to the user.

  2. Automatic gamut mapping would prevent colors from being roundtrippable. Without gamut mapping, it is possible to go from a wider to a narrower and back to a wider color space without losing information (except for the introduction of rounding errors).

A decent gamut mapping operation with a relative colorimetric intent is implemented by GamutMapCSS. This is the same algorithm that is used by browsers that implement the CSS Color Module Level 4 standard.

Whether a color is in gamut for its color space can be checked with Color.InGamut. There is also Color.InGamutOf that checks if a color, when converted to a target color space, will be in gamut.

The following example shows the creation of a very saturated pink (more saturated than can be displayed by non-wide-gamut displays) using Oklch and its conversion to sRGB with and without gamut mapping.

veryPink := Make(Oklch, 0.65, 0.29, 0, 1)
pinkSRGB := GamutMapCSS(&veryPink, SRGB)
veryPinkSRGB := veryPink.Convert(SRGB)

fmt.Println(veryPink, veryPink.InGamut())
fmt.Println(pinkSRGB, pinkSRGB.InGamut())
fmt.Println(veryPinkSRGB, veryPinkSRGB.InGamut())

Output:

color(--oklch 0.650000 0.290000 0.000000) true
color(srgb 1.000000 0.000000 0.533824) true
color(srgb 1.040595 -0.191616 0.533106) false

This is everything that is needed to create and use colors. The following sections describe more advanced but optional functionality.

Color spaces

Without an associated color space, a triple like (0.6, 0.2, 0) conveys no meaning. It might represent a brown color in sRGB (when representing values as floating point values in the range [0, 1]), or a soft pink in Oklch.

Package color supports numerous color spaces and allows users to define their own. They are represented by the Space type. Color spaces include meta data such as an ID (for use with Parse) and name as well as a white point. However, their main functionality is provided by having a "base" color space to and from which a color space can be converted. The base space might be closely related, such as sRGB being based on linear sRGB (as the former is just the latter with a transfer function applied). It might also be a more fundamental color space, often XYZ with the appropriate white point. Together, all color spaces form a tree, with XYZ D65 as the root. This tree allows converting between any two color spaces by finding a common ancestor (the conversion space) and applying a series of conversions from the source space to the conversion space and from the conversion space to the target space.

Chromatic adaptation

Different color spaces may have different white points, requiring chromatic adaptation when converting between them. This is automatically handled during color space conversion. Every color space's chain of base spaces will eventually lead to an XYZ color space with the appropriate white point. When converting between two XYZ color spaces with different white points, we use the Bradford method to adapt between them.

It is also possible to manually apply chromatic adaptation using the CAT type. This package provides the Bradford and CAT16 transformations, but any transformation that is based on using a 3x3 matrix to map to a cone response and another 3x3 matrix to map from a cone response can be implemented using CAT.

Furthermore, we provide definitions for numerous white points, expressed as xy chromaticities using the Chromaticity type. Additionally, CIE daylight illuminants can be created with MakeCIEDaylightIlluminant.

New XYZ spaces with custom white points can be created with NewXYZSpace.

Other functionality

The perceptual difference between two colors can be computed by functions whose names start with "Delta", such as DeltaEOK2. Different functions have different tradeoffs.

The contrast of two colors can be computed by functions whose names start with "Contrast", such as ContrastWeber. Different functions have different tradeoffs.

Step creates color gradients by linearly interpolating between two colors in a color space of your choice.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	Bradford = &CAT{
		ToCone: [3][3]float64{
			{+0.8951, +0.2664, -0.1614},
			{-0.7502, +1.7135, +0.0367},
			{+0.0389, -0.0685, +1.0296},
		},
		FromCone: [3][3]float64{
			{0.9869929054667121, -0.14705425642099013, 0.15996265166373122},
			{0.4323052697233945, 0.5183602715367774, 0.049291228212855594},
			{-0.00852866457517732, 0.04004282165408486, 0.96848669578755},
		},
	}

	CAT16 = &CAT{
		ToCone: [3][3]float64{
			{0.401288, 0.650173, -0.051461},
			{-0.250268, 1.204414, 0.045854},
			{-0.002079, 0.048952, 0.953127},
		},
		FromCone: [3][3]float64{
			{1.862067855087233, -1.0112546305316845, 0.14918677544445172},
			{0.3875265432361372, 0.6214474419314753, -0.008973985167612521},
			{-0.01584149884933386, -0.03412293802851557, 1.0499644368778496},
		},
	}
)
View Source
var (
	// Standard illuminants for the CIE 1931 standard observer, from tables T.3,
	// T.8, T.8.2, and T.9 in CIE 15:2004.
	WhitesCIE2004TwoDegA      = &Chromaticity{0.44758, 040745}
	WhitesCIE2004TwoDegC      = &Chromaticity{0.31006, 0.31616}
	WhitesCIE2004TwoDegD50    = &Chromaticity{0.34567, 0.35851}
	WhitesCIE2004TwoDegD55    = &Chromaticity{0.33243, 0.34744}
	WhitesCIE2004TwoDegD65    = &Chromaticity{0.31272, 0.32903}
	WhitesCIE2004TwoDegD75    = &Chromaticity{0.29903, 0.31488}
	WhitesCIE2004TwoDegFL1    = &Chromaticity{0.3131, 0.3371}
	WhitesCIE2004TwoDegFL2    = &Chromaticity{0.3721, 0.3751}
	WhitesCIE2004TwoDegFL3    = &Chromaticity{0.4091, 0.3941}
	WhitesCIE2004TwoDegFL3_1  = &Chromaticity{0.4407, 0.4033}
	WhitesCIE2004TwoDegFL3_2  = &Chromaticity{0.3808, 0.3734}
	WhitesCIE2004TwoDegFL3_3  = &Chromaticity{0.3153, 0.3439}
	WhitesCIE2004TwoDegFL3_4  = &Chromaticity{0.4429, 0.4043}
	WhitesCIE2004TwoDegFL3_5  = &Chromaticity{0.3749, 0.3672}
	WhitesCIE2004TwoDegFL3_6  = &Chromaticity{0.3488, 0.36}
	WhitesCIE2004TwoDegFL3_7  = &Chromaticity{0.4384, 0.4045}
	WhitesCIE2004TwoDegFL3_8  = &Chromaticity{0.382, 0.3832}
	WhitesCIE2004TwoDegFL3_9  = &Chromaticity{0.3499, 0.3591}
	WhitesCIE2004TwoDegFL3_10 = &Chromaticity{0.3455, 0.356}
	WhitesCIE2004TwoDegFL3_11 = &Chromaticity{0.3245, 0.3434}
	WhitesCIE2004TwoDegFL3_12 = &Chromaticity{0.4377, 0.4037}
	WhitesCIE2004TwoDegFL3_13 = &Chromaticity{0.383, 0.3724}
	WhitesCIE2004TwoDegFL3_14 = &Chromaticity{0.3447, 0.3609}
	WhitesCIE2004TwoDegFL3_15 = &Chromaticity{0.3127, 0.3288}
	WhitesCIE2004TwoDegFL4    = &Chromaticity{0.4402, 0.4031}
	WhitesCIE2004TwoDegFL5    = &Chromaticity{0.3138, 0.3452}
	WhitesCIE2004TwoDegFL6    = &Chromaticity{0.3779, 0.3882}
	WhitesCIE2004TwoDegFL7    = &Chromaticity{0.3129, 0.3292}
	WhitesCIE2004TwoDegFL8    = &Chromaticity{0.3458, 0.3586}
	WhitesCIE2004TwoDegFL9    = &Chromaticity{0.3741, 0.3727}
	WhitesCIE2004TwoDegFL10   = &Chromaticity{0.3458, 0.3588}
	WhitesCIE2004TwoDegFL11   = &Chromaticity{0.3805, 0.3769}
	WhitesCIE2004TwoDegFL12   = &Chromaticity{0.4370, 0.4042}
	WhitesCIE2004TwoDegHP1    = &Chromaticity{0.533, 0.415}
	WhitesCIE2004TwoDegHP2    = &Chromaticity{0.4778, 0.4158}
	WhitesCIE2004TwoDegHP3    = &Chromaticity{0.4302, 0.4075}
	WhitesCIE2004TwoDegHP4    = &Chromaticity{0.3812, 0.3797}
	WhitesCIE2004TwoDegHP5    = &Chromaticity{0.3776, 0.3713}

	// Standard illuminants for the CIE 1964 standard observer, from table T.3
	// in CIE 15:2004.
	WhitesCIE2004TenDegA   = &Chromaticity{0.45117, 0.40594}
	WhitesCIE2004TenDegC   = &Chromaticity{0.31039, 0.31905}
	WhitesCIE2004TenDegD50 = &Chromaticity{0.34773, 0.35952}
	WhitesCIE2004TenDegD55 = &Chromaticity{0.33412, 0.34877}
	WhitesCIE2004TenDegD65 = &Chromaticity{0.31381, 0.33098}
	WhitesCIE2004TenDegD75 = &Chromaticity{0.29968, 0.31740}

	// The D50 white point as defined in [CSS Color Module Level 4]. This
	// corresponds to [WhitesCIE2004TwoDegD50] but rounded to 4 digits.
	//
	// [CSS Color Module Level 4]: https://www.w3.org/TR/css-color-4/
	WhitesCSSD50 = &Chromaticity{0.3457, 0.3585}

	// The D65 white point as specified by sRGB. This corresponds to
	// [WhitesCIE2004TwoDegD65] but rounded to 4 digits.
	WhitesSRGBD65 = &Chromaticity{0.3127, 0.3290}
)
View Source
var DisplayP3 = (&Space{
	ID:   "display-p3",
	Name: "Display P3",
	Base: LinearDisplayP3,

	ToBase:   SRGB.ToBase,
	FromBase: SRGB.FromBase,
}).Init()
View Source
var LCh = (&Space{
	ID:   "lch",
	Name: "LCh",
	Coords: [3]Coordinate{
		{Name: "Lightness", Range: infty, RefRange: [2]float64{0, 100}},
		{Name: "Chroma", Range: infty, RefRange: [2]float64{0, 150}},
		{Name: "Hue", Range: infty, IsAngle: true, RefRange: [2]float64{0, 360}},
	},
	Base: Lab,
	FromBase: func(c *[3]float64) [3]float64 {
		return labToLCH(c, 250.0/1e5)
	},
	ToBase: func(cl *[3]float64) [3]float64 {

		l, c, h := cl[0], cl[1], cl[2]
		if c < 0 {
			c = 0
		}
		a := c * math.Cos(h*math.Pi/180.0)
		b := c * math.Sin(h*math.Pi/180)
		return [3]float64{l, a, b}
	},
}).Init()
View Source
var Lab = (&Space{
	ID:   "lab",
	Name: "Lab",
	Coords: [3]Coordinate{
		{Name: "Lightness", Range: infty, RefRange: [2]float64{0, 100}},
		{Name: "a", Range: infty, RefRange: [2]float64{-125, 125}},
		{Name: "b", Range: infty, RefRange: [2]float64{-125, 125}},
	},
	Base: XYZ_D50,
	FromBase: func(c *[3]float64) [3]float64 {
		const (
			ϵ  = 216.0 / 24389.0
			ϵ3 = 24.0 / 116.0
			κ  = 24389.0 / 27.0
		)

		white := WhitesCSSD50.XYZ()
		xyz := *c
		xyz[0] /= white[0]
		xyz[1] /= white[1]
		xyz[2] /= white[2]

		f := func(x float64) float64 {
			if x > ϵ {
				return math.Cbrt(x)
			} else {
				return (κ*x + 16) / 116.0
			}
		}
		x_ := f(xyz[0])
		y_ := f(xyz[1])
		z_ := f(xyz[2])

		l := 116.0*y_ - 16
		a := 500.0 * (x_ - y_)
		b := 200.0 * (y_ - z_)

		return [3]float64{l, a, b}
	},
	ToBase: func(c *[3]float64) [3]float64 {
		const (
			ϵ  = 216.0 / 24389.0
			ϵ3 = 24.0 / 116.0
			κ  = 24389.0 / 27.0
		)

		l, a, b := c[0], c[1], c[2]
		f1 := (l + 16.0) / 116.0
		f0 := a/500.0 + f1
		f2 := f1 - b/200.0

		var x, y, z float64
		if f0 > ϵ3 {
			x = f0 * f0 * f0
		} else {
			x = (116*f0 - 16) / κ
		}
		if l > 8 {
			n := (l + 16.0) / 116.0
			y = n * n * n
		} else {
			y = l / κ
		}
		if f2 > ϵ3 {
			z = f2 * f2 * f2
		} else {
			z = (116.0*f2 - 16) / κ
		}

		white := WhitesCSSD50.XYZ()
		x /= white[0]
		y /= white[1]
		z /= white[2]

		return [3]float64{x, y, z}
	},
}).Init()
View Source
var LinearDisplayP3 = newRGBSpace(
	&rgbSpace{
		ID:   "display-p3-linear",
		Name: "Linear Display P3",
		Base: XYZ_D65,
		ToBase: [3][3]float64{
			{0.4865709486482162, 0.26566769316909306, 0.1982172852343625},
			{0.2289745640697488, 0.6917385218365064, 0.079286914093745},
			{0.0000000000000000, 0.04511338185890264, 1.043944368900976},
		},
		FromBase: [3][3]float64{
			{2.493496911941425, -0.9313836179191239, -0.40271078445071684},
			{-0.8294889695615747, 1.7626640603183463, 0.023624685841943577},
			{0.03584583024378447, -0.07617238926804182, 0.9568845240076872},
		},
	},
)
View Source
var LinearProPhoto = newRGBSpace(
	&rgbSpace{
		ID:   "prophoto-rgb-linear",
		Name: "Linear ProPhoto",
		Base: XYZ_D50,
		ToBase: [3][3]float64{
			{0.79776664490064230, 0.13518129740053308, 0.03134773412839220},
			{0.28807482881940130, 0.71183523424187300, 0.00008993693872564},
			{0.00000000000000000, 0.00000000000000000, 0.82510460251046020},
		},
		FromBase: [3][3]float64{
			{1.34578688164715830, -0.25557208737979464, -0.05110186497554526},
			{-0.54463070512490190, 1.50824774284514680, 0.02052744743642139},
			{0.00000000000000000, 0.00000000000000000, 1.21196754563894520},
		},
	},
)
View Source
var LinearSRGB = newRGBSpace(
	&rgbSpace{
		ID:   "srgb-linear",
		Name: "Linear sRGB",
		Base: XYZ_D65,

		ToBase: [3][3]float64{
			{506752.0 / 1228815.0, 87881.0 / 245763.0, 12673.0 / 70218.0},
			{87098.0 / 409605.0, 175762.0 / 245763.0, 12673.0 / 175545.0},
			{7918.0 / 409605.0, 87881.0 / 737289.0, 1001167.0 / 1053270.0},
		},
		FromBase: [3][3]float64{
			{12831.0 / 3959.0, -329.0 / 214.0, -1974.0 / 3959.0},
			{-851781.0 / 878810.0, 1648619.0 / 878810.0, 36519.0 / 878810.0},
			{705.0 / 12673.0, -2585.0 / 12673.0, 705.0 / 667.0},
		},
	},
)
View Source
var Oklab = (&Space{
	ID:   "oklab",
	Name: "Oklab",
	Coords: [3]Coordinate{
		{Name: "Lightness", Range: infty, RefRange: norm},
		{Name: "a", Range: infty, RefRange: [2]float64{-0.4, 0.4}},
		{Name: "b", Range: infty, RefRange: [2]float64{-0.4, 0.4}},
	},
	Base: XYZ_D65,
	FromBase: func(c *[3]float64) [3]float64 {
		lms := mulVecMat(c, &oklabXyzToLms)

		lms_ := [3]float64{
			math.Cbrt(lms[0]),
			math.Cbrt(lms[1]),
			math.Cbrt(lms[2]),
		}
		lab := mulVecMat(&lms_, &oklabLmsToLab)
		return lab
	},
	ToBase: func(c *[3]float64) [3]float64 {
		lms := mulVecMat(c, &oklabLabToLms)
		lms_ := [3]float64{
			lms[0] * lms[0] * lms[0],
			lms[1] * lms[1] * lms[1],
			lms[2] * lms[2] * lms[2],
		}

		xyz := mulVecMat(&lms_, &oklabLmsToXyz)
		return xyz
	},
}).Init()
View Source
var Oklch = (&Space{
	ID:   "oklch",
	Name: "Oklch",
	Coords: [3]Coordinate{
		{Name: "Lightness", Range: infty, RefRange: norm},
		{Name: "Chroma", Range: infty, RefRange: [2]float64{0, 0.4}},
		{Name: "Hue", Range: infty, IsAngle: true, RefRange: [2]float64{0, 360}},
	},
	Base: Oklab,
	FromBase: func(c *[3]float64) [3]float64 {
		return labToLCH(c, 0.8/1e5)
	},
	ToBase: LCh.ToBase,
}).Init()
View Source
var ProPhoto = (&Space{
	ID:     "prophoto-rgb",
	Name:   "ProPhoto",
	Base:   LinearProPhoto,
	Coords: RGBCoordinates,
	ToBase: func(c *[3]float64) [3]float64 {
		f := func(v float64) float64 {
			if v < 16.0/512.0 {
				return v / 16.0
			} else {
				return math.Pow(v, 1.8)
			}
		}
		return [3]float64{
			f(c[0]),
			f(c[1]),
			f(c[2]),
		}
	},
	FromBase: func(c *[3]float64) [3]float64 {
		f := func(v float64) float64 {
			if v >= 1.0/512.0 {
				return math.Pow(v, (1.0 / 1.8))
			} else {
				return 16 * v
			}
		}
		return [3]float64{
			f(c[0]),
			f(c[1]),
			f(c[2]),
		}
	},
}).Init()
View Source
var RGBCoordinates = [3]Coordinate{
	{Name: "Red", Range: [2]float64{0, 1}},
	{Name: "Green", Range: [2]float64{0, 1}},
	{Name: "Blue", Range: [2]float64{0, 1}},
}
View Source
var SRGB = (&Space{
	ID:   "srgb",
	Name: "sRGB",
	Base: LinearSRGB,
	FromBase: func(c *[3]float64) [3]float64 {

		f := func(ch float64) float64 {
			var sign float64
			if ch < 0 {
				sign = -1.0
			} else {
				sign = 1.0
			}
			abs := ch * sign

			if abs > 0.0031308 {
				return sign * (1.055*(math.Pow(abs, 1.0/2.4)) - 0.055)
			} else {
				return 12.92 * ch
			}
		}
		return [3]float64{f(c[0]), f(c[1]), f(c[2])}
	},
	ToBase: func(c *[3]float64) [3]float64 {

		f := func(ch float64) float64 {
			var sign float64
			if ch < 0 {
				sign = -1
			} else {
				sign = 1
			}
			abs := ch * sign
			if abs <= 0.04045 {
				return ch / 12.92
			} else {
				return sign * math.Pow((abs+0.055)/1.055, 2.4)
			}
		}
		return [3]float64{f(c[0]), f(c[1]), f(c[2])}
	},
}).Init()
View Source
var XYZ_D50 = NewXYZSpace("XYZ D50", "xyz-d50", WhitesCSSD50)
View Source
var XYZ_D65 = (&Space{
	ID:   "xyz-d65",
	Name: "XYZ D65",
	Coords: [3]Coordinate{
		{Name: "X", Range: infty, RefRange: norm},
		{Name: "Y", Range: infty, RefRange: norm},
		{Name: "Z", Range: infty, RefRange: norm},
	},
	White: WhitesSRGBD65,
}).Init()

Functions

func Adapt

func Adapt(xyz *[3]float64, m *[3][3]float64) [3]float64

func ContrastMichelson

func ContrastMichelson(c1, c2 *Color) float64

ContrastMichelson computes the Michelson contrast.

func ContrastWeber

func ContrastWeber(c1, c2 *Color) float64

ContrastWeber computes the Weber luminance contrast.

func DeltaDistance

func DeltaDistance(reference, sample *Color, space *Space) float64

DeltaDistance computes the Euclidean distance in the provided color space.

func DeltaE76

func DeltaE76(reference, sample *Color) float64

DeltaE76 computes the CIE 1976 color difference using the Euclidean distance in the Lab color space.

func DeltaEOK

func DeltaEOK(reference, sample *Color) float64

DeltaEOK computes the color difference using the Euclidean distance in the Oklab color space.

func DeltaEOK2

func DeltaEOK2(reference, sample *Color) float64

DeltaEOK2 computes the color difference using the Euclidean distance in the Oklab color space, with the a and b axes scaled by a factor of 2, for better uniformity.

func RegisterSpace

func RegisterSpace(cs *Space)

RegisterSpace registers a color space. This allows it to be referenced by ID in 'color()' expressions as parsed by Parse and looked up by LookupSpace.

All color spaces provided by this package are automatically registered.

func Step

func Step(c1, c2 *Color, in, out *Space, num int) iter.Seq[Color]

Step computes num colors that lie between c1 and c2, interpolating in the in color space and returning them in the out color space, without applying any gamut mapping.

Types

type CAT

type CAT struct {
	ToCone   [3][3]float64
	FromCone [3][3]float64
}

CAT represents a chromatic adaptation transform. It consists of two matrices, one for converting from XYZ to cone responses and one for converting from cone responses back to XYZ.

Given a CAT, colors can be adapted between any two white points, either by using CAT.Adapt for one-offs, or by combining CAT.Matrix and Adapt, which allows reusing matrices computed for pairs of white points.

func (*CAT) Adapt

func (cat *CAT) Adapt(xyz *[3]float64, src, dst *Chromaticity) [3]float64

func (*CAT) Matrix

func (cat *CAT) Matrix(src, dst *Chromaticity) [3][3]float64

type Chromaticity

type Chromaticity struct {
	X float64
	Y float64
}

Chromaticity describes a color's chromaticity in the CIE 1931 xy color space.

func MakeCIEDaylightIlluminant

func MakeCIEDaylightIlluminant(temp float64) Chromaticity

MakeCIEDaylightIlluminant computes a daylight illuminant at a nominal correlated color temperature. The illuminant's correlated color temperature will be approximately equal to the nominal value, but not exactly so.

Note that due to pecularities in rounding in the CIE standards, values returned by this function will not exactly match predefined daylight illuminants.

The color temperature, specified in Kelvin, must be between 4000 K and 25,000 K.

func (*Chromaticity) XYZ

func (chr *Chromaticity) XYZ() [3]float64

XYZ converts the xy chromaticity to the X, Y, and Z tristimulus values, with Y = 1.

type Color

type Color struct {
	Values [3]float64
	Space  *Space
	Alpha  float64
}

Color represents a color with 3 coordinates in some color space. The meaning of the values depends on the color space.

The values of a color may be out of gamut for the color space. This is allowed so that conversions between color spaces do not lose any information, even if the destination space is smaller than the source space. The package provides functions for explicit gamut mapping.

For convenience, colors include an alpha channel, commonly used for opacity or coverage. The alpha value doesn't affect operations such as color space conversions, gamut mapping, or distance metrics and will simply be preserved. Step, however, will interpolate between the start and end alpha values.

func GamutMapCSS

func GamutMapCSS(c *Color, to *Space) Color

GamutMapCSS uses the CSS gamut mapping algorithm to map individual colors to a destination color space. It implements a relative colorimetric intent. That is, colors that are already inside the target gamut are unchanged. This is intended for mapping individual colors, not for mapping images.

For some limitations of this algorithm, see 1 and 2.

func Make

func Make(space *Space, p1, p2, p3, alpha float64) Color

Make is a convenience function for initializing colors.

func Parse

func Parse(s string) (Color, bool)

Parse parses colors in the CSS 'color()' format. The double dash for non-standard color spaces is optional.

Example
c, ok := Parse("color(lab 0.4 30% 0.2 / 1)")
fmt.Println(c, ok)
Output:

color(--lab 0.400000 -50.000000 0.200000) true

func (*Color) Convert

func (c *Color) Convert(space *Space) Color

Convert converts c from its current color space to a different color space. It does not apply any gamut mapping.

func (*Color) InGamut

func (c *Color) InGamut() bool

InGamut reports whether c's values are in gamut of its color space.

func (*Color) InGamutOf

func (c *Color) InGamutOf(space *Space) bool

InGamutOf reports whether c, when converted to space, is in gamut.

func (Color) String

func (c Color) String() string

type Coordinate

type Coordinate struct {
	// Name is the human readable name of the coordinate.
	Name string
	// Range describes the range of values that are in gamut. For some
	// coordinates in some color spaces, this will be [-∞, ∞].
	Range [2]float64
	// Range describes the values that map to 0% and 100%. If not set, defaults
	// to Range.
	RefRange [2]float64
	// IsAngle is true for coordinates that represent angles, such as color hue.
	IsAngle bool
}

Coordinate is metadata describing a coordinate of a color space.

type Space

type Space struct {
	ID       string
	Name     string
	White    *Chromaticity
	Base     *Space
	Coords   [3]Coordinate
	FromBase func(c *[3]float64) [3]float64
	ToBase   func(c *[3]float64) [3]float64
	// contains filtered or unexported fields
}

Space describes a color space, such as sRGB or HSV.

Color spaces form a tree. Every space, except for XYZ_D65, has a base space and can be converted to and from it. Every space can be converted to any other space by finding a common "connection space". Often, the common space is XYZ D65.

Color spaces are bit-width-agnostic and values are often stored in a normalized form. For example, the R, G, and B coordinates in sRGB will be in the range [0, 1], not [0, 255].

The white point of a color space is described by the White field. This field only serves as documentation and does not affect how conversions are carried out. That is, simply changing the white point of an existing color space will not have the intended effect.

When creating new color spaces, you must call Space.Init once you're done.

func LookupSpace

func LookupSpace(id string) (*Space, bool)

LookupSpace looks up a registered (see RegisterSpace) color space by ID.

func NewXYZSpace

func NewXYZSpace(name, id string, white *Chromaticity) *Space

NewXYZSpace returns a new CIE XYZ color space with the specified name, ID, and white point.

func (*Space) Convert

func (cs *Space) Convert(to *Space, coords [3]float64) [3]float64

func (*Space) InGamut

func (cs *Space) InGamut(values [3]float64) bool

func (*Space) Init

func (cs *Space) Init() *Space

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL