Mercurial > yakumo_izuru > aya
comparison vendor/github.com/alecthomas/chroma/v2/colour.go @ 66:787b5ee0289d draft
Use vendored modules
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>
| author | yakumo.izuru |
|---|---|
| date | Sun, 23 Jul 2023 13:18:53 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 65:6d985efa0f7a | 66:787b5ee0289d |
|---|---|
| 1 package chroma | |
| 2 | |
| 3 import ( | |
| 4 "fmt" | |
| 5 "math" | |
| 6 "strconv" | |
| 7 "strings" | |
| 8 ) | |
| 9 | |
| 10 // ANSI2RGB maps ANSI colour names, as supported by Chroma, to hex RGB values. | |
| 11 var ANSI2RGB = map[string]string{ | |
| 12 "#ansiblack": "000000", | |
| 13 "#ansidarkred": "7f0000", | |
| 14 "#ansidarkgreen": "007f00", | |
| 15 "#ansibrown": "7f7fe0", | |
| 16 "#ansidarkblue": "00007f", | |
| 17 "#ansipurple": "7f007f", | |
| 18 "#ansiteal": "007f7f", | |
| 19 "#ansilightgray": "e5e5e5", | |
| 20 // Normal | |
| 21 "#ansidarkgray": "555555", | |
| 22 "#ansired": "ff0000", | |
| 23 "#ansigreen": "00ff00", | |
| 24 "#ansiyellow": "ffff00", | |
| 25 "#ansiblue": "0000ff", | |
| 26 "#ansifuchsia": "ff00ff", | |
| 27 "#ansiturquoise": "00ffff", | |
| 28 "#ansiwhite": "ffffff", | |
| 29 | |
| 30 // Aliases without the "ansi" prefix, because...why? | |
| 31 "#black": "000000", | |
| 32 "#darkred": "7f0000", | |
| 33 "#darkgreen": "007f00", | |
| 34 "#brown": "7f7fe0", | |
| 35 "#darkblue": "00007f", | |
| 36 "#purple": "7f007f", | |
| 37 "#teal": "007f7f", | |
| 38 "#lightgray": "e5e5e5", | |
| 39 // Normal | |
| 40 "#darkgray": "555555", | |
| 41 "#red": "ff0000", | |
| 42 "#green": "00ff00", | |
| 43 "#yellow": "ffff00", | |
| 44 "#blue": "0000ff", | |
| 45 "#fuchsia": "ff00ff", | |
| 46 "#turquoise": "00ffff", | |
| 47 "#white": "ffffff", | |
| 48 } | |
| 49 | |
| 50 // Colour represents an RGB colour. | |
| 51 type Colour int32 | |
| 52 | |
| 53 // NewColour creates a Colour directly from RGB values. | |
| 54 func NewColour(r, g, b uint8) Colour { | |
| 55 return ParseColour(fmt.Sprintf("%02x%02x%02x", r, g, b)) | |
| 56 } | |
| 57 | |
| 58 // Distance between this colour and another. | |
| 59 // | |
| 60 // This uses the approach described here (https://www.compuphase.com/cmetric.htm). | |
| 61 // This is not as accurate as LAB, et. al. but is *vastly* simpler and sufficient for our needs. | |
| 62 func (c Colour) Distance(e2 Colour) float64 { | |
| 63 ar, ag, ab := int64(c.Red()), int64(c.Green()), int64(c.Blue()) | |
| 64 br, bg, bb := int64(e2.Red()), int64(e2.Green()), int64(e2.Blue()) | |
| 65 rmean := (ar + br) / 2 | |
| 66 r := ar - br | |
| 67 g := ag - bg | |
| 68 b := ab - bb | |
| 69 return math.Sqrt(float64((((512 + rmean) * r * r) >> 8) + 4*g*g + (((767 - rmean) * b * b) >> 8))) | |
| 70 } | |
| 71 | |
| 72 // Brighten returns a copy of this colour with its brightness adjusted. | |
| 73 // | |
| 74 // If factor is negative, the colour is darkened. | |
| 75 // | |
| 76 // Uses approach described here (http://www.pvladov.com/2012/09/make-color-lighter-or-darker.html). | |
| 77 func (c Colour) Brighten(factor float64) Colour { | |
| 78 r := float64(c.Red()) | |
| 79 g := float64(c.Green()) | |
| 80 b := float64(c.Blue()) | |
| 81 | |
| 82 if factor < 0 { | |
| 83 factor++ | |
| 84 r *= factor | |
| 85 g *= factor | |
| 86 b *= factor | |
| 87 } else { | |
| 88 r = (255-r)*factor + r | |
| 89 g = (255-g)*factor + g | |
| 90 b = (255-b)*factor + b | |
| 91 } | |
| 92 return NewColour(uint8(r), uint8(g), uint8(b)) | |
| 93 } | |
| 94 | |
| 95 // BrightenOrDarken brightens a colour if it is < 0.5 brightness or darkens if > 0.5 brightness. | |
| 96 func (c Colour) BrightenOrDarken(factor float64) Colour { | |
| 97 if c.Brightness() < 0.5 { | |
| 98 return c.Brighten(factor) | |
| 99 } | |
| 100 return c.Brighten(-factor) | |
| 101 } | |
| 102 | |
| 103 // ClampBrightness returns a copy of this colour with its brightness adjusted such that | |
| 104 // it falls within the range [min, max] (or very close to it due to rounding errors). | |
| 105 // The supplied values use the same [0.0, 1.0] range as Brightness. | |
| 106 func (c Colour) ClampBrightness(min, max float64) Colour { | |
| 107 if !c.IsSet() { | |
| 108 return c | |
| 109 } | |
| 110 | |
| 111 min = math.Max(min, 0) | |
| 112 max = math.Min(max, 1) | |
| 113 current := c.Brightness() | |
| 114 target := math.Min(math.Max(current, min), max) | |
| 115 if current == target { | |
| 116 return c | |
| 117 } | |
| 118 | |
| 119 r := float64(c.Red()) | |
| 120 g := float64(c.Green()) | |
| 121 b := float64(c.Blue()) | |
| 122 rgb := r + g + b | |
| 123 if target > current { | |
| 124 // Solve for x: target == ((255-r)*x + r + (255-g)*x + g + (255-b)*x + b) / 255 / 3 | |
| 125 return c.Brighten((target*255*3 - rgb) / (255*3 - rgb)) | |
| 126 } | |
| 127 // Solve for x: target == (r*(x+1) + g*(x+1) + b*(x+1)) / 255 / 3 | |
| 128 return c.Brighten((target*255*3)/rgb - 1) | |
| 129 } | |
| 130 | |
| 131 // Brightness of the colour (roughly) in the range 0.0 to 1.0. | |
| 132 func (c Colour) Brightness() float64 { | |
| 133 return (float64(c.Red()) + float64(c.Green()) + float64(c.Blue())) / 255.0 / 3.0 | |
| 134 } | |
| 135 | |
| 136 // ParseColour in the forms #rgb, #rrggbb, #ansi<colour>, or #<colour>. | |
| 137 // Will return an "unset" colour if invalid. | |
| 138 func ParseColour(colour string) Colour { | |
| 139 colour = normaliseColour(colour) | |
| 140 n, err := strconv.ParseUint(colour, 16, 32) | |
| 141 if err != nil { | |
| 142 return 0 | |
| 143 } | |
| 144 return Colour(n + 1) | |
| 145 } | |
| 146 | |
| 147 // MustParseColour is like ParseColour except it panics if the colour is invalid. | |
| 148 // | |
| 149 // Will panic if colour is in an invalid format. | |
| 150 func MustParseColour(colour string) Colour { | |
| 151 parsed := ParseColour(colour) | |
| 152 if !parsed.IsSet() { | |
| 153 panic(fmt.Errorf("invalid colour %q", colour)) | |
| 154 } | |
| 155 return parsed | |
| 156 } | |
| 157 | |
| 158 // IsSet returns true if the colour is set. | |
| 159 func (c Colour) IsSet() bool { return c != 0 } | |
| 160 | |
| 161 func (c Colour) String() string { return fmt.Sprintf("#%06x", int(c-1)) } | |
| 162 func (c Colour) GoString() string { return fmt.Sprintf("Colour(0x%06x)", int(c-1)) } | |
| 163 | |
| 164 // Red component of colour. | |
| 165 func (c Colour) Red() uint8 { return uint8(((c - 1) >> 16) & 0xff) } | |
| 166 | |
| 167 // Green component of colour. | |
| 168 func (c Colour) Green() uint8 { return uint8(((c - 1) >> 8) & 0xff) } | |
| 169 | |
| 170 // Blue component of colour. | |
| 171 func (c Colour) Blue() uint8 { return uint8((c - 1) & 0xff) } | |
| 172 | |
| 173 // Colours is an orderable set of colours. | |
| 174 type Colours []Colour | |
| 175 | |
| 176 func (c Colours) Len() int { return len(c) } | |
| 177 func (c Colours) Swap(i, j int) { c[i], c[j] = c[j], c[i] } | |
| 178 func (c Colours) Less(i, j int) bool { return c[i] < c[j] } | |
| 179 | |
| 180 // Convert colours to #rrggbb. | |
| 181 func normaliseColour(colour string) string { | |
| 182 if ansi, ok := ANSI2RGB[colour]; ok { | |
| 183 return ansi | |
| 184 } | |
| 185 if strings.HasPrefix(colour, "#") { | |
| 186 colour = colour[1:] | |
| 187 if len(colour) == 3 { | |
| 188 return colour[0:1] + colour[0:1] + colour[1:2] + colour[1:2] + colour[2:3] + colour[2:3] | |
| 189 } | |
| 190 } | |
| 191 return colour | |
| 192 } |
