color/internal/helper/clamp.go
2025-03-06 13:01:21 -05:00

64 lines
1.3 KiB
Go

package helper
import (
"math"
)
// 0 if NaN or -Inf, 1 otherwise.
func oneIfFinite(x float64) float64 {
if x > math.Inf(-1) {
return 1
}
// NaN or -Inf
return 0
}
// x if >= 0, 0 otherwise (including NaN).
func zeroOrMore(x float64) float64 {
if x >= 0 {
return x
}
return 0
}
// the builtin max function doesn't ignore NaNs like I'd prefer, so do it ourselves.
func max3(a, b, c float64) float64 {
result := a
if result != result || b > result {
result = b
}
if result != result || c > result {
result = c
}
return result
}
func ClampRGB(r, g, b float64) (_, _, _ float64) {
// if any components are greater than 1, scale them down back into a legal range and
// fade to white based to how for out of range they are.
if m := max3(r, g, b); m > 1 {
m2 := m * m
if math.IsInf(m2, 1) {
// This would be white if all components were sensible finite values,
// although we will return zeros for any that were NaN or -Inf.
return oneIfFinite(r), oneIfFinite(g), oneIfFinite(b)
}
c := 1 - 1/m
r = c + r/m2
g = c + g/m2
b = c + b/m2
}
// make sure no components are NaN or less than zero.
// note that we do this last so that the fade to white logic has a chance to bring
// components back into legal ranges.
return zeroOrMore(r), zeroOrMore(g), zeroOrMore(b)
}