// The colorful package provides all kinds of functions for working with colors.
package colorfulimport ()// A color is stored internally using sRGB (standard RGB) values in the range 0-1typeColorstruct { R, G, B float64}// Implement the Go color.Color interface.func ( Color) () (, , , uint32) { = uint32(.R*65535.0 + 0.5) = uint32(.G*65535.0 + 0.5) = uint32(.B*65535.0 + 0.5) = 0xFFFFreturn}// Constructs a colorful.Color from something implementing color.Colorfunc ( color.Color) (Color, bool) { , , , := .RGBA()if == 0 {returnColor{0, 0, 0}, false }// Since color.Color is alpha pre-multiplied, we need to divide the // RGB values by alpha again in order to get back the original RGB. *= 0xffff /= *= 0xffff /= *= 0xffff /= returnColor{float64() / 65535.0, float64() / 65535.0, float64() / 65535.0}, true}// Might come in handy sometimes to reduce boilerplate code.func ( Color) () (, , uint8) { = uint8(.R*255.0 + 0.5) = uint8(.G*255.0 + 0.5) = uint8(.B*255.0 + 0.5)return}// Used to simplify HSLuv testing.func ( Color) () (float64, float64, float64) {return .R, .G, .B}// This is the tolerance used when comparing colors using AlmostEqualRgb.constDelta = 1.0 / 255.0// This is the default reference white point.varD65 = [3]float64{0.95047, 1.00000, 1.08883}// And another one.varD50 = [3]float64{0.96422, 1.00000, 0.82521}// Checks whether the color exists in RGB space, i.e. all values are in [0..1]func ( Color) () bool {return0.0 <= .R && .R <= 1.0 &&0.0 <= .G && .G <= 1.0 &&0.0 <= .B && .B <= 1.0}// clamp01 clamps from 0 to 1.func clamp01( float64) float64 {returnmath.Max(0.0, math.Min(, 1.0))}// Returns Clamps the color into valid range, clamping each value to [0..1]// If the color is valid already, this is a no-op.func ( Color) () Color {returnColor{clamp01(.R), clamp01(.G), clamp01(.B)}}func sq( float64) float64 {return * }func cub( float64) float64 {return * * }// DistanceRgb computes the distance between two colors in RGB space.// This is not a good measure! Rather do it in Lab space.func ( Color) ( Color) float64 {returnmath.Sqrt(sq(.R-.R) + sq(.G-.G) + sq(.B-.B))}// DistanceLinearRGB computes the distance between two colors in linear RGB// space. This is not useful for measuring how humans perceive color, but// might be useful for other things, like dithering.func ( Color) ( Color) float64 { , , := .LinearRgb() , , := .LinearRgb()returnmath.Sqrt(sq(-) + sq(-) + sq(-))}// Check for equality between colors within the tolerance Delta (1/255).func ( Color) ( Color) bool {returnmath.Abs(.R-.R)+math.Abs(.G-.G)+math.Abs(.B-.B) < 3.0*Delta}// You don't really want to use this, do you? Go for BlendLab, BlendLuv or BlendHcl.func ( Color) ( Color, float64) Color {returnColor{.R + *(.R-.R), .G + *(.G-.G), .B + *(.B-.B)}}// Utility used by Hxx color-spaces for interpolating between two angles in [0,360].func interp_angle(, , float64) float64 {// Based on the answer here: http://stackoverflow.com/a/14498790/2366315 // With potential proof that it works here: http://math.stackexchange.com/a/2144499 := math.Mod(math.Mod(-, 360.0)+540, 360.0) - 180.0returnmath.Mod(+*+360.0, 360.0)}/// HSV //////////////// From http://en.wikipedia.org/wiki/HSL_and_HSV// Note that h is in [0..360] and s,v in [0..1]// Hsv returns the Hue [0..360], Saturation and Value [0..1] of the color.func ( Color) () (, , float64) { := math.Min(math.Min(.R, .G), .B) = math.Max(math.Max(.R, .G), .B) := - = 0.0if != 0.0 { = / } = 0.0// We use 0 instead of undefined as in wp.if != {if == .R { = math.Mod((.G-.B)/, 6.0) }if == .G { = (.B-.R)/ + 2.0 }if == .B { = (.R-.G)/ + 4.0 } *= 60.0if < 0.0 { += 360.0 } }return}// Hsv creates a new Color given a Hue in [0..360], a Saturation and a Value in [0..1]func (, , float64) Color { := / 60.0 := * := * (1.0 - math.Abs(math.Mod(, 2.0)-1.0)) := - , , := 0.0, 0.0, 0.0switch {case0.0 <= && < 1.0: = = case1.0 <= && < 2.0: = = case2.0 <= && < 3.0: = = case3.0 <= && < 4.0: = = case4.0 <= && < 5.0: = = case5.0 <= && < 6.0: = = }returnColor{ + , + , + }}// You don't really want to use this, do you? Go for BlendLab, BlendLuv or BlendHcl.func ( Color) ( Color, float64) Color { , , := .Hsv() , , := .Hsv()// We know that h are both in [0..360]returnHsv(interp_angle(, , ), +*(-), +*(-))}/// HSL //////////////// Hsl returns the Hue [0..360], Saturation [0..1], and Luminance (lightness) [0..1] of the color.func ( Color) () (, , float64) { := math.Min(math.Min(.R, .G), .B) := math.Max(math.Max(.R, .G), .B) = ( + ) / 2if == { = 0 = 0 } else {if < 0.5 { = ( - ) / ( + ) } else { = ( - ) / (2.0 - - ) }if == .R { = (.G - .B) / ( - ) } elseif == .G { = 2.0 + (.B-.R)/(-) } else { = 4.0 + (.R-.G)/(-) } *= 60if < 0 { += 360 } }return}// Hsl creates a new Color given a Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1]func (, , float64) Color {if == 0 {returnColor{, , } }var , , float64varfloat64varfloat64varfloat64varfloat64varfloat64if < 0.5 { = * (1.0 + ) } else { = + - * } = 2* - /= 360 = + 1.0/3.0 = = - 1.0/3.0if < 0 { ++ }if > 1 { -- }if < 0 { ++ }if > 1 { -- }if < 0 { ++ }if > 1 { -- }// Redif6* < 1 { = + (-)*6* } elseif2* < 1 { = } elseif3* < 2 { = + (-)*(2.0/3.0-)*6 } else { = }// Greenif6* < 1 { = + (-)*6* } elseif2* < 1 { = } elseif3* < 2 { = + (-)*(2.0/3.0-)*6 } else { = }// Blueif6* < 1 { = + (-)*6* } elseif2* < 1 { = } elseif3* < 2 { = + (-)*(2.0/3.0-)*6 } else { = }returnColor{, , }}/// Hex //////////////// Hex returns the hex "html" representation of the color, as in #ff0080.func ( Color) () string {// Add 0.5 for roundingreturnfmt.Sprintf("#%02x%02x%02x", uint8(.R*255.0+0.5), uint8(.G*255.0+0.5), uint8(.B*255.0+0.5))}// Hex parses a "html" hex color-string, either in the 3 "#f0c" or 6 "#ff1034" digits form.func ( string) (Color, error) { := "#%02x%02x%02x" := 1.0 / 255.0iflen() == 4 { = "#%1x%1x%1x" = 1.0 / 15.0 }var , , uint8 , := fmt.Sscanf(, , &, &, &)if != nil {returnColor{}, }if != 3 {returnColor{}, fmt.Errorf("color: %v is not a hex-color", ) }returnColor{float64() * , float64() * , float64() * }, nil}/// Linear /////////////////// http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/// http://www.brucelindbloom.com/Eqn_RGB_to_XYZ.htmlfunc linearize( float64) float64 {if <= 0.04045 {return / 12.92 }returnmath.Pow((+0.055)/1.055, 2.4)}// LinearRgb converts the color into the linear RGB space (see http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/).func ( Color) () (, , float64) { = linearize(.R) = linearize(.G) = linearize(.B)return}// A much faster and still quite precise linearization using a 6th-order Taylor approximation.// See the accompanying Jupyter notebook for derivation of the constants.func linearize_fast( float64) float64 { := - 0.5 := * := * := * //v5 := v3*v2return -0.248750514614486 + 0.925583310193438* + 1.16740237321695* + 0.280457026598666* - 0.0757991963780179* //+ 0.0437040411548932*v5}// FastLinearRgb is much faster than and almost as accurate as LinearRgb.// BUT it is important to NOTE that they only produce good results for valid colors r,g,b in [0,1].func ( Color) () (, , float64) { = linearize_fast(.R) = linearize_fast(.G) = linearize_fast(.B)return}func delinearize( float64) float64 {if <= 0.0031308 {return12.92 * }return1.055*math.Pow(, 1.0/2.4) - 0.055}// LinearRgb creates an sRGB color out of the given linear RGB color (see http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/).func (, , float64) Color {returnColor{delinearize(), delinearize(), delinearize()}}func delinearize_fast( float64) float64 {// This function (fractional root) is much harder to linearize, so we need to split.if > 0.2 { := - 0.6 := * := * := * := * return0.442430344268235 + 0.592178981271708* - 0.287864782562636* + 0.253214392068985* - 0.272557158129811* + 0.325554383321718* } elseif > 0.03 { := - 0.115 := * := * := * := * return0.194915592891669 + 1.55227076330229* - 3.93691860257828* + 18.0679839248761* - 101.468750302746* + 632.341487393927* } else { := - 0.015 := * := * := * := * // You can clearly see from the involved constants that the low-end is highly nonlinear.return0.0519565234928877 + 5.09316778537561* - 99.0338180489702* + 3484.52322764895* - 150028.083412663* + 7168008.42971613* }}// FastLinearRgb is much faster than and almost as accurate as LinearRgb.// BUT it is important to NOTE that they only produce good results for valid inputs r,g,b in [0,1].func (, , float64) Color {returnColor{delinearize_fast(), delinearize_fast(), delinearize_fast()}}// XyzToLinearRgb converts from CIE XYZ-space to Linear RGB space.func (, , float64) (, , float64) { = 3.2409699419045214* - 1.5373831775700935* - 0.49861076029300328* = -0.96924363628087983* + 1.8759675015077207* + 0.041555057407175613* = 0.055630079696993609* - 0.20397695888897657* + 1.0569715142428786*return}func (, , float64) (, , float64) { = 0.41239079926595948* + 0.35758433938387796* + 0.18048078840183429* = 0.21263900587151036* + 0.71516867876775593* + 0.072192315360733715* = 0.019330818715591851* + 0.11919477979462599* + 0.95053215224966058*return}/// XYZ //////////////// http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/func ( Color) () (, , float64) {returnLinearRgbToXyz(.LinearRgb())}func (, , float64) Color {returnLinearRgb(XyzToLinearRgb(, , ))}/// xyY //////////////// http://www.brucelindbloom.com/Eqn_XYZ_to_xyY.html// Well, the name is bad, since it's xyY but Golang needs me to start with a// capital letter to make the method public.func (, , float64) (, , float64) {returnXyzToXyyWhiteRef(, , , D65)}func (, , float64, [3]float64) (, , float64) { = := + + ifmath.Abs() < 1e-14 {// When we have black, Bruce Lindbloom recommends to use // the reference white's chromacity for x and y. = [0] / ([0] + [1] + [2]) = [1] / ([0] + [1] + [2]) } else { = / = / }return}func (, , float64) (, , float64) { = if -1e-14 < && < 1e-14 { = 0.0 = 0.0 } else { = / * = / * (1.0 - - ) }return}// Converts the given color to CIE xyY space using D65 as reference white.// (Note that the reference white is only used for black input.)// x, y and Y are in [0..1]func ( Color) () (, , float64) {returnXyzToXyy(.Xyz())}// Converts the given color to CIE xyY space, taking into account// a given reference white. (i.e. the monitor's white)// (Note that the reference white is only used for black input.)// x, y and Y are in [0..1]func ( Color) ( [3]float64) (, , float64) { , , := .Xyz()returnXyzToXyyWhiteRef(, , , )}// Generates a color by using data given in CIE xyY space.// x, y and Y are in [0..1]func (, , float64) Color {returnXyz(XyyToXyz(, , ))}/// L*a*b* /////////////////// http://en.wikipedia.org/wiki/Lab_color_space#CIELAB-CIEXYZ_conversions// For L*a*b*, we need to L*a*b*<->XYZ->RGB and the first one is device dependent.func lab_f( float64) float64 {if > 6.0/29.0*6.0/29.0*6.0/29.0 {returnmath.Cbrt() }return /3.0*29.0/6.0*29.0/6.0 + 4.0/29.0}func (, , float64) (, , float64) {// Use D65 white as reference point by default. // http://www.fredmiranda.com/forum/topic/1035332 // http://en.wikipedia.org/wiki/Standard_illuminantreturnXyzToLabWhiteRef(, , , D65)}func (, , float64, [3]float64) (, , float64) { := lab_f( / [1]) = 1.16* - 0.16 = 5.0 * (lab_f(/[0]) - ) = 2.0 * ( - lab_f(/[2]))return}func lab_finv( float64) float64 {if > 6.0/29.0 {return * * }return3.0 * 6.0 / 29.0 * 6.0 / 29.0 * ( - 4.0/29.0)}func (, , float64) (, , float64) {// D65 white (see above).returnLabToXyzWhiteRef(, , , D65)}func (, , float64, [3]float64) (, , float64) { := ( + 0.16) / 1.16 = [0] * lab_finv(+/5.0) = [1] * lab_finv() = [2] * lab_finv(-/2.0)return}// Converts the given color to CIE L*a*b* space using D65 as reference white.func ( Color) () (, , float64) {returnXyzToLab(.Xyz())}// Converts the given color to CIE L*a*b* space, taking into account// a given reference white. (i.e. the monitor's white)func ( Color) ( [3]float64) (, , float64) { , , := .Xyz()returnXyzToLabWhiteRef(, , , )}// Generates a color by using data given in CIE L*a*b* space using D65 as reference white.// WARNING: many combinations of `l`, `a`, and `b` values do not have corresponding// valid RGB values, check the FAQ in the README if you're unsure.func (, , float64) Color {returnXyz(LabToXyz(, , ))}// Generates a color by using data given in CIE L*a*b* space, taking// into account a given reference white. (i.e. the monitor's white)func (, , float64, [3]float64) Color {returnXyz(LabToXyzWhiteRef(, , , ))}// DistanceLab is a good measure of visual similarity between two colors!// A result of 0 would mean identical colors, while a result of 1 or higher// means the colors differ a lot.func ( Color) ( Color) float64 { , , := .Lab() , , := .Lab()returnmath.Sqrt(sq(-) + sq(-) + sq(-))}// DistanceCIE76 is the same as DistanceLab.func ( Color) ( Color) float64 {return .DistanceLab()}// Uses the CIE94 formula to calculate color distance. More accurate than// DistanceLab, but also more work.func ( Color) ( Color) float64 { , , := .Lab() , , := .Lab()// NOTE: Since all those formulas expect L,a,b values 100x larger than we // have them in this library, we either need to adjust all constants // in the formula, or convert the ranges of L,a,b before, and then // scale the distances down again. The latter is less error-prone. , , = *100.0, *100.0, *100.0 , , = *100.0, *100.0, *100.0 := 1.0// 2.0 for textiles := 1.0 := 1.0 := 0.045// 0.048 for textiles := 0.015// 0.014 for textiles. := - := math.Sqrt(sq() + sq()) := math.Sqrt(sq() + sq()) := - // Not taking Sqrt here for stability, and it's unnecessary. := sq(-) + sq(-) - sq() := 1.0 := 1.0 + * := 1.0 + * := sq( / ( * )) := sq( / ( * )) := / sq(*)returnmath.Sqrt(++) * 0.01// See above.}// DistanceCIEDE2000 uses the Delta E 2000 formula to calculate color// distance. It is more expensive but more accurate than both DistanceLab// and DistanceCIE94.func ( Color) ( Color) float64 {return .DistanceCIEDE2000klch(, 1.0, 1.0, 1.0)}// DistanceCIEDE2000klch uses the Delta E 2000 formula with custom values// for the weighting factors kL, kC, and kH.func ( Color) ( Color, , , float64) float64 { , , := .Lab() , , := .Lab()// As with CIE94, we scale up the ranges of L,a,b beforehand and scale // them down again afterwards. , , = *100.0, *100.0, *100.0 , , = *100.0, *100.0, *100.0 := math.Sqrt(sq() + sq()) := math.Sqrt(sq() + sq()) := ( + ) / 2 := 0.5 * (1 - math.Sqrt(math.Pow(, 7)/(math.Pow(, 7)+math.Pow(25, 7)))) := (1 + ) * := (1 + ) * := math.Sqrt(sq() + sq()) := math.Sqrt(sq() + sq()) := 0.0if != || != 0 { = math.Atan2(, )if < 0 { += math.Pi * 2 } *= 180 / math.Pi } := 0.0if != || != 0 { = math.Atan2(, )if < 0 { += math.Pi * 2 } *= 180 / math.Pi } := - := - := 0.0 := * if != 0 { = - if > 180 { -= 360 } elseif < -180 { += 360 } } := 2 * math.Sqrt() * math.Sin(/2*math.Pi/180) := ( + ) / 2 := ( + ) / 2 := + if != 0 { /= 2ifmath.Abs(-) > 180 {if + < 360 { += 180 } else { -= 180 } } } := 1 - 0.17*math.Cos((-30)*math.Pi/180) + 0.24*math.Cos(2**math.Pi/180) + 0.32*math.Cos((3*+6)*math.Pi/180) - 0.2*math.Cos((4*-63)*math.Pi/180) := 30 * math.Exp(-sq((-275)/25)) := 2 * math.Sqrt(math.Pow(, 7)/(math.Pow(, 7)+math.Pow(25, 7))) := 1 + (0.015*sq(-50))/math.Sqrt(20+sq(-50)) := 1 + 0.045* := 1 + 0.015** := -math.Sin(2**math.Pi/180) * returnmath.Sqrt(sq(/(*))+sq(/(*))+sq(/(*))+*(/(*))*(/(*))) * 0.01}// BlendLab blends two colors in the L*a*b* color-space, which should result in a smoother blend.// t == 0 results in c1, t == 1 results in c2func ( Color) ( Color, float64) Color { , , := .Lab() , , := .Lab()returnLab(+*(-), +*(-), +*(-))}/// L*u*v* /////////////////// http://en.wikipedia.org/wiki/CIELUV#XYZ_.E2.86.92_CIELUV_and_CIELUV_.E2.86.92_XYZ_conversions// For L*u*v*, we need to L*u*v*<->XYZ<->RGB and the first one is device dependent.func (, , float64) (, , float64) {// Use D65 white as reference point by default. // http://www.fredmiranda.com/forum/topic/1035332 // http://en.wikipedia.org/wiki/Standard_illuminantreturnXyzToLuvWhiteRef(, , , D65)}func (, , float64, [3]float64) (, , float64) {if /[1] <= 6.0/29.0*6.0/29.0*6.0/29.0 { = / [1] * (29.0 / 3.0 * 29.0 / 3.0 * 29.0 / 3.0) / 100.0 } else { = 1.16*math.Cbrt(/[1]) - 0.16 } , := xyz_to_uv(, , ) , := xyz_to_uv([0], [1], [2]) = 13.0 * * ( - ) = 13.0 * * ( - )return}// For this part, we do as R's graphics.hcl does, not as wikipedia does.// Or is it the same?func xyz_to_uv(, , float64) (, float64) { := + 15.0* + 3.0*if == 0.0 { , = 0.0, 0.0 } else { = 4.0 * / = 9.0 * / }return}func (, , float64) (, , float64) {// D65 white (see above).returnLuvToXyzWhiteRef(, , , D65)}func (, , float64, [3]float64) (, , float64) {//y = wref[1] * lab_finv((l + 0.16) / 1.16)if <= 0.08 { = [1] * * 100.0 * 3.0 / 29.0 * 3.0 / 29.0 * 3.0 / 29.0 } else { = [1] * cub((+0.16)/1.16) } , := xyz_to_uv([0], [1], [2])if != 0.0 { := /(13.0*) + := /(13.0*) + = * 9.0 * / (4.0 * ) = * (12.0 - 3.0* - 20.0*) / (4.0 * ) } else { , = 0.0, 0.0 }return}// Converts the given color to CIE L*u*v* space using D65 as reference white.// L* is in [0..1] and both u* and v* are in about [-1..1]func ( Color) () (, , float64) {returnXyzToLuv(.Xyz())}// Converts the given color to CIE L*u*v* space, taking into account// a given reference white. (i.e. the monitor's white)// L* is in [0..1] and both u* and v* are in about [-1..1]func ( Color) ( [3]float64) (, , float64) { , , := .Xyz()returnXyzToLuvWhiteRef(, , , )}// Generates a color by using data given in CIE L*u*v* space using D65 as reference white.// L* is in [0..1] and both u* and v* are in about [-1..1]// WARNING: many combinations of `l`, `u`, and `v` values do not have corresponding// valid RGB values, check the FAQ in the README if you're unsure.func (, , float64) Color {returnXyz(LuvToXyz(, , ))}// Generates a color by using data given in CIE L*u*v* space, taking// into account a given reference white. (i.e. the monitor's white)// L* is in [0..1] and both u* and v* are in about [-1..1]func (, , float64, [3]float64) Color {returnXyz(LuvToXyzWhiteRef(, , , ))}// DistanceLuv is a good measure of visual similarity between two colors!// A result of 0 would mean identical colors, while a result of 1 or higher// means the colors differ a lot.func ( Color) ( Color) float64 { , , := .Luv() , , := .Luv()returnmath.Sqrt(sq(-) + sq(-) + sq(-))}// BlendLuv blends two colors in the CIE-L*u*v* color-space, which should result in a smoother blend.// t == 0 results in c1, t == 1 results in c2func ( Color) ( Color, float64) Color { , , := .Luv() , , := .Luv()returnLuv(+*(-), +*(-), +*(-))}/// HCL //////////////// HCL is nothing else than L*a*b* in cylindrical coordinates!// (this was wrong on English wikipedia, I fixed it, let's hope the fix stays.)// But it is widely popular since it is a "correct HSV"// http://www.hunterlab.com/appnotes/an09_96a.pdf// Converts the given color to HCL space using D65 as reference white.// H values are in [0..360], C and L values are in [0..1] although C can overshoot 1.0func ( Color) () (, , float64) {return .HclWhiteRef(D65)}func (, , float64) (, , float64) {// Oops, floating point workaround necessary if a ~= b and both are very small (i.e. almost zero).ifmath.Abs(-) > 1e-4 && math.Abs() > 1e-4 { = math.Mod(57.29577951308232087721*math.Atan2(, )+360.0, 360.0) // Rad2Deg } else { = 0.0 } = math.Sqrt(sq() + sq()) = return}// Converts the given color to HCL space, taking into account// a given reference white. (i.e. the monitor's white)// H values are in [0..360], C and L values are in [0..1]func ( Color) ( [3]float64) (, , float64) { , , := .LabWhiteRef()returnLabToHcl(, , )}// Generates a color by using data given in HCL space using D65 as reference white.// H values are in [0..360], C and L values are in [0..1]// WARNING: many combinations of `h`, `c`, and `l` values do not have corresponding// valid RGB values, check the FAQ in the README if you're unsure.func (, , float64) Color {returnHclWhiteRef(, , , D65)}func (, , float64) (, , float64) { := 0.01745329251994329576 * // Deg2Rad = * math.Cos() = * math.Sin() = return}// Generates a color by using data given in HCL space, taking// into account a given reference white. (i.e. the monitor's white)// H values are in [0..360], C and L values are in [0..1]func (, , float64, [3]float64) Color { , , := HclToLab(, , )returnLabWhiteRef(, , , )}// BlendHcl blends two colors in the CIE-L*C*h° color-space, which should result in a smoother blend.// t == 0 results in c1, t == 1 results in c2func ( Color) ( Color, float64) Color { , , := .Hcl() , , := .Hcl()// We know that h are both in [0..360]returnHcl(interp_angle(, , ), +*(-), +*(-)).Clamped()}// LuvLch// Converts the given color to LuvLCh space using D65 as reference white.// h values are in [0..360], C and L values are in [0..1] although C can overshoot 1.0func ( Color) () (, , float64) {return .LuvLChWhiteRef(D65)}func (, , float64) (, , float64) {// Oops, floating point workaround necessary if u ~= v and both are very small (i.e. almost zero).ifmath.Abs(-) > 1e-4 && math.Abs() > 1e-4 { = math.Mod(57.29577951308232087721*math.Atan2(, )+360.0, 360.0) // Rad2Deg } else { = 0.0 } = = math.Sqrt(sq() + sq())return}// Converts the given color to LuvLCh space, taking into account// a given reference white. (i.e. the monitor's white)// h values are in [0..360], c and l values are in [0..1]func ( Color) ( [3]float64) (, , float64) {returnLuvToLuvLCh(.LuvWhiteRef())}// Generates a color by using data given in LuvLCh space using D65 as reference white.// h values are in [0..360], C and L values are in [0..1]// WARNING: many combinations of `l`, `c`, and `h` values do not have corresponding// valid RGB values, check the FAQ in the README if you're unsure.func (, , float64) Color {returnLuvLChWhiteRef(, , , D65)}func (, , float64) (, , float64) { := 0.01745329251994329576 * // Deg2Rad = * math.Cos() = * math.Sin() = return}// Generates a color by using data given in LuvLCh space, taking// into account a given reference white. (i.e. the monitor's white)// h values are in [0..360], C and L values are in [0..1]func (, , float64, [3]float64) Color { , , := LuvLChToLuv(, , )returnLuvWhiteRef(, , , )}// BlendLuvLCh blends two colors in the cylindrical CIELUV color space.// t == 0 results in c1, t == 1 results in c2func ( Color) ( Color, float64) Color { , , := .LuvLCh() , , := .LuvLCh()// We know that h are both in [0..360]returnLuvLCh(+*(-), +*(-), interp_angle(, , ))}
The pages are generated with Goldsv0.8.2. (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 @zigo_101 (reachable from the left QR code) to get the latest news of Golds.