Skip to content

Commit ae1fc57

Browse files
committed
Clean up verbose or old-style definitions
1 parent 7d02097 commit ae1fc57

File tree

2 files changed

+86
-94
lines changed

2 files changed

+86
-94
lines changed

src/ColorVectorSpace.jl

Lines changed: 83 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,33 @@ if !hasmethod(one, (Type{TransparentGray},))
4747
Base.one(p::Colorant) = one(typeof(p))
4848
end
4949

50-
# Real values are treated like grays
51-
if !hasmethod(gray, (Number,))
52-
ColorTypes.gray(x::Real) = x
50+
if !hasmethod(isfinite, (Colorant,))
51+
isfinite(c::Colorant) = mapreducec(isfinite, &, true, c)
52+
isinf(c::Colorant) = mapreducec(isinf, |, false, c)
53+
isnan(c::Colorant) = mapreducec(isnan, |, false, c)
54+
end
55+
56+
if !isdefined(ColorTypes, :nan)
57+
nan(::Type{T}) where {T<:AbstractFloat} = convert(T, NaN)
58+
nan(::Type{C}) where {T<:AbstractFloat, C<:MathTypes{T}} = mapc(_ -> nan(T), zero(C))
59+
end
60+
61+
if which(real, (Type{<:AbstractGray},)).module === Base
62+
real(::Type{C}) where {C<:AbstractGray} = real(eltype(C))
63+
end
64+
65+
# To help type inference
66+
promote_rule(::Type{T}, ::Type{C}) where {T<:Real,C<:AbstractGray} = promote_type(T, eltype(C))
67+
68+
promote_leaf_eltypes(x::Union{AbstractArray{T},Tuple{T,Vararg{T}}}) where {T<:MathTypes} = eltype(T)
69+
70+
if isdefined(Statistics, :_mean_promote)
71+
Statistics._mean_promote(x::MathTypes, y::MathTypes) = mapc(FixedPointNumbers.Treduce, y)
5372
end
5473

5574
## Traits and key utilities
5675

57-
# Return types for arithmetic operations
76+
# Return eltypes for arithmetic operations
5877
multype(::Type{A}, ::Type{B}) where {A,B} = coltype(typeof(zero(A)*zero(B)))
5978
sumtype(::Type{A}, ::Type{B}) where {A,B} = coltype(typeof(zero(A)+zero(B)))
6079
divtype(::Type{A}, ::Type{B}) where {A,B} = coltype(typeof(zero(A)/oneunit(B)))
@@ -99,20 +118,22 @@ _arith_colorant_type(::Type{<:AbstractRGBA}) = RGBA
99118
parametric(::Type{C}, ::Type{T}) where {C,T} = C{T}
100119
parametric(::Type{C}, ::Type{T}) where {T, C<:Colorant{T}} = C # e.g. parametric(RGB24, N0f8) == RGB24
101120

121+
rettype(::typeof(+), a::C, b::C) where {C <: Colorant} = C
122+
rettype(::typeof(-), a::C, b::C) where {C <: Colorant} = C
123+
rettype(::typeof(+), a, b) = parametric(color_rettype(a, b), sumtype(a, b))
124+
rettype(::typeof(-), a, b) = parametric(color_rettype(a, b), sumtype(a, b))
125+
rettype(::typeof(*), a, b) = parametric(color_rettype(a, b), multype(eltype(a), eltype(b))) # gray * gray
126+
rettype(::typeof(*), a::Real, b) = arith_colorant_type(b){multype(typeof(a), eltype(b))}
127+
rettype(::typeof(/), a, b::Real) = arith_colorant_type(a){divtype(eltype(a), typeof(b))}
128+
rettype(::typeof(^), a, b) = arith_colorant_type(a){powtype(eltype(a), typeof(b))}
129+
rettype(::typeof(^), a, b::Integer) = arith_colorant_type(a){powtype(eltype(a), Int)}
130+
102131
# Useful for leveraging iterator algorithms. Don't use this externally, as the implementation may change.
103132
channels(c::AbstractGray) = (gray(c),)
104133
channels(c::TransparentGray) = (gray(c), alpha(c))
105134
channels(c::AbstractRGB) = (red(c), green(c), blue(c))
106135
channels(c::TransparentRGB) = (red(c), green(c), blue(c), alpha(c))
107136

108-
nan(::Type{T}) where {T<:AbstractFloat} = convert(T, NaN)
109-
nan(::Type{C}) where {C<:MathTypes} = _nan(eltype(C), C)
110-
_nan(::Type{T}, ::Type{C}) where {T<:AbstractFloat,C<:AbstractGray} = (x = convert(T, NaN); C(x))
111-
_nan(::Type{T}, ::Type{C}) where {T<:AbstractFloat,C<:TransparentGray} = (x = convert(T, NaN); C(x,x))
112-
_nan(::Type{T}, ::Type{C}) where {T<:AbstractFloat,C<:AbstractRGB} = (x = convert(T, NaN); C(x,x,x))
113-
_nan(::Type{T}, ::Type{C}) where {T<:AbstractFloat,C<:TransparentRGB} = (x = convert(T, NaN); C(x,x,x,x))
114-
115-
116137
## Generic algorithms
117138
Base.add_sum(c1::MathTypes,c2::MathTypes) = mapc(Base.add_sum, c1, c2)
118139
Base.reduce_first(::typeof(Base.add_sum), c::MathTypes) = mapc(x->Base.reduce_first(Base.add_sum, x), c)
@@ -139,47 +160,60 @@ end
139160
dotc(x::T, y::T) where {T<:Real} = acc(x)*acc(y)
140161
dotc(x::Real, y::Real) = dotc(promote(x, y)...)
141162

163+
"""
164+
y = complement(x)
165+
166+
Take the complement `1-x` of `x`. If `x` is a color with an alpha channel,
167+
the alpha channel is left untouched. Don't forget to add a dot when `x` is
168+
an array: `complement.(x)`
169+
"""
170+
complement(x::Union{Number,Colorant}) = oneunit(x)-x
171+
complement(x::TransparentColor) = typeof(x)(complement(color(x)), alpha(x))
172+
142173

143174
## Math on Colors. These implementations encourage inlining and,
144175
## for the case of Normed types, nearly halve the number of multiplications (for RGB)
145176

177+
# Common
178+
copy(c::MathTypes) = c
179+
(*)(c::MathTypes, f::Real) = (*)(f, c)
180+
(+)(c::MathTypes) = mapc(+, c)
181+
(+)(c::MathTypes{Bool}) = c
182+
(-)(c::MathTypes) = mapc(-, c)
183+
(-)(c::MathTypes{Bool}) = c
184+
(/)(c::MathTypes, f::Real) = (one(f)/f)*c
185+
(/)(c::MathTypes, f::Integer) = (one(eltype(c))/f)*c
186+
abs(c::MathTypes) = mapc(abs, c)
187+
norm(c::MathTypes, p::Real=2) = (cc = channels(c); norm(cc, p)/(p == 0 ? length(cc) : length(cc)^(1/p)))
188+
189+
## Mixed types
190+
(+)(a::MathTypes, b::MathTypes) = (+)(promote(a, b)...)
191+
(-)(a::MathTypes, b::MathTypes) = (-)(promote(a, b)...)
192+
193+
146194
# Scalar RGB
147-
copy(c::AbstractRGB) = c
148-
(+)(c::AbstractRGB) = mapc(+, c)
149-
(+)(c::TransparentRGB) = mapc(+, c)
150-
(-)(c::AbstractRGB) = mapc(-, c)
151-
(-)(c::TransparentRGB) = mapc(-, c)
152-
(*)(f::Real, c::AbstractRGB) = arith_colorant_type(c){multype(typeof(f),eltype(c))}(f*red(c), f*green(c), f*blue(c))
153-
(*)(f::Real, c::TransparentRGB) = arith_colorant_type(c){multype(typeof(f),eltype(c))}(f*red(c), f*green(c), f*blue(c), f*alpha(c))
195+
(*)(f::Real, c::AbstractRGB) = rettype(*, f, c)(f*red(c), f*green(c), f*blue(c))
196+
(*)(f::Real, c::TransparentRGB) = rettype(*, f, c)(f*red(c), f*green(c), f*blue(c), f*alpha(c))
154197
function (*)(f::Real, c::AbstractRGB{T}) where T<:Normed
155198
fs = f*(1/reinterpret(oneunit(T)))
156-
arith_colorant_type(c){multype(typeof(f),T)}(fs*reinterpret(red(c)), fs*reinterpret(green(c)), fs*reinterpret(blue(c)))
199+
rettype(*, f, c)(fs*reinterpret(red(c)), fs*reinterpret(green(c)), fs*reinterpret(blue(c)))
157200
end
158201
function (*)(f::Normed, c::AbstractRGB{T}) where T<:Normed
159202
fs = reinterpret(f)*(1/widen(reinterpret(oneunit(T)))^2)
160-
arith_colorant_type(c){multype(typeof(f),T)}(fs*reinterpret(red(c)), fs*reinterpret(green(c)), fs*reinterpret(blue(c)))
203+
rettype(*, f, c)(fs*reinterpret(red(c)), fs*reinterpret(green(c)), fs*reinterpret(blue(c)))
161204
end
162205
function (/)(c::AbstractRGB{T}, f::Real) where T<:Normed
163206
fs = (one(f)/reinterpret(oneunit(T)))/f
164-
arith_colorant_type(c){divtype(typeof(f),T)}(fs*reinterpret(red(c)), fs*reinterpret(green(c)), fs*reinterpret(blue(c)))
207+
rettype(/, c, f)(fs*reinterpret(red(c)), fs*reinterpret(green(c)), fs*reinterpret(blue(c)))
165208
end
166209
function (/)(c::AbstractRGB{T}, f::Integer) where T<:Normed
167210
fs = (1/reinterpret(oneunit(T)))/f
168-
arith_colorant_type(c){divtype(typeof(f),T)}(fs*reinterpret(red(c)), fs*reinterpret(green(c)), fs*reinterpret(blue(c)))
211+
rettype(/, c, f)(fs*reinterpret(red(c)), fs*reinterpret(green(c)), fs*reinterpret(blue(c)))
169212
end
170-
(+)(a::AbstractRGB{S}, b::AbstractRGB{T}) where {S,T} = parametric(color_rettype(a, b), sumtype(S,T))(red(a)+red(b), green(a)+green(b), blue(a)+blue(b))
171-
(-)(a::AbstractRGB{S}, b::AbstractRGB{T}) where {S,T} = parametric(color_rettype(a, b), sumtype(S,T))(red(a)-red(b), green(a)-green(b), blue(a)-blue(b))
172-
(+)(a::TransparentRGB, b::TransparentRGB) =
173-
parametric(color_rettype(a, b), sumtype(a,b))(red(a)+red(b), green(a)+green(b), blue(a)+blue(b), alpha(a)+alpha(b))
174-
(-)(a::TransparentRGB, b::TransparentRGB) =
175-
parametric(color_rettype(a, b), sumtype(a,b))(red(a)-red(b), green(a)-green(b), blue(a)-blue(b), alpha(a)-alpha(b))
176-
(*)(c::AbstractRGB, f::Real) = (*)(f, c)
177-
(*)(c::TransparentRGB, f::Real) = (*)(f, c)
178-
(/)(c::AbstractRGB, f::Real) = (one(f)/f)*c
179-
(/)(c::TransparentRGB, f::Real) = (one(f)/f)*c
180-
(/)(c::AbstractRGB, f::Integer) = (one(eltype(c))/f)*c
181-
(/)(c::TransparentRGB, f::Integer) = (one(eltype(c))/f)*c
182-
213+
(+)(a::AbstractRGB, b::AbstractRGB) = rettype(+, a, b)(red(a)+red(b), green(a)+green(b), blue(a)+blue(b))
214+
(-)(a::AbstractRGB, b::AbstractRGB) = rettype(-, a, b)(red(a)-red(b), green(a)-green(b), blue(a)-blue(b))
215+
(+)(a::TransparentRGB, b::TransparentRGB) = rettype(+, a, b)(red(a)+red(b), green(a)+green(b), blue(a)+blue(b), alpha(a)+alpha(b))
216+
(-)(a::TransparentRGB, b::TransparentRGB) = rettype(-, a, b)(red(a)-red(b), green(a)-green(b), blue(a)-blue(b), alpha(a)-alpha(b))
183217

184218
# New multiplication operators
185219
()(x::AbstractRGB, y::AbstractRGB) = (T = acctype(eltype(x), eltype(y)); T(red(x))*T(red(y)) + T(green(x))*T(green(y)) + T(blue(x))*T(blue(y)))/3
@@ -188,24 +222,13 @@ end
188222
()(x::Union{AbstractRGB,AbstractGray}, y::Union{AbstractRGB,AbstractGray}) = (promote(x, y)...)
189223
# ⊗ defined below
190224

191-
isfinite(c::Colorant{T}) where {T<:Normed} = true
192-
isfinite(c::Colorant) = mapreducec(isfinite, &, true, c)
193-
isnan(c::Colorant{T}) where {T<:Normed} = false
194-
isnan(c::Colorant) = mapreducec(isnan, |, false, c)
195-
isinf(c::Colorant{T}) where {T<:Normed} = false
196-
isinf(c::Colorant) = mapreducec(isinf, |, false, c)
197-
abs(c::MathTypes) = mapc(abs, c)
198-
norm(c::MathTypes, p::Real=2) = (cc = channels(c); norm(cc, p)/(p == 0 ? length(cc) : length(cc)^(1/p)))
199-
200-
promote_leaf_eltypes(x::Union{AbstractArray{T},Tuple{T,Vararg{T}}}) where {T<:MathTypes} = eltype(T)
201225

202226
# These constants come from squaring the conversion to grayscale
203227
# (rec601 luma), and normalizing
204228
dotc(x::T, y::T) where {T<:AbstractRGB} = 0.200f0 * acc(red(x))*acc(red(y)) + 0.771f0 * acc(green(x))*acc(green(y)) + 0.029f0 * acc(blue(x))*acc(blue(y))
205229
dotc(x::AbstractRGB, y::AbstractRGB) = dotc(promote(x, y)...)
206230

207231
# Scalar Gray
208-
copy(c::AbstractGray) = c
209232
const unaryOps = (:~, :conj, :abs,
210233
:sin, :cos, :tan, :sinh, :cosh, :tanh,
211234
:asin, :acos, :atan, :asinh, :acosh, :atanh,
@@ -232,43 +255,19 @@ function logabsgamma(c::AbstractGray)
232255
return Gray(lagc), s
233256
end
234257

235-
"""
236-
y = complement(x)
237-
238-
Take the complement `1-x` of `x`. If `x` is a color with an alpha channel,
239-
the alpha channel is left untouched. Don't forget to add a dot when `x` is
240-
an array: `complement.(x)`
241-
"""
242-
complement(x::Union{Number,Colorant}) = oneunit(x)-x
243-
complement(x::TransparentColor) = typeof(x)(complement(color(x)), alpha(x))
244-
245258
middle(c::AbstractGray) = arith_colorant_type(c)(middle(gray(c)))
246259
middle(x::C, y::C) where {C<:AbstractGray} = arith_colorant_type(C)(middle(gray(x), gray(y)))
247260

248-
if isdefined(Statistics, :_mean_promote)
249-
Statistics._mean_promote(x::MathTypes, y::MathTypes) = mapc(FixedPointNumbers.Treduce, y)
250-
end
251-
252-
(*)(f::Real, c::AbstractGray) = arith_colorant_type(c){multype(typeof(f),eltype(c))}(f*gray(c))
253-
(*)(f::Real, c::TransparentGray) = arith_colorant_type(c){multype(typeof(f),eltype(c))}(f*gray(c), f*alpha(c))
254-
(*)(c::AbstractGray, f::Real) = (*)(f, c)
255-
(*)(c::TransparentGray, f::Real) = (*)(f, c)
256-
(/)(c::AbstractGray, f::Real) = (one(f)/f)*c
261+
(*)(f::Real, c::AbstractGray) = rettype(*, f, c)(f*gray(c))
262+
(*)(f::Real, c::TransparentGray) = rettype(*, f, c)(f*gray(c), f*alpha(c))
257263
(/)(n::Number, c::AbstractGray) = base_color_type(c)(n/gray(c))
258-
(/)(c::TransparentGray, f::Real) = (one(f)/f)*c
259-
(/)(c::AbstractGray, f::Integer) = (one(eltype(c))/f)*c
260-
(/)(c::TransparentGray, f::Integer) = (one(eltype(c))/f)*c
261-
(+)(a::AbstractGray{S}, b::AbstractGray{T}) where {S,T} = parametric(color_rettype(a,b), sumtype(S,T))(gray(a)+gray(b))
262-
(+)(a::TransparentGray, b::TransparentGray) = parametric(color_rettype(a,b), sumtype(eltype(a),eltype(b)))(gray(a)+gray(b),alpha(a)+alpha(b))
263-
(-)(a::AbstractGray{S}, b::AbstractGray{T}) where {S,T} = parametric(color_rettype(a,b), sumtype(S,T))(gray(a)-gray(b))
264-
(-)(a::TransparentGray, b::TransparentGray) = parametric(color_rettype(a,b), sumtype(eltype(a),eltype(b)))(gray(a)-gray(b),alpha(a)-alpha(b))
265-
(*)(a::AbstractGray{S}, b::AbstractGray{T}) where {S,T} = parametric(color_rettype(a,b), multype(S,T))(gray(a)*gray(b))
266-
(^)(a::AbstractGray{S}, b::Integer) where {S} = arith_colorant_type(a){powtype(S,Int)}(gray(a)^convert(Int,b))
267-
(^)(a::AbstractGray{S}, b::Real) where {S} = arith_colorant_type(a){powtype(S,typeof(b))}(gray(a)^b)
268-
(+)(c::AbstractGray) = c
269-
(+)(c::TransparentGray) = c
270-
(-)(c::AbstractGray) = typeof(c)(-gray(c))
271-
(-)(c::TransparentGray) = typeof(c)(-gray(c),-alpha(c))
264+
(+)(a::AbstractGray, b::AbstractGray) = rettype(+, a, b)(gray(a)+gray(b))
265+
(+)(a::TransparentGray, b::TransparentGray) = rettype(+, a, b)(gray(a)+gray(b), alpha(a)+alpha(b))
266+
(-)(a::AbstractGray, b::AbstractGray) = rettype(-, a, b)(gray(a)-gray(b))
267+
(-)(a::TransparentGray, b::TransparentGray) = rettype(-, a, b)(gray(a)-gray(b), alpha(a)-alpha(b))
268+
(*)(a::AbstractGray, b::AbstractGray) = rettype(*, a, b)(gray(a)*gray(b))
269+
(^)(a::AbstractGray, b::Integer) = rettype(^, a, b)(gray(a)^convert(Int,b))
270+
(^)(a::AbstractGray, b::Real) = rettype(^, a, b)(gray(a)^b)
272271
(/)(a::C, b::C) where C<:AbstractGray = base_color_type(C)(gray(a)/gray(b))
273272
(/)(a::AbstractGray, b::AbstractGray) = /(promote(a, b)...)
274273
(+)(a::AbstractGray, b::Number) = base_color_type(a)(gray(a)+b)
@@ -306,20 +305,10 @@ end
306305
dotc(x::T, y::T) where {T<:AbstractGray} = acc(gray(x))*acc(gray(y))
307306
dotc(x::AbstractGray, y::AbstractGray) = dotc(promote(x, y)...)
308307

309-
# Mixed types
310-
(+)(a::MathTypes, b::MathTypes) = (+)(promote(a, b)...)
311-
(-)(a::MathTypes, b::MathTypes) = (-)(promote(a, b)...)
312-
313-
real(::Type{C}) where {C<:AbstractGray} = real(eltype(C))
314-
315-
# To help type inference
316-
promote_rule(::Type{T}, ::Type{C}) where {T<:Real,C<:AbstractGray} = promote_type(T, eltype(C))
317-
318-
typemin(::Type{T}) where {T<:ColorTypes.AbstractGray} = T(typemin(eltype(T)))
319-
typemax(::Type{T}) where {T<:ColorTypes.AbstractGray} = T(typemax(eltype(T)))
320-
321-
typemin(::T) where {T<:ColorTypes.AbstractGray} = T(typemin(eltype(T)))
322-
typemax(::T) where {T<:ColorTypes.AbstractGray} = T(typemax(eltype(T)))
308+
typemin(::Type{C}) where {C<:AbstractGray} = C(typemin(eltype(C)))
309+
typemax(::Type{C}) where {C<:AbstractGray} = C(typemax(eltype(C)))
310+
typemin(c::AbstractGray) = typemin(typeof(c))
311+
typemax(c::AbstractGray) = typemax(typeof(c))
323312

324313
## RGB tensor products
325314

test/runtests.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ ColorTypes.alpha(c::GrayA32) = reinterpret(N0f8, c.color % UInt8)
5050
ColorTypes.comp2(c::RGBA32) = alpha(c)
5151

5252
@testset "Colortypes" begin
53+
@testset "ambiguities" begin
54+
@test isempty(detect_ambiguities(ColorVectorSpace))
55+
end
5356

5457
@testset "convert" begin
5558
for x in (0.5, 0.5f0, NaN, NaN32, N0f8(0.5))

0 commit comments

Comments
 (0)