You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
644 lines
16 KiB
644 lines
16 KiB
package color
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"git.aiterp.net/lucifer3/server/internal/gentools"
|
|
"github.com/lucasb-eyer/go-colorful"
|
|
"log"
|
|
"math"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Color struct {
|
|
RGB *RGB `json:"rgb,omitempty"`
|
|
HS *HueSat `json:"hs,omitempty"`
|
|
K *int `json:"k,omitempty"`
|
|
XY *XY `json:"xy,omitempty"`
|
|
}
|
|
|
|
func (col *Color) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(col.String())
|
|
}
|
|
|
|
func (col *Color) UnmarshalJSON(bytes []byte) error {
|
|
var s string
|
|
err := json.Unmarshal(bytes, &s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
*col, err = Parse(s)
|
|
return err
|
|
}
|
|
|
|
func (col *Color) IsHueSat() bool {
|
|
return col.HS != nil
|
|
}
|
|
|
|
func (col *Color) IsHueSatKelvin() bool {
|
|
return col.HS != nil && col.K != nil
|
|
}
|
|
|
|
func (col *Color) IsKelvin() bool {
|
|
return col.K != nil
|
|
}
|
|
|
|
func (col *Color) IsEmpty() bool {
|
|
return *col == Color{}
|
|
}
|
|
|
|
func (col *Color) SetK(k int) {
|
|
*col = Color{K: &k}
|
|
}
|
|
|
|
func (col *Color) SetXY(xy XY) {
|
|
*col = Color{XY: &xy}
|
|
}
|
|
|
|
func (col *Color) AlmostEquals(other Color) bool {
|
|
if col.HS != nil && other.HS != nil {
|
|
if math.Abs(col.HS.Hue-other.HS.Hue) > 0.01 {
|
|
return false
|
|
}
|
|
if math.Abs(col.HS.Sat-other.HS.Sat) > 0.01 {
|
|
return false
|
|
}
|
|
|
|
if col.K != nil && other.K != nil && *col.K != *other.K {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
if col.K != nil {
|
|
if other.K != nil {
|
|
return false
|
|
}
|
|
|
|
return *col.K == *other.K
|
|
}
|
|
|
|
if col.RGB != nil && other.RGB != nil {
|
|
if math.Abs(col.RGB.Red-other.RGB.Red) > 0.01 {
|
|
return false
|
|
}
|
|
if math.Abs(col.RGB.Blue-other.RGB.Blue) > 0.01 {
|
|
return false
|
|
}
|
|
if math.Abs(col.RGB.Green-other.RGB.Green) > 0.01 {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
xy1, _ := col.ToXY()
|
|
xy2, _ := other.ToXY()
|
|
return math.Abs(xy1.XY.X-xy2.XY.X)+math.Abs(xy1.XY.Y-xy2.XY.Y) < 0.001
|
|
}
|
|
|
|
// ToRGB tries to copy the color to an RGB color. If it's already RGB, it will be plainly copied, but HS
|
|
// will be returned. If ok is false, then no copying has occurred and cv2 will be blank.
|
|
func (col *Color) ToRGB() (col2 Color, ok bool) {
|
|
if col.RGB != nil {
|
|
rgb := *col.RGB
|
|
col2 = Color{RGB: &rgb}
|
|
ok = true
|
|
} else if col.HS != nil {
|
|
rgb := col.HS.ToRGB()
|
|
col2 = Color{RGB: &rgb}
|
|
ok = true
|
|
} else if col.XY != nil {
|
|
rgb := col.XY.ToRGB()
|
|
col2 = Color{RGB: &rgb}
|
|
ok = true
|
|
} else if col.K != nil {
|
|
rgb := kToRGB(*col.K)
|
|
col2 = Color{RGB: &rgb}
|
|
ok = true
|
|
}
|
|
|
|
if ok {
|
|
col2 = Color{RGB: &RGB{
|
|
Red: math.Max(col2.RGB.Red, 0.0),
|
|
Green: math.Max(col2.RGB.Green, 0.0),
|
|
Blue: math.Max(col2.RGB.Blue, 0.0),
|
|
}}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (col *Color) ToHS() (col2 Color, ok bool) {
|
|
if col.HS != nil {
|
|
hs := *col.HS
|
|
col2 = Color{HS: &hs}
|
|
ok = true
|
|
} else if col.RGB != nil {
|
|
hs := col.RGB.ToHS()
|
|
col2 = Color{HS: &hs}
|
|
ok = true
|
|
} else if col.XY != nil {
|
|
hs := col.XY.ToHS()
|
|
col2 = Color{HS: &hs}
|
|
ok = true
|
|
} else if col.K != nil {
|
|
hs := kToRGB(*col.K).ToHS()
|
|
col2 = Color{HS: &hs}
|
|
ok = true
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (col *Color) ToHSK() (col2 Color, ok bool) {
|
|
k := 4000
|
|
|
|
if col.HS != nil {
|
|
hs := *col.HS
|
|
col2 = Color{HS: &hs}
|
|
|
|
if col.K != nil {
|
|
k = *col.K
|
|
}
|
|
col2.K = &k
|
|
|
|
ok = true
|
|
} else if col.RGB != nil {
|
|
hs := col.RGB.ToHS()
|
|
col2 = Color{HS: &hs}
|
|
col2.K = &k
|
|
ok = true
|
|
} else if col.XY != nil {
|
|
hs := col.XY.ToHS()
|
|
col2 = Color{HS: &hs}
|
|
col2.K = &k
|
|
ok = true
|
|
} else if col.K != nil {
|
|
k = *col.K
|
|
col2.HS = &HueSat{Hue: 0, Sat: 0}
|
|
col2.K = &k
|
|
ok = true
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// ToXY tries to copy the color to an XY color.
|
|
func (col *Color) ToXY() (col2 Color, ok bool) {
|
|
if col.XY != nil {
|
|
xy := *col.XY
|
|
col2 = Color{XY: &xy}
|
|
ok = true
|
|
} else if col.HS != nil {
|
|
xy := col.HS.ToXY()
|
|
col2 = Color{XY: &xy}
|
|
ok = true
|
|
} else if col.RGB != nil {
|
|
xy := col.RGB.ToXY()
|
|
col2 = Color{XY: &xy}
|
|
ok = true
|
|
} else if col.K != nil {
|
|
xy := kToRGB(*col.K).ToXY()
|
|
col2 = Color{XY: &xy}
|
|
ok = true
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (col *Color) Interpolate(other Color, fac float64) Color {
|
|
if col.AlmostEquals(other) {
|
|
log.Println("ALMOST EQUAL", col.String(), other.String())
|
|
return *col
|
|
}
|
|
|
|
// Special case for both kelvin values.
|
|
if col.IsKelvin() && other.IsKelvin() {
|
|
k1 := *col.K
|
|
k2 := *other.K
|
|
|
|
if k2 > k1 {
|
|
return Color{K: gentools.Ptr(k1 + int(float64(k2-k1)*fac))}
|
|
} else {
|
|
return Color{K: gentools.Ptr(k1 - int(float64(k1-k2)*fac))}
|
|
}
|
|
}
|
|
|
|
if fac < 0.000001 {
|
|
return *col
|
|
} else if fac > 0.999999 {
|
|
return other
|
|
}
|
|
|
|
// Get the colorful values.
|
|
cvCF := col.colorful()
|
|
otherCF := other.colorful()
|
|
|
|
// Blend and normalize (clamping is hax to avoid issues with some colors)
|
|
blended := cvCF.BlendLuv(otherCF, fac)
|
|
blendedHue, blendedSat, _ := blended.Hsv()
|
|
blendedHs := HueSat{Hue: blendedHue, Sat: blendedSat}
|
|
|
|
// Convert to the first's type
|
|
switch col.Kind() {
|
|
case "rgb":
|
|
rgb := blendedHs.ToRGB()
|
|
return Color{RGB: &rgb}
|
|
case "xy":
|
|
xy := blendedHs.ToXY()
|
|
return Color{XY: &xy}
|
|
default:
|
|
return Color{HS: &blendedHs}
|
|
}
|
|
}
|
|
|
|
func (col *Color) Kind() string {
|
|
switch {
|
|
case col.RGB != nil:
|
|
return "rgb"
|
|
case col.XY != nil:
|
|
return "xy"
|
|
case col.HS != nil && col.K != nil:
|
|
return "hsk"
|
|
case col.HS != nil:
|
|
return "hs"
|
|
case col.K != nil:
|
|
return "k"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func (col *Color) String() string {
|
|
switch {
|
|
case col.RGB != nil:
|
|
return fmt.Sprintf("rgb:%.3f,%.3f,%.3f", col.RGB.Red, col.RGB.Green, col.RGB.Blue)
|
|
case col.XY != nil:
|
|
return fmt.Sprintf("xy:%.4f,%.4f", col.XY.X, col.XY.Y)
|
|
case col.HS != nil && col.K != nil:
|
|
return fmt.Sprintf("hsk:%.2f,%.3f,%d", col.HS.Hue, col.HS.Sat, *col.K)
|
|
case col.HS != nil:
|
|
return fmt.Sprintf("hs:%.2f,%.3f", col.HS.Hue, col.HS.Sat)
|
|
case col.K != nil:
|
|
return fmt.Sprintf("k:%d", *col.K)
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func (col *Color) colorful() colorful.Color {
|
|
switch {
|
|
case col.K != nil:
|
|
col2, _ := col.ToXY()
|
|
return col2.colorful()
|
|
case col.HS != nil:
|
|
return colorful.Hsv(col.HS.Hue, col.HS.Sat, 1)
|
|
case col.RGB != nil:
|
|
return colorful.Color{R: col.RGB.Red, G: col.RGB.Green, B: col.RGB.Blue}
|
|
case col.XY != nil:
|
|
return colorful.Xyy(col.XY.X, col.XY.Y, 0.5)
|
|
default:
|
|
return colorful.Color{R: 1, B: 1, G: 1}
|
|
}
|
|
}
|
|
|
|
func MustParse(raw string) Color {
|
|
col, err := Parse(raw)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return col
|
|
}
|
|
|
|
func Parse(raw string) (col Color, err error) {
|
|
if raw == "" {
|
|
return
|
|
}
|
|
|
|
convertTokens := strings.SplitN(raw, "|", 2)
|
|
|
|
tokens := strings.SplitN(convertTokens[0], ":", 2)
|
|
if len(tokens) != 2 {
|
|
err = ErrBadColorInput
|
|
return
|
|
}
|
|
|
|
switch tokens[0] {
|
|
case "kelvin", "k":
|
|
{
|
|
parsedPart, err := strconv.Atoi(tokens[1])
|
|
if err != nil {
|
|
err = ErrBadColorInput
|
|
break
|
|
}
|
|
|
|
col.K = &parsedPart
|
|
}
|
|
|
|
case "xy":
|
|
{
|
|
parts := strings.Split(tokens[1], ",")
|
|
if len(parts) < 2 {
|
|
err = ErrUnknownColorFormat
|
|
return
|
|
}
|
|
|
|
x, err1 := strconv.ParseFloat(parts[0], 64)
|
|
y, err2 := strconv.ParseFloat(parts[1], 64)
|
|
if err1 != nil || err2 != nil {
|
|
err = ErrBadColorInput
|
|
break
|
|
}
|
|
|
|
col.XY = &XY{x, y}
|
|
}
|
|
|
|
case "hs":
|
|
{
|
|
parts := strings.Split(tokens[1], ",")
|
|
if len(parts) < 2 {
|
|
err = ErrUnknownColorFormat
|
|
return
|
|
}
|
|
|
|
part1, err1 := strconv.ParseFloat(parts[0], 64)
|
|
part2, err2 := strconv.ParseFloat(parts[1], 64)
|
|
if err1 != nil || err2 != nil {
|
|
err = ErrBadColorInput
|
|
break
|
|
}
|
|
|
|
col.HS = &HueSat{Hue: part1, Sat: part2}
|
|
}
|
|
|
|
case "hsk":
|
|
{
|
|
parts := strings.Split(tokens[1], ",")
|
|
if len(parts) < 3 {
|
|
err = ErrUnknownColorFormat
|
|
return
|
|
}
|
|
|
|
part1, err1 := strconv.ParseFloat(parts[0], 64)
|
|
part2, err2 := strconv.ParseFloat(parts[1], 64)
|
|
part3, err3 := strconv.Atoi(parts[2])
|
|
if err1 != nil || err2 != nil || err3 != nil {
|
|
err = ErrBadColorInput
|
|
break
|
|
}
|
|
|
|
col.HS = &HueSat{Hue: part1, Sat: part2}
|
|
col.K = &part3
|
|
}
|
|
|
|
case "rgb":
|
|
{
|
|
if strings.HasPrefix(tokens[1], "#") {
|
|
hex := tokens[1][1:]
|
|
if !validHex(hex) {
|
|
err = ErrBadColorInput
|
|
break
|
|
}
|
|
|
|
if len(hex) == 6 {
|
|
col.RGB = &RGB{
|
|
Red: float64(hex2num(hex[0:2])) / 255.0,
|
|
Green: float64(hex2num(hex[2:4])) / 255.0,
|
|
Blue: float64(hex2num(hex[4:6])) / 255.0,
|
|
}
|
|
} else if len(hex) == 3 {
|
|
col.RGB = &RGB{
|
|
Red: float64(hex2digit(hex[0])) / 15.0,
|
|
Green: float64(hex2digit(hex[1])) / 15.0,
|
|
Blue: float64(hex2digit(hex[2])) / 15.0,
|
|
}
|
|
} else {
|
|
err = ErrUnknownColorFormat
|
|
return
|
|
}
|
|
} else {
|
|
parts := strings.Split(tokens[1], ",")
|
|
if len(parts) < 3 {
|
|
err = ErrUnknownColorFormat
|
|
return
|
|
}
|
|
|
|
part1, err1 := strconv.ParseFloat(parts[0], 64)
|
|
part2, err2 := strconv.ParseFloat(parts[1], 64)
|
|
part3, err3 := strconv.ParseFloat(parts[2], 64)
|
|
if err1 != nil || err2 != nil || err3 != nil {
|
|
err = ErrBadColorInput
|
|
break
|
|
}
|
|
|
|
col.RGB = &RGB{Red: part1, Green: part2, Blue: part3}
|
|
}
|
|
|
|
normalizedRGB := col.RGB.ToHS().ToRGB()
|
|
col.RGB = &normalizedRGB
|
|
}
|
|
|
|
default:
|
|
err = ErrUnknownColorFormat
|
|
}
|
|
|
|
if err == nil && len(convertTokens) == 2 {
|
|
switch convertTokens[1] {
|
|
case "xy":
|
|
col2, ok := col.ToXY()
|
|
if !ok {
|
|
err = ErrUnknownColorFormat
|
|
} else {
|
|
col = col2
|
|
}
|
|
case "rgb":
|
|
col2, ok := col.ToRGB()
|
|
if !ok {
|
|
err = ErrUnknownColorFormat
|
|
} else {
|
|
col = col2
|
|
}
|
|
case "hs":
|
|
col2, ok := col.ToHS()
|
|
if !ok {
|
|
err = ErrUnknownColorFormat
|
|
} else {
|
|
col = col2
|
|
}
|
|
default:
|
|
err = ErrUnknownColorFormat
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func validHex(h string) bool {
|
|
for _, ch := range h {
|
|
if !((ch >= 'a' && ch <= 'f') || (ch >= '0' || ch <= '9')) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func hex2num(s string) int {
|
|
v := 0
|
|
for _, h := range s {
|
|
v *= 16
|
|
v += hex2digit(byte(h))
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func hex2digit(h byte) int {
|
|
if h >= 'a' && h <= 'f' {
|
|
return 10 + int(h-'a')
|
|
} else {
|
|
return int(h - '0')
|
|
}
|
|
}
|
|
|
|
func kToRGB(kelvin int) RGB {
|
|
if kelvin < 1000 {
|
|
kelvin = 1000
|
|
} else if kelvin > 12000 {
|
|
kelvin = 12000
|
|
}
|
|
if kelvin%100 == 0 {
|
|
return kelvinRGBTable[kelvin]
|
|
}
|
|
|
|
fac := float64(kelvin%100) / 100
|
|
floor := (kelvin / 100) * 100
|
|
ceil := floor + 100
|
|
floorRGB := kelvinRGBTable[floor]
|
|
ceilRGB := kelvinRGBTable[ceil]
|
|
|
|
return RGB{
|
|
Red: (floorRGB.Red * fac) + (ceilRGB.Red * (1 - fac)),
|
|
Green: (floorRGB.Green * fac) + (ceilRGB.Green * (1 - fac)),
|
|
Blue: (floorRGB.Blue * fac) + (ceilRGB.Blue * (1 - fac)),
|
|
}
|
|
}
|
|
|
|
var kelvinRGBTable = map[int]RGB{
|
|
1000: {Red: 1.000, Green: 0.220, Blue: 0.000},
|
|
1100: {Red: 1.000, Green: 0.278, Blue: 0.000},
|
|
1200: {Red: 1.000, Green: 0.325, Blue: 0.000},
|
|
1300: {Red: 1.000, Green: 0.365, Blue: 0.000},
|
|
1400: {Red: 1.000, Green: 0.396, Blue: 0.000},
|
|
1500: {Red: 1.000, Green: 0.427, Blue: 0.000},
|
|
1600: {Red: 1.000, Green: 0.451, Blue: 0.000},
|
|
1700: {Red: 1.000, Green: 0.475, Blue: 0.000},
|
|
1800: {Red: 1.000, Green: 0.494, Blue: 0.000},
|
|
1900: {Red: 1.000, Green: 0.514, Blue: 0.000},
|
|
2000: {Red: 1.000, Green: 0.541, Blue: 0.071},
|
|
2100: {Red: 1.000, Green: 0.557, Blue: 0.129},
|
|
2200: {Red: 1.000, Green: 0.576, Blue: 0.173},
|
|
2300: {Red: 1.000, Green: 0.596, Blue: 0.212},
|
|
2400: {Red: 1.000, Green: 0.616, Blue: 0.247},
|
|
2500: {Red: 1.000, Green: 0.631, Blue: 0.282},
|
|
2600: {Red: 1.000, Green: 0.647, Blue: 0.310},
|
|
2700: {Red: 1.000, Green: 0.663, Blue: 0.341},
|
|
2800: {Red: 1.000, Green: 0.678, Blue: 0.369},
|
|
2900: {Red: 1.000, Green: 0.694, Blue: 0.396},
|
|
3000: {Red: 1.000, Green: 0.706, Blue: 0.420},
|
|
3100: {Red: 1.000, Green: 0.722, Blue: 0.447},
|
|
3200: {Red: 1.000, Green: 0.733, Blue: 0.471},
|
|
3300: {Red: 1.000, Green: 0.745, Blue: 0.494},
|
|
3400: {Red: 1.000, Green: 0.757, Blue: 0.518},
|
|
3500: {Red: 1.000, Green: 0.769, Blue: 0.537},
|
|
3600: {Red: 1.000, Green: 0.780, Blue: 0.561},
|
|
3700: {Red: 1.000, Green: 0.788, Blue: 0.580},
|
|
3800: {Red: 1.000, Green: 0.800, Blue: 0.600},
|
|
3900: {Red: 1.000, Green: 0.808, Blue: 0.624},
|
|
4000: {Red: 1.000, Green: 0.820, Blue: 0.639},
|
|
4100: {Red: 1.000, Green: 0.827, Blue: 0.659},
|
|
4200: {Red: 1.000, Green: 0.835, Blue: 0.678},
|
|
4300: {Red: 1.000, Green: 0.843, Blue: 0.694},
|
|
4400: {Red: 1.000, Green: 0.851, Blue: 0.714},
|
|
4500: {Red: 1.000, Green: 0.859, Blue: 0.729},
|
|
4600: {Red: 1.000, Green: 0.867, Blue: 0.745},
|
|
4700: {Red: 1.000, Green: 0.875, Blue: 0.761},
|
|
4800: {Red: 1.000, Green: 0.882, Blue: 0.776},
|
|
4900: {Red: 1.000, Green: 0.890, Blue: 0.792},
|
|
5000: {Red: 1.000, Green: 0.894, Blue: 0.808},
|
|
5100: {Red: 1.000, Green: 0.902, Blue: 0.824},
|
|
5200: {Red: 1.000, Green: 0.910, Blue: 0.835},
|
|
5300: {Red: 1.000, Green: 0.914, Blue: 0.851},
|
|
5400: {Red: 1.000, Green: 0.922, Blue: 0.863},
|
|
5500: {Red: 1.000, Green: 0.925, Blue: 0.878},
|
|
5600: {Red: 1.000, Green: 0.933, Blue: 0.890},
|
|
5700: {Red: 1.000, Green: 0.937, Blue: 0.902},
|
|
5800: {Red: 1.000, Green: 0.941, Blue: 0.914},
|
|
5900: {Red: 1.000, Green: 0.949, Blue: 0.925},
|
|
6000: {Red: 1.000, Green: 0.953, Blue: 0.937},
|
|
6100: {Red: 1.000, Green: 0.957, Blue: 0.949},
|
|
6200: {Red: 1.000, Green: 0.961, Blue: 0.961},
|
|
6300: {Red: 1.000, Green: 0.965, Blue: 0.969},
|
|
6400: {Red: 1.000, Green: 0.973, Blue: 0.984},
|
|
6500: {Red: 1.000, Green: 0.976, Blue: 0.992},
|
|
6600: {Red: 0.996, Green: 0.976, Blue: 1.000},
|
|
6700: {Red: 0.988, Green: 0.969, Blue: 1.000},
|
|
6800: {Red: 0.976, Green: 0.965, Blue: 1.000},
|
|
6900: {Red: 0.969, Green: 0.961, Blue: 1.000},
|
|
7000: {Red: 0.961, Green: 0.953, Blue: 1.000},
|
|
7100: {Red: 0.953, Green: 0.949, Blue: 1.000},
|
|
7200: {Red: 0.941, Green: 0.945, Blue: 1.000},
|
|
7300: {Red: 0.937, Green: 0.941, Blue: 1.000},
|
|
7400: {Red: 0.929, Green: 0.937, Blue: 1.000},
|
|
7500: {Red: 0.922, Green: 0.933, Blue: 1.000},
|
|
7600: {Red: 0.914, Green: 0.929, Blue: 1.000},
|
|
7700: {Red: 0.906, Green: 0.925, Blue: 1.000},
|
|
7800: {Red: 0.902, Green: 0.922, Blue: 1.000},
|
|
7900: {Red: 0.894, Green: 0.918, Blue: 1.000},
|
|
8000: {Red: 0.890, Green: 0.914, Blue: 1.000},
|
|
8100: {Red: 0.882, Green: 0.910, Blue: 1.000},
|
|
8200: {Red: 0.878, Green: 0.906, Blue: 1.000},
|
|
8300: {Red: 0.871, Green: 0.902, Blue: 1.000},
|
|
8400: {Red: 0.867, Green: 0.902, Blue: 1.000},
|
|
8500: {Red: 0.863, Green: 0.898, Blue: 1.000},
|
|
8600: {Red: 0.855, Green: 0.898, Blue: 1.000},
|
|
8700: {Red: 0.851, Green: 0.890, Blue: 1.000},
|
|
8800: {Red: 0.847, Green: 0.890, Blue: 1.000},
|
|
8900: {Red: 0.843, Green: 0.886, Blue: 1.000},
|
|
9000: {Red: 0.839, Green: 0.882, Blue: 1.000},
|
|
9100: {Red: 0.831, Green: 0.882, Blue: 1.000},
|
|
9200: {Red: 0.827, Green: 0.878, Blue: 1.000},
|
|
9300: {Red: 0.824, Green: 0.875, Blue: 1.000},
|
|
9400: {Red: 0.820, Green: 0.875, Blue: 1.000},
|
|
9500: {Red: 0.816, Green: 0.871, Blue: 1.000},
|
|
9600: {Red: 0.812, Green: 0.867, Blue: 1.000},
|
|
9700: {Red: 0.812, Green: 0.867, Blue: 1.000},
|
|
9800: {Red: 0.808, Green: 0.863, Blue: 1.000},
|
|
9900: {Red: 0.804, Green: 0.863, Blue: 1.000},
|
|
10000: {Red: 0.812, Green: 0.855, Blue: 1.000},
|
|
10100: {Red: 0.812, Green: 0.855, Blue: 1.000},
|
|
10200: {Red: 0.808, Green: 0.851, Blue: 1.000},
|
|
10300: {Red: 0.804, Green: 0.851, Blue: 1.000},
|
|
10400: {Red: 0.800, Green: 0.847, Blue: 1.000},
|
|
10500: {Red: 0.800, Green: 0.847, Blue: 1.000},
|
|
10600: {Red: 0.796, Green: 0.843, Blue: 1.000},
|
|
10700: {Red: 0.792, Green: 0.843, Blue: 1.000},
|
|
10800: {Red: 0.792, Green: 0.839, Blue: 1.000},
|
|
10900: {Red: 0.788, Green: 0.839, Blue: 1.000},
|
|
11000: {Red: 0.784, Green: 0.835, Blue: 1.000},
|
|
11100: {Red: 0.784, Green: 0.835, Blue: 1.000},
|
|
11200: {Red: 0.780, Green: 0.831, Blue: 1.000},
|
|
11300: {Red: 0.776, Green: 0.831, Blue: 1.000},
|
|
11400: {Red: 0.776, Green: 0.831, Blue: 1.000},
|
|
11500: {Red: 0.773, Green: 0.827, Blue: 1.000},
|
|
11600: {Red: 0.773, Green: 0.827, Blue: 1.000},
|
|
11700: {Red: 0.773, Green: 0.824, Blue: 1.000},
|
|
11800: {Red: 0.769, Green: 0.824, Blue: 1.000},
|
|
11900: {Red: 0.765, Green: 0.824, Blue: 1.000},
|
|
12000: {Red: 0.765, Green: 0.820, Blue: 1.000},
|
|
}
|