summaryrefslogtreecommitdiff
path: root/internal/colors/hsl.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/colors/hsl.go')
-rw-r--r--internal/colors/hsl.go108
1 files changed, 108 insertions, 0 deletions
diff --git a/internal/colors/hsl.go b/internal/colors/hsl.go
index 7477042..2a31f81 100644
--- a/internal/colors/hsl.go
+++ b/internal/colors/hsl.go
@@ -1 +1,109 @@
package colors
+
+import (
+ "fmt"
+ "math"
+)
+
+type HSL struct {
+ H int // 0-360
+ S int // 0-100
+ L int // 0-100
+}
+
+func (h HSL) String() string {
+ return fmt.Sprintf("hsl(%d, %d, %d)", h.H, h.S, h.L)
+}
+
+func (h HSL) ToPrecise() PreciseColor {
+ // Normalize H, S, L
+ hue := float64(h.H) / 360.0
+ sat := float64(h.S) / 100.0
+ light := float64(h.L) / 100.0
+
+ var r, g, b float64
+
+ if sat == 0 {
+ // Achromatic case
+ r, g, b = light, light, light
+ } else {
+ var q float64
+ if light < 0.5 {
+ q = light * (1 + sat)
+ } else {
+ q = light + sat - (light * sat)
+ }
+ p := 2*light - q
+ r = hueToRGB(p, q, hue+1.0/3.0)
+ g = hueToRGB(p, q, hue)
+ b = hueToRGB(p, q, hue-1.0/3.0)
+ }
+
+ return PreciseColor{R: r, G: g, B: b}
+}
+
+func hueToRGB(p, q, t float64) float64 {
+ if t < 0 {
+ t += 1
+ }
+ if t > 1 {
+ t -= 1
+ }
+ if t < 1.0/6.0 {
+ return p + (q-p)*6*t
+ }
+ if t < 1.0/2.0 {
+ return q
+ }
+ if t < 2.0/3.0 {
+ return p + (q-p)*(2.0/3.0-t)*6
+ }
+ return p
+}
+
+func (h HSL) FromPrecise(p PreciseColor) ColorSpace {
+ r := p.R
+ g := p.G
+ b := p.B
+
+ max := math.Max(math.Max(r, g), b)
+ min := math.Min(math.Min(r, g), b)
+ delta := max - min
+
+ light := (max + min) / 2
+ var sat, hue float64
+
+ if delta == 0 {
+ // Achromatic case
+ hue, sat = 0, 0
+ } else {
+ if light < 0.5 {
+ sat = delta / (max + min)
+ } else {
+ sat = delta / (2 - max - min)
+ }
+
+ switch max {
+ case r:
+ hue = (g-b)/delta + (6 * boolToFloat64(g < b))
+ case g:
+ hue = (b-r)/delta + 2
+ case b:
+ hue = (r-g)/delta + 4
+ }
+ hue /= 6
+ }
+
+ return HSL{
+ H: int(math.Round(hue * 360)),
+ S: int(math.Round(sat * 100)),
+ L: int(math.Round(light * 100)),
+ }
+}
+
+func boolToFloat64(b bool) float64 {
+ if b {
+ return 1
+ }
+ return 0
+}