diff --git a/baseelement.go b/baseelement.go index 2180fd0..f67c554 100644 --- a/baseelement.go +++ b/baseelement.go @@ -24,13 +24,25 @@ func renderText(w io.Writer, rules *ElementStyle, s string) { if rules != nil { if rules.Color != "" { - i, err := strconv.Atoi(rules.Color) + var i int + var err error + if rules.Color[0] == '#' { + i, err = hexToANSIColor(rules.Color) + } else { + i, err = strconv.Atoi(rules.Color) + } if err == nil && i >= 0 && i <= 255 { out = out.Index(uint8(i)) } } if rules.BackgroundColor != "" { - i, err := strconv.Atoi(rules.BackgroundColor) + var i int + var err error + if rules.BackgroundColor[0] == '#' { + i, err = hexToANSIColor(rules.BackgroundColor) + } else { + i, err = strconv.Atoi(rules.BackgroundColor) + } if err == nil && i >= 0 && i <= 255 { out = out.BgIndex(uint8(i)) } diff --git a/go.mod b/go.mod index c574dd0..2bc196d 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.13 require ( github.com/alecthomas/chroma v0.7.0 github.com/logrusorgru/aurora v0.0.0-20191017060258-dc85c304c434 + github.com/lucasb-eyer/go-colorful v1.0.3 github.com/mattn/go-isatty v0.0.10 github.com/mattn/go-runewidth v0.0.7 github.com/microcosm-cc/bluemonday v1.0.2 diff --git a/go.sum b/go.sum index 9a8364e..5936f7e 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/logrusorgru/aurora v0.0.0-20191017060258-dc85c304c434 h1:im9kkmH0WWwxzegiv18gSUJbuXR9y028rXrWuPp6Jug= github.com/logrusorgru/aurora v0.0.0-20191017060258-dc85c304c434/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= +github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= diff --git a/style.go b/style.go index 4fbbe6d..dd41a5f 100644 --- a/style.go +++ b/style.go @@ -2,6 +2,8 @@ package gold import ( "fmt" + + "github.com/lucasb-eyer/go-colorful" ) type StyleType int @@ -81,6 +83,56 @@ func cascadeStyle(parent *ElementStyle, child *ElementStyle) *ElementStyle { return &s } +func hexToANSIColor(h string) (int, error) { + c, err := colorful.Hex(h) + if err != nil { + return 0, err + } + + v2ci := func(v float64) int { + if v < 48 { + return 0 + } + if v < 115 { + return 1 + } + return int((v - 35) / 40) + } + + // Calculate the nearest 0-based color index at 16..231 + r := v2ci(c.R * 255.0) // 0..5 each + g := v2ci(c.G * 255.0) + b := v2ci(c.B * 255.0) + ci := 36*r + 6*g + b /* 0..215 */ + + // Calculate the represented colors back from the index + i2cv := [6]int{0, 0x5f, 0x87, 0xaf, 0xd7, 0xff} + cr := i2cv[r] // r/g/b, 0..255 each + cg := i2cv[g] + cb := i2cv[b] + + // Calculate the nearest 0-based gray index at 232..255 + var grayIdx int + average := (r + g + b) / 3 + if average > 238 { + grayIdx = 23 + } else { + grayIdx = (average - 3) / 10 // 0..23 + } + gv := 8 + 10*grayIdx // same value for r/g/b, 0..255 + + // Return the one which is nearer to the original input rgb value + c2 := colorful.Color{float64(cr) / 255.0, float64(cg) / 255.0, float64(cb) / 255.0} + g2 := colorful.Color{float64(gv) / 255.0, float64(gv) / 255.0, float64(gv) / 255.0} + colorDist := c.DistanceLab(c2) + grayDist := c.DistanceLab(g2) + + if colorDist <= grayDist { + return 16 + ci, nil + } + return 232 + grayIdx, nil +} + func keyToType(key string) (StyleType, error) { switch key { case "document":