Skip to content

Commit

Permalink
Move promotion rules and some typealiases to ColorTypes.jl v0.10
Browse files Browse the repository at this point in the history
Since gray-->rgb conversions were supported and some rgb-->rgb conversions were fixed in ColorTypes.jl,
this commit delegates the conversions to ColorType.jl.
  • Loading branch information
kimikage committed Mar 12, 2020
1 parent a447509 commit 4ef39c6
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 112 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ os:
- linux
julia:
- 1.0
- 1.2
- 1
- nightly
notifications:
email: false
Expand Down
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Colors"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.11.2"
version = "0.12.0"

[deps]
ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
Expand All @@ -9,8 +9,8 @@ InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"

[compat]
ColorTypes = "0.9"
FixedPointNumbers = "0.6, 0.7"
ColorTypes = "0.10"
FixedPointNumbers = "0.6, 0.7, 0.8"
Reexport = "0.2"
julia = "1"

Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
environment:
matrix:
- julia_version: 1.0
- julia_version: 1.2
- julia_version: 1
- julia_version: latest

platform:
Expand Down
4 changes: 0 additions & 4 deletions src/Colors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ using Reexport
Base.@deprecate_binding RGB1 XRGB
Base.@deprecate_binding RGB4 RGBX

# TODO: why these types are defined here? Can they move to ColorTypes.jl?
AbstractAGray{C<:AbstractGray,T} = AlphaColor{C,T,2}
AbstractGrayA{C<:AbstractGray,T} = ColorAlpha{C,T,2}

import Base: ==, +, -, *, /
import Base: convert, eltype, isless, range, show, typemin, typemax
Expand All @@ -29,7 +26,6 @@ include("utilities.jl")

# Include other module components
include("conversions.jl")
include("promotions.jl")
include("algorithms.jl")
include("parse.jl")
include("differences.jl")
Expand Down
132 changes: 47 additions & 85 deletions src/conversions.jl
Original file line number Diff line number Diff line change
@@ -1,50 +1,52 @@
# Conversions
# -----------

# convert(C, c) might be called as convert(RGB, c) or convert(RGB{Float32}, c)
# This is handled in ColorTypes, which calls functions
# _convert(::Type{Cdest}, ::Type{Odest}, ::Type{Osrc}, c)
# _convert(::Type{Cdest}, ::Type{Odest}, ::Type{Osrc}, c, alpha)
# Here are the argument types:
# - Cdest may be any concrete Color{T,N} type. For parametric Color types
# it _always_ has the desired element type (e.g., Float32), so it's
# safe to dispatch on Cdest{T}.
# - Odest and Osrc are Color subtypes, i.e., things like RGB
# or HSV. They have no element type.
# - c is the Colorant object you wish to convert.
# - alpha, if present, is a user-supplied alpha value (to be used in
# place of any default alpha or alpha present in c).
#
# The motivation for this arrangement is that Julia doesn't (yet) support
# "triangular dispatch", e.g.,
# convert{T,C}(::Type{C{T}}, c)
# The various arguments of _convert therefore "peel off" element types
# (or guarantee them) so that comparisons may be made via
# dispatch. The alternative design is
# for C in parametric_colors
# @eval convert{T}(::Type{$C{T}}, c) = ...
# @eval convert( ::Type{$C}, c) = convert($C{eltype(c)}, c)
# ...
# end
# but this requires a fair amount of codegen (especially for all
# the various alpha variants) and can break if not all C support
# the same eltypes.
#
# Note that ColorTypes handles the cases where Odest == Osrc, or they
# are both subtypes of AbstractRGB. Therefore, here we only have to
# deal with conversions between different spaces.


function ColorTypes._convert(::Type{Cdest}, ::Type{Odest}, ::Type{Osrc}, p, alpha) where {Cdest<:TransparentColor,Odest,Osrc}
#=
`convert(C, c)` might be called as `convert(RGB, c)` or
`convert(RGB{Float32}, c)`.
This is handled in ColorTypes, which calls functions
```
_convert(::Type{Cdest}, ::Type{Odest}, ::Type{Osrc}, c)
_convert(::Type{Cdest}, ::Type{Odest}, ::Type{Osrc}, c, alpha)
```
Here are the argument types:
- `Cdest` may be any concrete `Colorant{T,N}` type. For parametric Color types
it _always_ has the desired element type (e.g., `Float32`), so it's safe to
dispatch on `Cdest <: Colorant{T}`.
- `Odest` and `Osrc` are opaque `Color` subtypes, i.e., things like `RGB` or
`HSV`. They have no element type.
- `c` is the `Colorant` object you wish to convert.
- `alpha`, if present, is a user-supplied alpha value (to be used in place of
any default alpha or alpha present in `c`).
The original motivation for this arrangement was that Julia "did not" support
"triangular dispatch", e.g.,
```
convert(::Type{C{T}}, c) where {C, T}
```
On Julia v0.6 or later, parameter constraints can refer to previous parameters.
Threfore, we can use:
```
convert(::Type{C}, c) where {T, C <: Colorant{T}}
```
However, the example above does not match `convert(RGB, c)`. Also, we should
catch all the various alpha variants (e.g. `ARGB`/`RGBA` with/without element
type).
The various arguments of `_convert` "peel off" element types (or guarantee them)
so that comparisons may be made via dispatch. Therefore, this arrangement is
still helpful.
Note that ColorTypes handles the cases where `Odest == Osrc`, or they are both
subtypes of `AbstractRGB` or `AbstractGray`. Therefore, here we only have to
deal with conversions between different spaces.
=#

function ColorTypes._convert(::Type{Cdest}, ::Type{Odest}, ::Type{Osrc}, p, alpha=alpha(p)) where {Cdest<:TransparentColor,Odest,Osrc}
# Convert the base color
c = cnvt(color_type(Cdest), color(p))
# Append the alpha
ColorTypes._convert(Cdest, Odest, Odest, c, alpha)
end
function ColorTypes._convert(::Type{Cdest}, ::Type{Odest}, ::Type{Osrc}, p) where {Cdest<:TransparentColor,Odest,Osrc}
c = cnvt(color_type(Cdest), color(p))
ColorTypes._convert(Cdest, Odest, Odest, c, alpha(p))
end

ColorTypes._convert(::Type{Cdest}, ::Type{Odest}, ::Type{Osrc}, c) where {Cdest<:Color,Odest,Osrc} = cnvt(Cdest, c)

Expand Down Expand Up @@ -188,10 +190,7 @@ cnvt(::Type{CV}, c::LCHab) where {CV<:AbstractRGB} = cnvt(CV, convert(Lab{eltyp
cnvt(::Type{CV}, c::LCHuv) where {CV<:AbstractRGB} = cnvt(CV, convert(Luv{eltype(c)}, c))
cnvt(::Type{CV}, c::Color3) where {CV<:AbstractRGB} = cnvt(CV, convert(XYZ{eltype(c)}, c))

function cnvt(::Type{CV}, c::AbstractGray) where CV<:AbstractRGB
g = convert(eltype(CV), gray(c))
CV(g, g, g)
end
# AbstractRGB --> AbstractGray conversions are implemented in ColorTypes.jl


# Everything to HSV
Expand Down Expand Up @@ -735,51 +734,15 @@ end

cnvt(::Type{YCbCr{T}}, c::Color3) where {T} = cnvt(YCbCr{T}, convert(RGB{T}, c))

# Everything to RGB24
# -------------------

convert(::Type{RGB24}, c::RGB24) = c
convert(::Type{RGB24}, c::AbstractRGB{N0f8}) = RGB24(red(c), green(c), blue(c))
function convert(::Type{RGB24}, c::AbstractRGB)
u = (reinterpret(N0f8(red(c))) % UInt32)<<16 +
(reinterpret(N0f8(green(c))) % UInt32)<<8 +
reinterpret(N0f8(blue(c))) % UInt32
reinterpret(RGB24, u)
end

convert(::Type{RGB24}, c::Color) = convert(RGB24, convert(RGB{N0f8}, c))

# To ARGB32
# ----------------

convert(::Type{ARGB32}, c::ARGB32) = c
convert(::Type{ARGB32}, c::TransparentColor{CV}) where {CV<:AbstractRGB{N0f8}} =
ARGB32(red(c), green(c), blue(c), alpha(c))
function convert(::Type{ARGB32}, c::TransparentColor)
u = reinterpret(UInt32, convert(RGB24, c)) | (reinterpret(N0f8(alpha(c)))%UInt32)<<24
reinterpret(ARGB32, u)
end
function convert(::Type{ARGB32}, c::Color)
u = reinterpret(UInt32, convert(RGB24, c)) | 0xff000000
reinterpret(ARGB32, u)
end
function convert(::Type{ARGB32}, c::Color, alpha)
u = reinterpret(UInt32, convert(RGB24, c)) | (reinterpret(N0f8(alpha))%UInt32)<<24
reinterpret(ARGB32, u)
end

# To Gray
# -------
# AbstractGray --> AbstractRGB conversions are implemented in ColorTypes.jl, but
# AbstractRGB --> AbstractGray conversions should be implemented here.

# Rec 601 luma conversion
const unsafe_trunc = Base.unsafe_trunc

convert(::Type{Gray{T}}, x::Gray{T}) where {T} = x
convert(::Type{Gray24}, x::Gray24) = x

convert(::Type{G}, x::AbstractGray) where {G<:AbstractGray} = G(gray(x))

function convert(::Type{G}, x::AbstractRGB{T}) where {G<:AbstractGray,T<:Normed}
function cnvt(::Type{G}, x::AbstractRGB{T}) where {G<:AbstractGray,T<:Normed}
TU, Tf = FixedPointNumbers.rawtype(T), floattype(T)
if sizeof(TU) < sizeof(UInt)
val = Tf(0.001)*(299*reinterpret(red(x)) + 587*reinterpret(green(x)) + 114*reinterpret(blue(x)))
Expand All @@ -788,8 +751,7 @@ function convert(::Type{G}, x::AbstractRGB{T}) where {G<:AbstractGray,T<:Normed}
end
return G(reinterpret(T, round(TU, val)))
end
convert(::Type{G}, x::AbstractRGB) where {G<:AbstractGray} =
cnvt(::Type{G}, x::AbstractRGB) where {G<:AbstractGray} =
G(0.299f0*red(x) + 0.587f0*green(x) + 0.114f0*blue(x))

convert(::Type{G}, x::Color) where {G<:AbstractGray} =
convert(G, convert(RGB, x))
cnvt(::Type{G}, x::Color) where {G<:AbstractGray} = convert(G, convert(RGB, x))
6 changes: 0 additions & 6 deletions src/promotions.jl

This file was deleted.

12 changes: 0 additions & 12 deletions test/conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@ using ColorTypes: eltype_default, parametric3
@testset "Conversion" begin
r8(x) = reinterpret(N0f8, x)

# Promotions
a, b = promote(RGB(1,0,0), Gray(0.8))
@test isa(a, RGB{Float64}) && isa(b, RGB{Float64})
a, b = promote(RGBA(1,0,0), Gray(0.8))
@test isa(a, RGBA{Float64}) && isa(b, RGBA{Float64})
a, b = promote(RGBA(1,0,0), GrayA(0.8))
@test isa(a, RGBA{Float64}) && isa(b, RGBA{Float64})
a, b = promote(RGB(1,0,0), GrayA(0.8))
@test isa(a, RGBA{Float64}) && isa(b, RGBA{Float64})
a, b = promote(RGB(1,0,0), AGray(0.8))
@test isa(a, ARGB{Float64}) && isa(b, ARGB{Float64})

# srgb_compand / invert_srgb_compand
@test Colors.srgb_compand(0.5) 0.7353569830524494 atol=eps()
@test Colors.invert_srgb_compand(0.7353569830524494) 0.5 atol=eps()
Expand Down

0 comments on commit 4ef39c6

Please sign in to comment.