Skip to content

Commit 7d02097

Browse files
authored
Generalize non-parametric type handling (#149)
1 parent 85b8759 commit 7d02097

File tree

2 files changed

+52
-12
lines changed

2 files changed

+52
-12
lines changed

src/ColorVectorSpace.jl

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,20 @@ _color_rettype(::Type{C}, ::Type{C}) where {C<:Colorant} = C
8484
color_rettype(c1::Colorant, c2::Colorant) = color_rettype(typeof(c1), typeof(c2))
8585

8686
arith_colorant_type(::C) where {C<:Colorant} = arith_colorant_type(C)
87-
arith_colorant_type(::Type{C}) where {C<:Colorant} = base_colorant_type(C)
88-
arith_colorant_type(::Type{Gray24}) = Gray
89-
arith_colorant_type(::Type{AGray32}) = AGray
90-
arith_colorant_type(::Type{RGB24}) = RGB
91-
arith_colorant_type(::Type{ARGB32}) = ARGB
87+
function arith_colorant_type(::Type{C}) where {C<:Colorant}
88+
Cb = base_colorant_type(C)
89+
isconcretetype(C) && C === Cb && return _arith_colorant_type(C) # non-parametric
90+
return Cb
91+
end
92+
_arith_colorant_type(::Type{<:AbstractGray}) = Gray
93+
_arith_colorant_type(::Type{<:TransparentGray}) = AGray
94+
_arith_colorant_type(::Type{<:AbstractGrayA}) = GrayA
95+
_arith_colorant_type(::Type{<:AbstractRGB}) = RGB
96+
_arith_colorant_type(::Type{<:TransparentRGB}) = ARGB
97+
_arith_colorant_type(::Type{<:AbstractRGBA}) = RGBA
9298

9399
parametric(::Type{C}, ::Type{T}) where {C,T} = C{T}
94-
parametric(::Type{Gray24}, ::Type{N0f8}) = Gray24
95-
parametric(::Type{RGB24}, ::Type{N0f8}) = RGB24
96-
parametric(::Type{AGray32}, ::Type{N0f8}) = AGray32
97-
parametric(::Type{ARGB32}, ::Type{N0f8}) = ARGB32
100+
parametric(::Type{C}, ::Type{T}) where {T, C<:Colorant{T}} = C # e.g. parametric(RGB24, N0f8) == RGB24
98101

99102
# Useful for leveraging iterator algorithms. Don't use this externally, as the implementation may change.
100103
channels(c::AbstractGray) = (gray(c),)

test/runtests.jl

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,29 @@ ColorTypes.red(c::RatRGB) = c.r
2626
ColorTypes.green(c::RatRGB) = c.g
2727
ColorTypes.blue(c::RatRGB) = c.b
2828

29+
struct RGBA32 <: AbstractRGBA{RGB24, N0f8}
30+
color::UInt32
31+
RGBA32(c::UInt32, ::Type{Val{true}}) = new(c)
32+
end
33+
function RGBA32(r, g, b, alpha=1N0f8)
34+
u32 = reinterpret(UInt32, ARGB32(r, g, b, alpha))
35+
RGBA32((u32 << 0x8) | (u32 >> 0x18), Val{true})
36+
end
37+
ColorTypes.red( c::RGBA32) = reinterpret(N0f8, (c.color >> 0x18) % UInt8)
38+
ColorTypes.green(c::RGBA32) = reinterpret(N0f8, (c.color >> 0x10) % UInt8)
39+
ColorTypes.blue( c::RGBA32) = reinterpret(N0f8, (c.color >> 0x08) % UInt8)
40+
ColorTypes.alpha(c::RGBA32) = reinterpret(N0f8, c.color % UInt8)
41+
ColorTypes.comp4(c::RGBA32) = alpha(c)
42+
43+
struct GrayA32 <: AbstractGrayA{Gray24, N0f8}
44+
color::UInt32
45+
GrayA32(c::UInt32, ::Type{Val{true}}) = new(c)
46+
end
47+
GrayA32(g, alpha=1N0f8) = GrayA32(bswap(reinterpret(UInt32, AGray32(g, alpha))), Val{true})
48+
ColorTypes.gray( c::GrayA32) = reinterpret(N0f8, (c.color >> 0x18) % UInt8)
49+
ColorTypes.alpha(c::GrayA32) = reinterpret(N0f8, c.color % UInt8)
50+
ColorTypes.comp2(c::RGBA32) = alpha(c)
51+
2952
@testset "Colortypes" begin
3053

3154
@testset "convert" begin
@@ -244,7 +267,7 @@ ColorTypes.blue(c::RatRGB) = c.b
244267
@test -Gray(u) == Gray(-u)
245268
end
246269

247-
@testset "Arithmetic with GrayA" begin
270+
@testset "Arithmetic with TransparentGray" begin
248271
p1 = GrayA{Float32}(Gray(0.8), 0.2)
249272
@test @inferred(zero(p1)) === GrayA{Float32}(0,0)
250273
@test @inferred(oneunit(p1)) === GrayA{Float32}(1,1)
@@ -282,6 +305,13 @@ ColorTypes.blue(c::RatRGB) = c.b
282305

283306
# issue #133
284307
@test AGray32(1, 0.4) - AGray32(0.2, 0.2) === AGray32(0.8, 0.2)
308+
309+
# issue #146
310+
@test @inferred(GrayA32(0.8,0.2)*N0f8(0.5)) === GrayA{N0f8}(0.4,0.1)
311+
@test @inferred(GrayA32(0.8,0.2)*0.5) === GrayA(0.4,0.1)
312+
@test @inferred(GrayA32(0.8,0.2)/2) === GrayA(0.5f0*N0f8(0.8),0.5f0*N0f8(0.2))
313+
@test @inferred(GrayA32(0.8,0.2)/2.0) === GrayA(0.4,0.1)
314+
@test @inferred(GrayA32(1, 0.4) - GrayA32(0.2, 0.2)) === GrayA32(0.8, 0.2)
285315
end
286316

287317
@testset "Arithemtic with RGB" begin
@@ -383,7 +413,7 @@ ColorTypes.blue(c::RatRGB) = c.b
383413
@test String(take!(io)) == "RGBRGB{$Tstr}(\n 0.012N0f8 0.02N0f8 0.031N0f8\n 0.02N0f8 0.039N0f8 0.059N0f8\n 0.031N0f8 0.059N0f8 0.09N0f8$spstr)"
384414
end
385415

386-
@testset "Arithemtic with RGBA" begin
416+
@testset "Arithemtic with TransparentRGB" begin
387417
cf = RGBA{Float32}(0.1,0.2,0.3,0.4)
388418
@test @inferred(zero(cf)) === RGBA{Float32}(0,0,0,0)
389419
@test @inferred(oneunit(cf)) === RGBA{Float32}(1,1,1,1)
@@ -452,6 +482,13 @@ ColorTypes.blue(c::RatRGB) = c.b
452482
@test ARGB32(1,0,0,0.8)/2.0 === ARGB(0.5,0,0,0.4)
453483
# issue #133
454484
@test ARGB32(1, 0, 0, 0.2) + ARGB32(0, 0, 1, 0.2) === ARGB32(1, 0, 1, 0.4)
485+
486+
# issue #146
487+
@test @inferred(RGBA32(1,0,0,0.8)*N0f8(0.5)) === RGBA{N0f8}(0.5,0,0,0.4)
488+
@test @inferred(RGBA32(1,0,0,0.8)*0.5) === RGBA(0.5,0,0,0.4)
489+
@test @inferred(RGBA32(1,0,0,0.8)/2) === RGBA(0.5f0,0,0,0.5f0*N0f8(0.8))
490+
@test @inferred(RGBA32(1,0,0,0.8)/2.0) === RGBA(0.5,0,0,0.4)
491+
@test @inferred(RGBA32(1, 0, 0, 0.2) + RGBA32(0, 0, 1, 0.2)) === RGBA32(1, 0, 1, 0.4)
455492
end
456493

457494
@testset "Mixed-type arithmetic" begin
@@ -475,7 +512,7 @@ ColorTypes.blue(c::RatRGB) = c.b
475512
@test rgb g == rgb RGB(g)
476513
end
477514

478-
@testset "Custom RGB arithmetic" begin
515+
@testset "Custom RGB arithmetic" begin # see also the `RGBA32` cases above
479516
cf = RatRGB(1//10, 2//10, 3//10)
480517
@test cf cf === (Float64(red(cf))^2 + Float64(green(cf))^2 + Float64(blue(cf))^2)/3
481518
end

0 commit comments

Comments
 (0)