summaryrefslogtreecommitdiffstats
path: root/resources/images/color.go
diff options
context:
space:
mode:
Diffstat (limited to 'resources/images/color.go')
-rw-r--r--resources/images/color.go120
1 files changed, 116 insertions, 4 deletions
diff --git a/resources/images/color.go b/resources/images/color.go
index 71872a30e..e2ff2377f 100644
--- a/resources/images/color.go
+++ b/resources/images/color.go
@@ -16,10 +16,76 @@ package images
import (
"encoding/hex"
"fmt"
+ "hash/fnv"
"image/color"
+ "math"
"strings"
+
+ "github.com/gohugoio/hugo/common/hstrings"
)
+type colorGoProvider interface {
+ ColorGo() color.Color
+}
+
+type Color struct {
+ // The color.
+ color color.Color
+
+ // The color prefixed with a #.
+ hex string
+
+ // The relative luminance of the color.
+ luminance float64
+}
+
+// Luminance as defined by w3.org.
+// See https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
+func (c Color) Luminance() float64 {
+ return c.luminance
+}
+
+// ColorGo returns the color as a color.Color.
+// For internal use only.
+func (c Color) ColorGo() color.Color {
+ return c.color
+}
+
+// ColorHex returns the color as a hex string prefixed with a #.
+func (c Color) ColorHex() string {
+ return c.hex
+}
+
+// String returns the color as a hex string prefixed with a #.
+func (c Color) String() string {
+ return c.hex
+}
+
+// For hashstructure. This struct is used in template func options
+// that needs to be able to hash a Color.
+// For internal use only.
+func (c Color) Hash() (uint64, error) {
+ h := fnv.New64a()
+ h.Write([]byte(c.hex))
+ return h.Sum64(), nil
+}
+
+func (c *Color) init() error {
+ c.hex = ColorGoToHexString(c.color)
+ r, g, b, _ := c.color.RGBA()
+ c.luminance = 0.2126*c.toSRGB(uint8(r)) + 0.7152*c.toSRGB(uint8(g)) + 0.0722*c.toSRGB(uint8(b))
+ return nil
+}
+
+func (c Color) toSRGB(i uint8) float64 {
+ v := float64(i) / 255
+ if v <= 0.04045 {
+ return v / 12.92
+ } else {
+ return math.Pow((v+0.055)/1.055, 2.4)
+ }
+}
+
// AddColorToPalette adds c as the first color in p if not already there.
// Note that it does no additional checks, so callers must make sure
// that the palette is valid for the relevant format.
@@ -45,14 +111,60 @@ func ReplaceColorInPalette(c color.Color, p color.Palette) {
p[p.Index(c)] = c
}
-// ColorToHexString converts a color to a hex string.
-func ColorToHexString(c color.Color) string {
+// ColorGoToHexString converts a color.Color to a hex string.
+func ColorGoToHexString(c color.Color) string {
r, g, b, a := c.RGBA()
rgba := color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
- return fmt.Sprintf("#%.2x%.2x%.2x", rgba.R, rgba.G, rgba.B)
+ if rgba.A == 0xff {
+ return fmt.Sprintf("#%.2x%.2x%.2x", rgba.R, rgba.G, rgba.B)
+ }
+ return fmt.Sprintf("#%.2x%.2x%.2x%.2x", rgba.R, rgba.G, rgba.B, rgba.A)
+}
+
+// ColorGoToColor converts a color.Color to a Color.
+func ColorGoToColor(c color.Color) Color {
+ cc := Color{color: c}
+ if err := cc.init(); err != nil {
+ panic(err)
+ }
+ return cc
+}
+
+func hexStringToColor(s string) Color {
+ c, err := hexStringToColorGo(s)
+ if err != nil {
+ panic(err)
+ }
+ return ColorGoToColor(c)
+}
+
+// HexStringsToColors converts a slice of hex strings to a slice of Colors.
+func HexStringsToColors(s ...string) []Color {
+ var colors []Color
+ for _, v := range s {
+ colors = append(colors, hexStringToColor(v))
+ }
+ return colors
+}
+
+func toColorGo(v any) (color.Color, bool, error) {
+ switch vv := v.(type) {
+ case colorGoProvider:
+ return vv.ColorGo(), true, nil
+ default:
+ s, ok := hstrings.ToString(v)
+ if !ok {
+ return nil, false, nil
+ }
+ c, err := hexStringToColorGo(s)
+ if err != nil {
+ return nil, false, err
+ }
+ return c, true, nil
+ }
}
-func hexStringToColor(s string) (color.Color, error) {
+func hexStringToColorGo(s string) (color.Color, error) {
s = strings.TrimPrefix(s, "#")
if len(s) != 3 && len(s) != 4 && len(s) != 6 && len(s) != 8 {