color

package module
v0.0.0-...-a57d0d1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 7, 2025 License: MIT Imports: 5 Imported by: 0

README

Color Package for go

color provides a common interface for dealing with colors in various environments.

For example, CSS understands colors as strings. Either as a name (e.g. red), a hexadecimal RGB string (e.g. #f00 or #ff0000) or via HSL components (e.g. hsl( 0deg 50% 90% )), but does not support HSV.

At the same time, graphviz also understands the same kinds of colors, but uses the formats #rgb, #rrggbb, #rrggbbaa (note: #rgba is not supported) and h,+s,+v for HSV colors, but HSL colors are not supported.

This package helps retain the original color specification, while also making it available to other environments, e.g. graphviz only understands X11 color names and RGB strings.

Goals

  • accept colors as either RGB, HSL or HSV (with optional opacity) as a well-defined set of ints
    • go's image/color uses uint32 and pre-multiplies all values by their alpha value?!
  • provide implicit conversion of colors to any other format
    • e.g. ask and ye shall receive:
      • c.RGB() will give you the RGB or RGBA representation of a color
      • c.HSL() will give you the HSL or HSLA representation of a color
      • c.Opaque() will give you the color without its opacity component
      • c.Translucent() will give you the color with its opacity component (default opaque)
  • provide the requested values as a well-defined set of ints
  • minimal space requirements to represent a color
    • RGB colors are represented by a 4-byte struct
    • HSL, HSV colors require 5 bytes (8 bytes aligned)
    • named colors obviously require more space for their name

Non-Goals

  • the conversion to/from various string formats is not provided, as this is entirely dependent on the environment in which the colors are used.
  • the representation and parsing of colors as strings
    • to do this, clients should embed color.Color in their own, environent specific structs (see below)

Use of colors in specific environments

To use color.Color for specific formats, create your own struct, embedding color.Color. e.g.

package graphviz

import (
    "fmt"
    "regexp"
    "strconv"
    "strings"
    "codeberg.org/japh/go-color"
    )

type Color struct {
  color.Color   // 1. embed color.Color in your own struct
}

// 2. provide the formatting required for your environment

var colorPatterns = []struct{
  format string
  ctype  color.Type
  match  *regexp.Regexp
  ints   *regexp.Regexp
  fn     func(int)int
}{
  {
    // "#rgb"
    format: "RGB",
    ctype:  color.RGBType,
    match:  regexp.MustCompile(`(?i)^#[0-9a-f]{3}$`),
    ints:   regexp.MustCompile(`(?i)[0-9a-f]{1}`),
    atoi:   func(a string) (int, error) {
      i, err := strconv.ParseInt( a, 16, 0 )
      if err != nil {
        return 0, err
      }
      return i<<4|i, nil
    },
  },
  {
    // "#rrggbb" or "#rrggbbaa"
    format: "RGB",
    ctype:  color.RGBType,
    match:  regexp.MustCompile(`(?i)^#[0-9a-f]{6,8}$`),
    ints:   regexp.MustCompile(`(?i)[0-9a-f]{2}`),
    atoi:   func(a string) (int, error) {
      i, err := strconv.ParseInt( a, 16, 0 )
      if err != nil {
        return 0, err
      }
      return i, nil
    },
  },
  {
    // "h,+s,v"
    format: "HSV",   
    ctype:  color.HSVType,
    match:  regexp.MustCompile(`(?i)^\d+,\+\d+,\+\d+$`),
    ints:   regexp.MustCompile(`\d+`),             
    atoi:   func(a string) (int, error) {
      i, err := strconv.Atoi( a )
      if err != nil {
        return 0, err
      }
      return i, nil
    },
  },
  {
    // "{name}" or "/{colorscheme}/{name}"
    format: "named",
    match:  regexp.MustCompile(`^(/\w*/)?\w+$`),         
  },
}

func ColorFromString(s string) (Color, error) {
  for _, p := range colorPatterns {
    if p.match.MatchString(s) {
      switch p.format {
        case "RGB", "HSV":
          ints := []int{}
          for _, a := range p.ints.FindStringAll(s)[1:] {
            i, err := p.atoi(a)
            if err != nil {
              return err
            }
            ints = append( ints, i )
          }
          return color.FromInts( p.ctype, ints )
        default: // name
          c := color.Schemes.ColorWithName(s)
      }
    }
  }
}

func (c Color)String() string {
  if c.HasName() {
    return c.Name()
  }
  ints := c.RGB().Ints()
  if len(ints) == 4 {
    return fmt.Sprintf("#%02d%02d%02d%02d", ints...)
  }
  return fmt.Sprintf("#%02d%02d%02d", ints...)
}

Progress

progress.svg

progress.dot

Background

  • technically, computer screens and graphics cards represent colors as tupels of 3, 8-bit values representing the red, green and blue components of a color.
  • opacity may optionally be provided to determine the mixing ratio of the color with its background, however, in this case the computed color, after mixing, will again be represented as just the three basic red, green and blue components.
  • HSL and HSV are poor cousins of RGB, and indeed are defined relative to the RGB color space (a cube of size 256 in all three dimensions)
  • HSL and HSV do not take human perception into account
    • saturation and lighness are confounded
    • hue and lightness are also confounded
  • it should be enough to store all colors as RGB and derive HSL/HSV as needed

Conversions

See colors_test.html for a quick overview of conversions between each of the available formats.

Note that HTML/CSS does not support HSV colors, so all HSV values appear white.

Implementation

The Color type is only an interface. Via the interface, a color may be converted to its various equivalent forms.

Internally, color uses separate structs to represent colors in each specific form, and provide the ability to convert between forms.

All colors are represented by a 4-integer tuple (including opacity), opaque colors simply set the opacity to "fully opaque" internally and only report their first three values.

References

Golang standard library:

  • image/color
    • is intended for the technical adjustment of colors e.g. for rendering images etc.
    • only implements conversions between RGB, CMYK and YCbCr
    • has little relation to color string representations

Converters (HSL->RGB etc, no names):

Color Manipulator (darken, adjusthue, ...)

Calculations / Background Info:

HSL 'v' HSV:

Color Names:

Documentation

Index

Constants

View Source
const HSLAOpaque = byte(100)
View Source
const HSVAOpaque = byte(100)
View Source
const RGBAOpaque = byte(255)

Variables

View Source
var (
	NotYetImplementedErr        = errors.New("not yet implemented")
	UnknownColorTypeErr         = errors.New("unknown color type")
	UnparsableColorStringErr    = errors.New("could not parse color string")
	NotEnoughIntsErr            = errors.New("not enough values")
	TooManyIntsErr              = errors.New("too many values")
	ColorComponentOutOfRangeErr = errors.New("color component out of range")
	UnnamedColorErr             = errors.New("unnamed color")
	UnknownColorNameErr         = errors.New("unknown color name")
	UnknownColorSchemeNameErr   = errors.New("unknown colorscheme name")
)
View Source
var HSLAIntLimits = intLimits{
	// contains filtered or unexported fields
}
View Source
var HSVAIntLimits = intLimits{
	// contains filtered or unexported fields
}
View Source
var RGBAIntLimits = intLimits{
	// contains filtered or unexported fields
}
View Source
var Schemes = &Collection{
	Schemes: []*Scheme{},
	Scheme:  map[string]*Scheme{},
}

Functions

This section is empty.

Types

type Collection

type Collection struct {
	Schemes []*Scheme
	Scheme  map[string]*Scheme
}

func (*Collection) Add

func (c *Collection) Add(s *Scheme, ids ...string)

func (*Collection) ColorWithName

func (c *Collection) ColorWithName(name string) (Color, error)

parse a color name of the form [/[scheme]/]name

- all comparisons are case-insensitive - if no scheme name is provided, all schemes will be scanned in order

func (*Collection) WithID

func (c *Collection) WithID(id string) (*Scheme, error)

type Color

type Color interface {
	HasName(string) bool // will mostly be false
	Name() string        // will mostly be ""
	Names() []string     // will mostly be []
	Type() Type          // type of color (RGB, HSL or HSV)
	Ints() []int         // type-dependent component values, guaranteed to be in the expected order and ranges (rgb[a] or hsl[a])
	Opaque() Color       // returns a color in it's original format, without opacity (i.e. 3 ints)
	Translucent() Color  // returns a color in it's original format, with opacity (i.e. 4 ints)
	RGB() Color          // returns an RGB/RGBA representation of the color
	HSL() Color          // returns an HSL/HSLA representation of the color
	HSV() Color          // returns an HSL/HSLA representation of the color
}

func DecodeHexRGB

func DecodeHexRGB(s string) (Color, error)

TODO: 2024-12-29 refactor this somehow

func HSLAFromInts

func HSLAFromInts(ints ...int) (Color, error)

HSLAFromInts returns a Color constructed from 3 or 4 HSL(A) components

The first value will be folded to the range [0,359] All other values must be between 0 and 100 (percent)

func HSLFromInts

func HSLFromInts(ints ...int) (Color, error)

HSLFromInts creates an HSL value from 3 ints in the order red, green, blue.

If a 4th int is provided, it is assumed to be an opacity value and an HSLA value will be returned instead.

All values must be in the range between 0 and 255 inclusively.

func HSVAFromInts

func HSVAFromInts(ints ...int) (Color, error)

HSVAFromInts returns a Color constructed from 3 or 4 HSV(A) components

The first value will be folded to the range [0,359] All other values must be between 0 and 100 (percent)

func HSVFromInts

func HSVFromInts(ints ...int) (Color, error)

HSVFromInts creates an HSV value from 3 ints in the order hue, saturation, value (brightness)

If a 4th int is provided, it is assumed to be an opacity value and a HSVA value will be returned instead.

All values must be in the range between 0 and 255 inclusively.

func RGBAFromInts

func RGBAFromInts(ints ...int) (Color, error)

RGBAFromInts creates an RGBA value from 4 ints in the order red, green, blue and alpha (opacity).

If only 3 values are provided, an RGB color will be returned instead.

All values must be in the range between 0 and 255 inclusively.

func RGBFromInts

func RGBFromInts(ints ...int) (Color, error)

RGBFromInts creates an RGB value from 3 ints in the order red, green, blue.

If a 4th int is provided, it is assumed to be an opacity value and an RGBA value will be returned instead.

All values must be in the range between 0 and 255 inclusively.

func WithName

func WithName(name string, c Color) Color

WithName creates a new color with the name provided

Note: colors can have multiple names!

type HSLAColor

type HSLAColor struct {
	H int16 // hue:        0 .. 360 degrees (too big for a byte)
	S byte  // saturation: 0 .. 100 (%)
	L byte  // lightness:  0 .. 100 (%)
	A byte  // opacity:    0 .. 100 (%)
}

HSLAColor represents a color specified by four integer values for hue (0 .. 359: 0: red, 120: green, 240: blue) saturation (0 .. 100: 0: no color 100: fully saturated) luminence (0 .. 100: 0: dark 100: light) and opacity (0 .. 100: 0: transparent 100: opaque)

func (HSLAColor) HSL

func (c HSLAColor) HSL() Color

func (HSLAColor) HSV

func (c HSLAColor) HSV() Color

func (HSLAColor) HasName

func (HSLAColor) HasName(string) bool

func (HSLAColor) Ints

func (c HSLAColor) Ints() []int

func (HSLAColor) Name

func (HSLAColor) Name() string

func (HSLAColor) Names

func (HSLAColor) Names() []string

func (HSLAColor) Opaque

func (c HSLAColor) Opaque() Color

func (HSLAColor) RGB

func (c HSLAColor) RGB() Color

func (HSLAColor) Translucent

func (c HSLAColor) Translucent() Color

func (HSLAColor) Type

func (HSLAColor) Type() Type

type HSLColor

type HSLColor struct {
	HSLAColor
}

HSLColor is just an HSLColor with foll opacity

func (HSLColor) HSL

func (c HSLColor) HSL() Color

func (HSLColor) HSV

func (c HSLColor) HSV() Color

HSL => HSV

func (HSLColor) Ints

func (c HSLColor) Ints() []int

func (HSLColor) Opaque

func (c HSLColor) Opaque() Color

func (HSLColor) RGB

func (c HSLColor) RGB() Color

HSL => RGB

func (HSLColor) Translucent

func (c HSLColor) Translucent() Color

type HSVAColor

type HSVAColor struct {
	H int16 // hue:        0 .. 360 degrees (too big for a byte)
	S byte  // saturation: 0 .. 100 (%)
	V byte  // lightness:  0 .. 100 (%)
	A byte  // opacity:    0 .. 100 (%)
}

HSVAColor represents a color specified by four integer values for hue (0 .. 359: 0: red, 120: green, 240: blue) saturation (0 .. 100: 0: no color 100: fully saturated) value (brighness) (0 .. 100: 0: dark 100: bright) and opacity (0 .. 100: 0: transparent 100: opaque)

func (HSVAColor) HSL

func (c HSVAColor) HSL() Color

func (HSVAColor) HSV

func (c HSVAColor) HSV() Color

func (HSVAColor) HasName

func (HSVAColor) HasName(string) bool

func (HSVAColor) Ints

func (c HSVAColor) Ints() []int

func (HSVAColor) Name

func (HSVAColor) Name() string

func (HSVAColor) Names

func (HSVAColor) Names() []string

func (HSVAColor) Opaque

func (c HSVAColor) Opaque() Color

func (HSVAColor) RGB

func (c HSVAColor) RGB() Color

func (HSVAColor) Translucent

func (c HSVAColor) Translucent() Color

func (HSVAColor) Type

func (HSVAColor) Type() Type

type HSVColor

type HSVColor struct {
	HSVAColor
}

HSVColor is just an HSVColor with foll opacity

func (HSVColor) HSL

func (c HSVColor) HSL() Color

HSV => HSL

func (HSVColor) HSV

func (c HSVColor) HSV() Color

func (HSVColor) Ints

func (c HSVColor) Ints() []int

func (HSVColor) Opaque

func (c HSVColor) Opaque() Color

func (HSVColor) RGB

func (c HSVColor) RGB() Color

HSV => RGB

func (HSVColor) Translucent

func (c HSVColor) Translucent() Color

type Named

type Named struct {
	Color
	// contains filtered or unexported fields
}

func (Named) HasName

func (n Named) HasName(name string) bool

func (Named) Name

func (n Named) Name() string

func (Named) Names

func (n Named) Names() []string

Names recursively gets all names assigned to this color

type RGBAColor

type RGBAColor struct {
	R byte // red:     0 .. 255
	G byte // green:   0 .. 255
	B byte // blue:    0 .. 255
	A byte // opacity: 0 .. 255
}

RGBAColor represents a color specified by four integer values for red, green, blue and opacity (0: transparent, 255: opaque), ranging between 0 and 255

func (RGBAColor) HSL

func (c RGBAColor) HSL() Color

func (RGBAColor) HSV

func (c RGBAColor) HSV() Color

func (RGBAColor) HasName

func (RGBAColor) HasName(string) bool

func (RGBAColor) Ints

func (c RGBAColor) Ints() []int

func (RGBAColor) Name

func (RGBAColor) Name() string

func (RGBAColor) Names

func (RGBAColor) Names() []string

func (RGBAColor) Opaque

func (c RGBAColor) Opaque() Color

func (RGBAColor) RGB

func (c RGBAColor) RGB() Color

func (RGBAColor) String

func (c RGBAColor) String() string

func (RGBAColor) Translucent

func (c RGBAColor) Translucent() Color

func (RGBAColor) Type

func (RGBAColor) Type() Type

type RGBColor

type RGBColor struct {
	RGBAColor
}

RGBColor is just an RGBAColor with full opacity Note: even without the opacity value, both structs would be 32 bits in size

func (RGBColor) HSL

func (c RGBColor) HSL() Color

RGB => HSL

func (RGBColor) HSV

func (c RGBColor) HSV() Color

RGB => HSV

func (RGBColor) Ints

func (c RGBColor) Ints() []int

func (RGBColor) Opaque

func (c RGBColor) Opaque() Color

func (RGBColor) RGB

func (c RGBColor) RGB() Color

func (RGBColor) String

func (c RGBColor) String() string

func (RGBColor) Translucent

func (c RGBColor) Translucent() Color

type Scheme

type Scheme struct {
	Name  string
	Color map[string]Color
}

func NewScheme

func NewScheme(name string) *Scheme

NewScheme creates a new color scheme

An error will be returned if any color does not have a name

func (*Scheme) Add

func (s *Scheme) Add(name, value string) error

func (*Scheme) ColorWithName

func (s *Scheme) ColorWithName(name string) (Color, error)

func (*Scheme) Colors

func (s *Scheme) Colors() []Color

type Type

type Type byte
const (
	RGBType Type = iota
	HSLType
	HSVType
)

func (Type) FromInts

func (t Type) FromInts(ints ...int) (Color, error)

func (Type) String

func (ct Type) String() string

Directories

Path Synopsis
adapter

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL