71
71
# -----------------
72
72
73
73
correct_gamut (c:: CV ) where {CV<: AbstractRGB } = CV (clamp01 (red (c)), clamp01 (green (c)), clamp01 (blue (c)))
74
+ correct_gamut (c:: CV ) where {T<: Union{N0f8,N0f16,N0f32} , CV<: AbstractRGB{T} } = c
74
75
clamp01 (v:: T ) where {T<: Fractional } = ifelse (v < zero (T), zero (T), ifelse (v > one (T), one (T), v))
75
76
76
77
function srgb_compand (v:: Fractional )
81
82
82
83
cnvt (:: Type{CV} , c:: AbstractRGB ) where {CV<: AbstractRGB } = CV (red (c), green (c), blue (c))
83
84
84
- function cnvt (:: Type{CV} , c:: HSV ) where CV<: AbstractRGB
85
- h = c. h / 60
86
- i = floor (Int, h)
87
- f = h - i
88
- if i & 1 == 0
89
- f = 1 - f
90
- end
91
- m = c. v * (1 - c. s)
92
- n = c. v * (1 - c. s * f)
93
- if i == 6 || i == 0 ; CV (c. v, n, m)
94
- elseif i == 1 ; CV (n, c. v, m)
95
- elseif i == 2 ; CV (m, c. v, n)
96
- elseif i == 3 ; CV (m, n, c. v)
97
- elseif i == 4 ; CV (n, m, c. v)
98
- else ; CV (c. v, m, n)
99
- end
100
- end
101
-
102
- function qtrans (u, v, hue)
103
- hue = normalize_hue (hue)
104
-
105
- if hue < 60 ; u + (v - u) * hue / 60
106
- elseif hue < 180 ; v
107
- elseif hue < 240 ; u + (v - u) * (240 - hue) / 60
108
- else ; u
109
- end
110
- end
111
-
112
- function cnvt (:: Type{CV} , c:: HSL ) where CV<: AbstractRGB
113
- v = c. l <= 0.5 ? c. l * (1 + c. s) : c. l + c. s - (c. l * c. s)
114
- u = 2 * c. l - v
115
85
116
- if c. s == 0 ; CV (c. l, c. l, c. l)
117
- else ; CV (qtrans (u, v, c. h + 120 ),
118
- qtrans (u, v, c. h),
119
- qtrans (u, v, c. h - 120 ))
120
- end
121
- end
122
-
123
- function cnvt (:: Type{CV} , c:: HSI ) where CV<: AbstractRGB
124
- h, s, i = normalize_hue (c. h), c. s, c. i
125
- is = i* s
126
- if h < 120
127
- cosr = cosd (h) / cosd (60 - h)
128
- CV (i+ is* cosr, i+ is* (1 - cosr), i- is)
129
- elseif h < 240
130
- cosr = cosd (h- 120 ) / cosd (180 - h)
131
- CV (i- is, i+ is* cosr, i+ is* (1 - cosr))
86
+ function _hsx_to_rgb (im:: UInt8 , v, n, m)
87
+ r = ifelse ((im & 0b100001 ) != 0x0 , v, ifelse ((im & 0b010010 ) != 0x0 , n, m))
88
+ g = ifelse ((im & 0b000110 ) != 0x0 , v, ifelse ((im & 0b001001 ) != 0x0 , n, m))
89
+ b = ifelse ((im & 0b011000 ) != 0x0 , v, ifelse ((im & 0b100100 ) != 0x0 , n, m))
90
+ return (r, g, b)
91
+ end
92
+ function _hsx_to_rgb (im:: UInt8 , v:: T , n:: T , m:: T ) where T <: Union{Float16, Float32, Float64}
93
+ vu, nu, mu = reinterpret .(Unsigned, (v, n, m)) # prompt the compiler to use conditional moves
94
+ r = ifelse ((im & 0b100001 ) != 0x0 , vu, ifelse ((im & 0b010010 ) != 0x0 , nu, mu))
95
+ g = ifelse ((im & 0b000110 ) != 0x0 , vu, ifelse ((im & 0b001001 ) != 0x0 , nu, mu))
96
+ b = ifelse ((im & 0b011000 ) != 0x0 , vu, ifelse ((im & 0b100100 ) != 0x0 , nu, mu))
97
+ return reinterpret .(T, (r, g, b))
98
+ end
99
+
100
+ function cnvt (:: Type{CV} , c:: HSV ) where {T, CV<: AbstractRGB{T} }
101
+ F = promote_type (T, eltype (c))
102
+ h, s, v = div60 (F (c. h)), clamp01 (F (c. s)), clamp01 (F (c. v))
103
+ hi = unsafe_trunc (Int32, h) # instead of floor
104
+ i = h >= 0 ? hi : hi - 0x1
105
+ f = (i & 0x1 != 0 ) ? h - i : 1 - (h - i)
106
+ im = 0x1 << (mod6 (UInt8, i) & 0x07 )
107
+ m = v * (1 - s)
108
+ n = v * (1 - s * f)
109
+ r, g, b = _hsx_to_rgb (im, v, n, m)
110
+ T <: FixedPoint && typemax (T) >= 1 ? CV (r % T, g % T, b % T) : CV (r, g, b)
111
+ end
112
+
113
+ function cnvt (:: Type{CV} , c:: HSL ) where {T, CV<: AbstractRGB{T} }
114
+ F = promote_type (T, eltype (c))
115
+ h, s, l = div60 (F (c. h)), clamp01 (F (c. s)), clamp01 (F (c. l))
116
+ a = @fastmath min (l, 1 - l) * s
117
+ v = a + l
118
+ hi = unsafe_trunc (Int32, h) # instead of floor
119
+ i = h >= 0 ? hi : hi - 0x1
120
+ f = (i & 0x1 != 0 ) ? h - i : 1 - (h - i)
121
+ im = 0x1 << (mod6 (UInt8, i) & 0x07 )
122
+ m = v - 2 * a
123
+ n = v - 2 * a * f
124
+ r, g, b = _hsx_to_rgb (im, v, n, m)
125
+ T <: FixedPoint && typemax (T) >= 1 ? CV (r % T, g % T, b % T) : CV (r, g, b)
126
+ end
127
+
128
+ function cnvt (:: Type{CV} , c:: HSI ) where {T, CV<: AbstractRGB{T} }
129
+ F = promote_type (T, eltype (c))
130
+ h, s, i = deg2rad (normalize_hue (F (c. h))), clamp01 (F (c. s)), clamp01 (F (c. i))
131
+ is = i * s
132
+ if h < F (2 π/ 3 )
133
+ @fastmath cosr = cos (h) / cos (F (π/ 3 )- h)
134
+ r0, g0, b0 = muladd (is, cosr, i), muladd (is, 1 - cosr, i), i - is
135
+ elseif h < F (4 π/ 3 )
136
+ @fastmath cosr = cos (h- F (2 π/ 3 )) / cos (F (π)- h)
137
+ r0, g0, b0 = i - is, muladd (is, cosr, i), muladd (is, 1 - cosr, i)
132
138
else
133
- cosr = cosd (h- 240 ) / cosd ( 300 - h)
134
- CV (i + is * ( 1 - cosr), i- is, i + is * cosr)
139
+ @fastmath cosr = cos (h- F ( 4 π / 3 )) / cos ( F ( 5 π / 3 ) - h)
140
+ r0, g0, b0 = muladd (is, 1 - cosr, i ), i - is, muladd (is, cosr, i )
135
141
end
142
+ r, g, b = min (r0, oneunit (F)), min (g0, oneunit (F)), min (b0, oneunit (F))
143
+ T <: FixedPoint && typemax (T) >= 1 ? CV (r % T, g % T, b % T) : CV (r, g, b)
136
144
end
137
145
138
146
function cnvt (:: Type{CV} , c:: XYZ ) where CV<: AbstractRGB
@@ -175,26 +183,23 @@ end
175
183
# -----------------
176
184
177
185
function cnvt (:: Type{HSV{T}} , c:: AbstractRGB ) where T
178
- c_min = Float64 ( min ( red (c), green (c), blue (c) ))
179
- c_max = Float64 ( max (red (c), green (c), blue (c)))
180
- if c_min == c_max
181
- return HSV {T} ( zero (T), zero (T ), c_max )
182
- end
183
-
184
- if c_min == red (c)
185
- f = Float64 ( green (c)) - Float64 ( blue (c))
186
- i = 3
187
- elseif c_min == green (c)
188
- f = Float64 ( blue (c)) - Float64 ( red (c))
189
- i = 5
186
+ F = promote_type (T, eltype (c ))
187
+ r, g, b = F .( (red (c), green (c), blue (c)))
188
+ @fastmath c_min = min ( min (r, g), b)
189
+ @fastmath c_max = max ( max (r, g ), b )
190
+ s0 = c_max - c_min
191
+ s0 == 0 && return HSV {T} ( zero (T), zero (T), T (c_max))
192
+
193
+ if c_max == r
194
+ h0 = (g - b) / s0
195
+ h = (h0 < 0 ) * 6 + h0
196
+ elseif c_max == g
197
+ h = 2 + (b - r) / s0
190
198
else
191
- f = Float64 (red (c)) - Float64 (green (c))
192
- i = 1
199
+ h = 4 + (r - g) / s0
193
200
end
194
201
195
- HSV {T} (60 * (i - f / (c_max - c_min)),
196
- (c_max - c_min) / c_max,
197
- c_max)
202
+ HSV {T} (h * 60 , s0 / c_max, c_max)
198
203
end
199
204
200
205
@@ -205,28 +210,26 @@ cnvt(::Type{HSV{T}}, c::Color3) where {T} = cnvt(HSV{T}, convert(RGB{T}, c))
205
210
# -----------------
206
211
207
212
function cnvt (:: Type{HSL{T}} , c:: AbstractRGB ) where T
208
- r, g, b = T (red (c)), T (green (c)), T (blue (c))
209
- c_min = min (r, g, b)
210
- c_max = max (r, g, b)
211
- l = (c_max + c_min) / 2
212
-
213
- if c_max == c_min
214
- return HSL (zero (T), zero (T), l)
215
- end
216
-
217
- if l < 0.5 ; s = (c_max - c_min) / (c_max + c_min)
218
- else ; s = (c_max - c_min) / (convert (T, 2 ) - c_max - c_min)
219
- end
220
-
221
- if c_max == red (c)
222
- h = (g - b) / (c_max - c_min)
223
- elseif c_max == green (c)
224
- h = convert (T, 2 ) + (b - r) / (c_max - c_min)
213
+ F = promote_type (T, eltype (c))
214
+ r, g, b = F (red (c)), F (green (c)), F (blue (c))
215
+ c_min = @fastmath min (min (r, g), b)
216
+ c_max = @fastmath max (max (r, g), b)
217
+ l0 = c_max + c_min
218
+ s0 = c_max - c_min
219
+ s0 == 0 && return HSL {T} (zero (T), zero (T), l0 * T (0.5 ))
220
+
221
+ s = @fastmath s0 / min (l0, 2 - l0)
222
+
223
+ if c_max == r
224
+ h0 = (g - b) / s0
225
+ h = (h0 < 0 ) * 6 + h0
226
+ elseif c_max == g
227
+ h = 2 + (b - r) / s0
225
228
else
226
- h = convert (T, 4 ) + (r - g) / (c_max - c_min)
229
+ h = 4 + (r - g) / s0
227
230
end
228
231
229
- HSL {T} (normalize_hue ( h * 60 ) , s, l )
232
+ HSL {T} (h * 60 , s, l0 * F ( 0.5 ) )
230
233
end
231
234
232
235
@@ -236,22 +239,20 @@ cnvt(::Type{HSL{T}}, c::Color3) where {T} = cnvt(HSL{T}, convert(RGB{T}, c))
236
239
# Everything to HSI
237
240
# -----------------
238
241
239
- function cnvt (:: Type{HSI{T}} , c:: AbstractRGB ) where T
242
+ # Since acosd() is slow, the following is "inline-worthy".
243
+ @inline function cnvt (:: Type{HSI{T}} , c:: AbstractRGB ) where T
240
244
rgb = correct_gamut (c)
241
- r, g, b = float (red (rgb)), float (green (rgb)), float (blue (rgb))
242
- isum = r+ g+ b
243
- dnorm = sqrt (((r- g)^ 2 + (r- b)^ 2 + (g- b)^ 2 )/ 2 )
244
- dnorm = dnorm == 0 ? oftype (dnorm, 1 ) : dnorm
245
- i = isum/ 3
246
- m = min (r, g, b)
247
- s = i > 0 ? 1 - m/ i : zero (1 - m/ i)
248
- val = (r- (g+ b)/ 2 )/ dnorm
249
- val = clamp (val, - oneunit (val), oneunit (val))
250
- h = acosd (val)
251
- if b > g
252
- h = 360 - h
253
- end
254
- HSI {T} (h, s, i)
245
+ F = promote_type (T, eltype (c))
246
+ r, g, b = F (red (rgb)), F (green (rgb)), F (blue (rgb))
247
+ dnorm = @fastmath sqrt (((r- g)^ 2 + (r- b)^ 2 + (g- b)^ 2 ) * F (0.5 ))
248
+ isum = r + g + b
249
+ i = isum / 3
250
+ dnorm == 0 && return HSI {T} (T (90 ), zero (T), T (i))
251
+ val = muladd (g + b, F (- 0.5 ), r) / dnorm
252
+ h = @fastmath acosd (clamp (val, - oneunit (F), oneunit (F)))
253
+ m = @fastmath min (min (r, g), b)
254
+ s = 1 - m/ i
255
+ HSI {T} (b > g ? 360 - h : h, s, i)
255
256
end
256
257
257
258
cnvt (:: Type{HSI{T}} , c:: Color3 ) where {T} = cnvt (HSI{T}, convert (RGB{T}, c))
0 commit comments