From 4d25e4ece0b72d240bb2565f8abb7389e650990a Mon Sep 17 00:00:00 2001 From: Benjamin Chausse Date: Sat, 23 Nov 2024 21:05:11 -0500 Subject: Preview + Unit-tests for color conversions --- internal/colors/hsl.go | 108 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) (limited to 'internal/colors/hsl.go') 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 +} -- cgit v1.2.3