Skip to content

Commit 391cfb7

Browse files
committed
Support blending of N colours at once
1 parent 6cdf468 commit 391cfb7

File tree

2 files changed

+29
-22
lines changed

2 files changed

+29
-22
lines changed

docs/src/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,6 @@ StyledStrings.SimpleColor
341341
StyledStrings.parse(::Type{StyledStrings.SimpleColor}, ::String)
342342
StyledStrings.tryparse(::Type{StyledStrings.SimpleColor}, ::String)
343343
StyledStrings.merge(::StyledStrings.Face, ::StyledStrings.Face)
344-
StyledStrings.blend(::StyledStrings.SimpleColor, ::StyledStrings.SimpleColor, ::Real)
344+
StyledStrings.blend
345345
StyledStrings.recolor
346346
```

src/faces.jl

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -900,13 +900,15 @@ function rgbcolor(color::SimpleColor)
900900
end
901901

902902
"""
903-
blend(a::Union{Symbol, SimpleColor}, b::Union{Symbol, SimpleColor}, α::Real)
903+
blend(a::Union{Symbol, SimpleColor}, [b::Union{Symbol, SimpleColor} => α::Real]...)
904904
905905
Blend colors `a` and `b` in Oklab space, with mix ratio `α` (0–1).
906906
907907
The colors `a` and `b` can either be `SimpleColor`s, or `Symbol`s naming a face
908908
or base color. The mix ratio `α` combines `(1 - α)` of `a` with `α` of `b`.
909909
910+
Multiple colors can be blended at once by providing multiple `b => α` pairs.
911+
910912
# Examples
911913
912914
```julia-repl
@@ -920,9 +922,11 @@ julia> blend(:green, SimpleColor(0xffffff), 0.3)
920922
SimpleColor(■ #74be93)
921923
```
922924
"""
923-
function blend(c1::SimpleColor, c2::SimpleColor, α::Real)
924-
function oklab(rgb::RGBTuple)
925-
r, g, b = (Tuple(rgb) ./ 255) .^ 2.2
925+
function blend end
926+
927+
function blend(primaries::Pair{RGBTuple, <:Real}...)
928+
function oklab(rgb::RGBTuple)
929+
r, g, b = (rgb.r / 255)^2.2, (rgb.g / 255)^2.2, (rgb.b / 255)^2.2
926930
l = cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b)
927931
m = cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b)
928932
s = cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b)
@@ -941,22 +945,25 @@ function blend(c1::SimpleColor, c2::SimpleColor, α::Real)
941945
b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
942946
(r = tohex(r), g = tohex(g), b = tohex(b))
943947
end
944-
lab1 = oklab(rgbcolor(c1))
945-
lab2 = oklab(rgbcolor(c2))
946-
mix = (L = (1 - α) * lab1.L + α * lab2.L,
947-
a = (1 - α) * lab1.a + α * lab2.a,
948-
b = (1 - α) * lab1.b + α * lab2.b)
949-
SimpleColor(rgb(mix))
950-
end
951-
952-
function blend(f1::Union{Symbol, SimpleColor}, f2::Union{Symbol, SimpleColor}, α::Real)
953-
function face_or_color(name::Symbol)
954-
c = getface(name).foreground
955-
if c.value === :foreground && haskey(FACES.basecolors, name)
956-
c = SimpleColor(name)
957-
end
958-
c
948+
L′, a′, b′ = 0.0, 0.0, 0.0
949+
for (color, α) in primaries
950+
lab = oklab(color)
951+
L′ += lab.L * α
952+
a′ += lab.a * α
953+
b′ += lab.b * α
959954
end
960-
face_or_color(c::SimpleColor) = c
961-
blend(face_or_color(f1), face_or_color(f2), α)
955+
mix = (L = L′, a = a′, b = b′)
956+
rgb(mix)
962957
end
958+
959+
blend(base::RGBTuple, primaries::Pair{RGBTuple, <:Real}...) =
960+
blend(base => 1.0 - sum(last, primaries), primaries...)
961+
962+
blend(primaries::Pair{<:Union{Symbol, SimpleColor}, <:Real}...) =
963+
SimpleColor(blend((rgbcolor(c) => w for (c, w) in primaries)...))
964+
965+
blend(base::Union{Symbol, SimpleColor}, primaries::Pair{<:Union{Symbol, SimpleColor}, <:Real}...) =
966+
SimpleColor(blend(rgbcolor(base), (rgbcolor(c) => w for (c, w) in primaries)...))
967+
968+
blend(a::Union{Symbol, SimpleColor}, b::Union{Symbol, SimpleColor}, α::Real) =
969+
blend(a => 1 - α, b => α)

0 commit comments

Comments
 (0)