package colorfulimport// Source: https://github.com/hsluv/hsluv-go// Under MIT License// Modified so that Saturation and Luminance are in [0..1] instead of [0..100].// HSLuv uses a rounded version of the D65. This has no impact on the final RGB// values, but to keep high levels of accuracy for internal operations and when// comparing to the test values, this modified white reference is used internally.//// See this GitHub thread for details on these values:// https://github.com/hsluv/hsluv/issues/79var hSLuvD65 = [3]float64{0.95045592705167, 1.0, 1.089057750759878}func (, , float64) (float64, float64, float64) {// [-1..1] but the code expects it to be [-100..100] *= 100.0 *= 100.0var , float64if > 99.9999999 || < 0.00000001 { = 0.0 } else { = maxChromaForLH(, ) = / * 100.0 }return , clamp01( / 100.0), clamp01( / 100.0)}func (, , float64) (float64, float64, float64) { *= 100.0 *= 100.0var , float64if > 99.9999999 || < 0.00000001 { = 0.0 } else { = maxChromaForLH(, ) = / 100.0 * }// c is [-100..100], but for LCh it's supposed to be almost [-1..1]returnclamp01( / 100.0), / 100.0, }func (, , float64) (float64, float64, float64) {// [-1..1] but the code expects it to be [-100..100] *= 100.0 *= 100.0var , float64if > 99.9999999 || < 0.00000001 { = 0.0 } else { = maxSafeChromaForL() = / * 100.0 }return , / 100.0, / 100.0}func (, , float64) (float64, float64, float64) {// [-1..1] but the code expects it to be [-100..100] *= 100.0 *= 100.0var , float64if > 99.9999999 || < 0.00000001 { = 0.0 } else { = maxSafeChromaForL() = / 100.0 * }return / 100.0, / 100.0, }// HSLuv creates a new Color from values in the HSLuv color space.// Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1].//// The returned color values are clamped (using .Clamped), so this will never output// an invalid color.func (, , float64) Color {// HSLuv -> LuvLCh -> CIELUV -> CIEXYZ -> Linear RGB -> sRGB , , := LuvLChToLuv(HSLuvToLuvLCh(, , ))returnLinearRgb(XyzToLinearRgb(LuvToXyzWhiteRef(, , , hSLuvD65))).Clamped()}// HPLuv creates a new Color from values in the HPLuv color space.// Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1].//// The returned color values are clamped (using .Clamped), so this will never output// an invalid color.func (, , float64) Color {// HPLuv -> LuvLCh -> CIELUV -> CIEXYZ -> Linear RGB -> sRGB , , := LuvLChToLuv(HPLuvToLuvLCh(, , ))returnLinearRgb(XyzToLinearRgb(LuvToXyzWhiteRef(, , , hSLuvD65))).Clamped()}// HSLuv returns the Hue, Saturation and Luminance of the color in the HSLuv// color space. Hue in [0..360], a Saturation [0..1], and a Luminance// (lightness) in [0..1].func ( Color) () (, , float64) {// sRGB -> Linear RGB -> CIEXYZ -> CIELUV -> LuvLCh -> HSLuvreturnLuvLChToHSLuv(.LuvLChWhiteRef(hSLuvD65))}// HPLuv returns the Hue, Saturation and Luminance of the color in the HSLuv// color space. Hue in [0..360], a Saturation [0..1], and a Luminance// (lightness) in [0..1].//// Note that HPLuv can only represent pastel colors, and so the Saturation// value could be much larger than 1 for colors it can't represent.func ( Color) () (, , float64) {returnLuvLChToHPLuv(.LuvLChWhiteRef(hSLuvD65))}// DistanceHSLuv calculates Euclidan distance in the HSLuv colorspace. No idea// how useful this is.//// The Hue value is divided by 100 before the calculation, so that H, S, and L// have the same relative ranges.func ( Color) ( Color) float64 { , , := .HSLuv() , , := .HSLuv()returnmath.Sqrt(sq((-)/100.0) + sq(-) + sq(-))}// DistanceHPLuv calculates Euclidean distance in the HPLuv colorspace. No idea// how useful this is.//// The Hue value is divided by 100 before the calculation, so that H, S, and L// have the same relative ranges.func ( Color) ( Color) float64 { , , := .HPLuv() , , := .HPLuv()returnmath.Sqrt(sq((-)/100.0) + sq(-) + sq(-))}var m = [3][3]float64{ {3.2409699419045214, -1.5373831775700935, -0.49861076029300328}, {-0.96924363628087983, 1.8759675015077207, 0.041555057407175613}, {0.055630079696993609, -0.20397695888897657, 1.0569715142428786},}const kappa = 903.2962962962963const epsilon = 0.0088564516790356308func maxChromaForLH(, float64) float64 { := / 360.0 * math.Pi * 2.0 := math.MaxFloat64for , := rangegetBounds() { := lengthOfRayUntilIntersect(, [0], [1])if > 0.0 && < { = } }return}func getBounds( float64) [6][2]float64 {varfloat64var [6][2]float64 := math.Pow(+16.0, 3.0) / 1560896.0if > epsilon { = } else { = / kappa }for := rangem {for := 0; < 2; ++ { := (284517.0*m[][0] - 94839.0*m[][2]) * := (838422.0*m[][2]+769860.0*m[][1]+731718.0*m[][0])** - 769860.0*float64()* := (632260.0*m[][2]-126452.0*m[][1])* + 126452.0*float64() [*2+][0] = / [*2+][1] = / } }return}func lengthOfRayUntilIntersect(, , float64) ( float64) { = / (math.Sin() - *math.Cos())return}func maxSafeChromaForL( float64) float64 { := math.MaxFloat64for , := rangegetBounds() { := [0] := [1] := intersectLineLine(, , -1.0/, 0.0) := distanceFromPole(, +*)if < { = } }return}func intersectLineLine(, , , float64) float64 {return ( - ) / ( - )}func distanceFromPole(, float64) float64 {returnmath.Sqrt(math.Pow(, 2.0) + math.Pow(, 2.0))}
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.