package utils import ( "fmt" "math" ) const ( Pred float64 = 0.299 Pgreen float64 = 0.587 Pblue float64 = 0.114 ) var ( DarkAltFallback = []uint8{0x1c, 0x10, 0x10} LightAltFallback = []uint8{0xf2, 0xef, 0xef} ) func IntToRgb(color uint32) (uint8, uint8, uint8) { b := color % 256 g := color / 256 % 256 r := color / (256 * 256) % 256 return uint8(r), uint8(g), uint8(b) } func RgbToString(r, g, b uint8) string { return fmt.Sprintf("#%02x%02x%02x", r, g, b) } func AltColor(r, g, b uint8) (uint8, uint8, uint8) { l1 := Luminance(r, g, b) isDark := l1 <= 0.5098 brightnessAmount := -0.6 if isDark { // color is dark brightnessAmount = 0.85 } r2, g2, b2 := Brighten(r, g, b, brightnessAmount) l2 := Luminance(r2, g2, b2) ratio := WCAGRatio(l1, l2) // log.Printf("isDark=%v, ratio: %f, l1(%f)=%s, l2(%f)=%s", isDark, ratio, l1, RgbToString(r, g, b), l2, RgbToString(r2, g2, b2)) if ratio >= 3 { return r2, g2, b2 } if isDark { return LightAltFallback[0], LightAltFallback[1], LightAltFallback[2] } else { return DarkAltFallback[0], DarkAltFallback[1], DarkAltFallback[3] } } func Brighten(r, g, b uint8, amount float64) (uint8, uint8, uint8) { return multiply(r, amount), multiply(g, amount), multiply(b, amount) } func multiply(i uint8, amount float64) uint8 { iF := float64(i) return uint8( math.Max( 0, math.Min( 255, iF+255*amount, ), ), ) } func sRGB(c uint8) float64 { cf := float64(c) / 255 if cf <= 0.03928 { return cf / 12.92 } else { return math.Pow((cf+0.055)/1.055, 2.4) } } func Luminance(r, g, b uint8) float64 { rC := Pred * math.Pow(sRGB(r), 2) gC := Pgreen * math.Pow(sRGB(g), 2) bC := Pblue * math.Pow(sRGB(b), 2) return math.Sqrt(rC + gC + bC) } func WCAGRatio(l1, l2 float64) float64 { return (math.Max(l1, l2) + 0.05) / (math.Min(l1, l2) + 0.05) }