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.
213 lines
4.8 KiB
213 lines
4.8 KiB
package judgment
|
|
|
|
// Some code below is taken directly from colorful's doc examples.
|
|
// https://github.com/lucasb-eyer/go-colorful/blob/master/doc/gradientgen/gradientgen.go
|
|
|
|
// May be useful later:
|
|
// c, err := colorful.Hex(s)
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/lucasb-eyer/go-colorful"
|
|
"image/color"
|
|
)
|
|
|
|
// CreateDefaultPalette returns a Palette of amountOfColors colors.
|
|
// 7 colors we use, red to green:
|
|
// "#df3222", "#ed6f01", "#fab001", "#c5d300", "#7bbd3e", "#00a249", "#017a36"
|
|
// When requiring more than 7, we interpolate in HSV space.
|
|
// This tries to be fault-tolerant, and returns an empty palette upon trouble.
|
|
func CreateDefaultPalette(amountOfColors int) color.Palette {
|
|
const Color0 = 0xdf3222
|
|
const Color1 = 0xed6f01
|
|
const Color2 = 0xfab001
|
|
const Color3 = 0xc5d300
|
|
const Color4 = 0x7bbd3e
|
|
const Color5 = 0x00a249
|
|
const Color6 = 0x017a36
|
|
|
|
color0 := hexToRGB(Color0)
|
|
color1 := hexToRGB(Color1)
|
|
color2 := hexToRGB(Color2)
|
|
color3 := hexToRGB(Color3)
|
|
color4 := hexToRGB(Color4)
|
|
color5 := hexToRGB(Color5)
|
|
color6 := hexToRGB(Color6)
|
|
|
|
if amountOfColors < 0 {
|
|
amountOfColors = amountOfColors * -1
|
|
}
|
|
|
|
switch amountOfColors {
|
|
case 0:
|
|
return []color.Color{}
|
|
case 1:
|
|
return []color.Color{
|
|
color5,
|
|
}
|
|
case 2:
|
|
return []color.Color{
|
|
color0,
|
|
color5,
|
|
}
|
|
case 3:
|
|
return []color.Color{
|
|
color0,
|
|
color2,
|
|
color5,
|
|
}
|
|
case 4:
|
|
return []color.Color{
|
|
color0,
|
|
color2,
|
|
color4,
|
|
color6,
|
|
}
|
|
case 5:
|
|
return []color.Color{
|
|
color0,
|
|
color1,
|
|
color2,
|
|
color4,
|
|
color5,
|
|
}
|
|
case 6:
|
|
return []color.Color{
|
|
color0,
|
|
color1,
|
|
color2,
|
|
color4,
|
|
color5,
|
|
color6,
|
|
}
|
|
case 7:
|
|
return []color.Color{
|
|
color0,
|
|
color1,
|
|
color2,
|
|
color3,
|
|
color4,
|
|
color5,
|
|
color6,
|
|
}
|
|
default:
|
|
palette, err := bakePalette(amountOfColors, []color.Color{
|
|
color0,
|
|
color1,
|
|
color2,
|
|
color3,
|
|
color4,
|
|
color5,
|
|
color6,
|
|
})
|
|
if err != nil {
|
|
//panic("CreateDefaultPalette: failed to bake: "+err.Error())
|
|
return []color.Color{}
|
|
}
|
|
return palette
|
|
}
|
|
}
|
|
|
|
// DumpPaletteHexString dumps the provided palette as a string
|
|
// Looks like: "#df3222", "#ed6f01", "#fab001", "#c5d300", "#7bbd3e", "#00a249", "#017a36"
|
|
func DumpPaletteHexString(palette color.Palette, separator string, quote string) string {
|
|
out := ""
|
|
|
|
for colorIndex, colorRgba := range palette {
|
|
if colorIndex > 0 {
|
|
out += separator
|
|
}
|
|
out += quote
|
|
out += DumpColorHexString(colorRgba, "#", false)
|
|
out += quote
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
// DumpColorHexString outputs strings like #ff3399 or #ff3399ff with alpha
|
|
// Be mindful that PRECISION IS LOST because hex format has less bits
|
|
func DumpColorHexString(c color.Color, prefix string, withAlpha bool) string {
|
|
out := prefix
|
|
r, g, b, a := c.RGBA()
|
|
out += fmt.Sprintf("%02x", r>>8)
|
|
out += fmt.Sprintf("%02x", g>>8)
|
|
out += fmt.Sprintf("%02x", b>>8)
|
|
if withAlpha {
|
|
out += fmt.Sprintf("%02x", a>>8)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// there probably is a colorful way to do this
|
|
func hexToRGB(hexColor int) color.Color {
|
|
rgba := color.RGBA{
|
|
R: uint8((hexColor & 0xff0000) >> 16),
|
|
G: uint8((hexColor & 0x00ff00) >> 8),
|
|
B: uint8((hexColor & 0x0000ff) >> 0),
|
|
A: 0xff,
|
|
}
|
|
c, success := colorful.MakeColor(rgba)
|
|
if !success {
|
|
panic("hexToRgb")
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
// This table contains the "key" colors of the color gradient we want to generate.
|
|
// The position of each key has to live in the range [0,1]
|
|
type keyColor struct {
|
|
Color colorful.Color
|
|
Position float64
|
|
}
|
|
type gradientTable []keyColor
|
|
|
|
// This is the meat of the gradient computation. It returns a HCL-blend between
|
|
// the two colors around `t`.
|
|
// Note: It relies heavily on the fact that the gradient keypoints are sorted.
|
|
func (gt gradientTable) getInterpolatedColorFor(t float64) colorful.Color {
|
|
for i := 0; i < len(gt)-1; i++ {
|
|
c1 := gt[i]
|
|
c2 := gt[i+1]
|
|
if c1.Position <= t && t <= c2.Position {
|
|
// We are in between c1 and c2. Go blend them!
|
|
t := (t - c1.Position) / (c2.Position - c1.Position)
|
|
return c1.Color.BlendHcl(c2.Color, t).Clamped()
|
|
}
|
|
}
|
|
|
|
// Nothing found? Means we're at (or past) the last gradient keypoint.
|
|
return gt[len(gt)-1].Color
|
|
}
|
|
|
|
func bakePalette(toLength int, keyColors color.Palette) (color.Palette, error) {
|
|
if toLength < 2 {
|
|
return nil, errors.New("bakePalette: the length of the palette must be > 1")
|
|
}
|
|
|
|
keyPoints := gradientTable{}
|
|
paletteLen := len(keyColors)
|
|
|
|
for colorIndex, colorObject := range keyColors {
|
|
colorfulColor, success := colorful.MakeColor(colorObject)
|
|
if !success {
|
|
panic("Bad palette color: alpha channel is probably 0.")
|
|
}
|
|
keyPoints = append(keyPoints, keyColor{
|
|
Color: colorfulColor,
|
|
Position: float64(colorIndex) / (float64(paletteLen) - 1.0),
|
|
})
|
|
}
|
|
|
|
outPalette := make([]color.Color, 0, 7)
|
|
|
|
for i := 0; i < toLength; i++ {
|
|
c := keyPoints.getInterpolatedColorFor(float64(i) / (float64(toLength) - 1))
|
|
outPalette = append(outPalette, c)
|
|
}
|
|
|
|
return outPalette, nil
|
|
}
|