Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for 4-component color types #179

Closed
kimikage opened this issue Apr 8, 2020 · 8 comments
Closed

Support for 4-component color types #179

kimikage opened this issue Apr 8, 2020 · 8 comments

Comments

@kimikage
Copy link
Collaborator

kimikage commented Apr 8, 2020

There has been a request for CMYK support for some time (cf. JuliaGraphics/Colors.jl#264).
IMO, Colors.jl, Images.jl and so on still need some time to properly handle the CMYK colors, so we should not add CMYK to ColorTypes for now.

However, it is good that users can easily define and use 4-component (or 2-component) colors.

It is good to specialize the 3-component or 1-component colors in terms of performance, but at present, they are also specialized in terms of functionalities, i.e. they lack generality.
For example, 4-component colors cannot be shown properly.

# FIXME: handle `Color` and `TransparentColor` correctly
# (e.g. `Color{T,4}` such as CMYK is different from `Transparent3`).
for N = 1:4
component = N >= 3 ? (:comp1, :comp2, :comp3, :alpha) : (:comp1, :alpha)

@kimikage
Copy link
Collaborator Author

kimikage commented Apr 20, 2020

Why doesn't throw_colorerror(and its caller checkval) use the color types directly?

ColorTypes.jl/src/types.jl

Lines 683 to 695 in 4bb8aa9

if length(values) == 1
vstr = "$(values[1]) is an integer"
Tstr = "Gray"
else
vstr = "$values are integers"
if length(values) == 2
Tstr = "AGray"
elseif length(values) == 3
Tstr = "RGB"
else
Tstr = "RGBA"
end
end

Of course, it is just "for example", so it is OK...

julia> ARGB{N0f8}(100,150,200,250) # not RGBA
ERROR: ArgumentError: (100, 150, 200, 250) are integers in the range 0-255, but integer inputs are encoded with the N0f8
  type, an 8-bit type representing 256 discrete values between 0 and 1.
  Consider dividing your input values by 255, for example: RGBA{N0f8}(100/255,150/255,200/255,250/255)
  See the READMEs for FixedPointNumbers and ColorTypes for more information.

cf. #183

@kimikage
Copy link
Collaborator Author

kimikage commented Apr 20, 2020

Anyway, in order to handle types like ACMYK{N0f8}, we need to add a 5-arg checkval.
Since Julia doesn't seem to fully do "horizontal" SIMD optimizations, I think there is room for optimizations.

ColorTypes.jl/src/types.jl

Lines 644 to 652 in 4bb8aa9

@inline function checkval(::Type{T}, a, b) where T<:Normed
isok(T, a) & isok(T, b) || throw_colorerror(T, a, b)
end
@inline function checkval(::Type{T}, a, b, c) where T<:Normed
isok(T, a) & isok(T, b) & isok(T, c) || throw_colorerror(T, a, b, c)
end
@inline function checkval(::Type{T}, a, b, c, d) where T<:Normed
isok(T, a) & isok(T, b) & isok(T, c) & isok(T, d) || throw_colorerror(T, a, b, c, d)
end

@timholy
Copy link
Member

timholy commented Apr 20, 2020

Why doesn't throw_colorerror(and its caller checkval) use the color types directly?

Clearly it should!

@johnnychen94
Copy link
Member

johnnychen94 commented Apr 20, 2020

IMO, Colors.jl, Images.jl and so on still need some time to properly handle the CMYK colors, so we should not add CMYK to ColorTypes for now.

I don't quite get the reason behind, could you please give some further explanation on this? Do you mean adding CMYK to ColorTypes doesn't make it generally a valid input to functions in Colors and Images because it has 4 components?

@kimikage
Copy link
Collaborator Author

In the first place, Colors.jl does not have "practical" conversion methods between CMYK space and other color spaces. I think that CMYK conversion which is not based on color profiles is just a toy. 😄

Do you mean adding CMYK to ColorTypes doesn't make it generally a valid input to functions in Colors and Images because it has 4 components?

At least I don't think that has been fully tested. It is quite possible that there are codes other than the above which interpret the 4-component colors as RGBA or Transparent3 colors. Moreover, TransparentCMYK is a 5-component color.

In order to run such tests, it is important that ColorTypes.jl handles 2-/4-/5-component colors correctly first.

@kimikage
Copy link
Collaborator Author

Tests for show.

using ColorTypes, FixedPointNumbers

# dummy type for testing 2-component color
struct AnaglyphColor{T} <: Color{T,2} # not `TransparentGray`
    left::T; right::T
end
# dummy type for testing 4-component color
struct CMYK{T} <: Color{T,4} # not `Transparent3`
    c::T; m::T; y::T; k::T
end
# dummy type for testing 5-component color
struct ACMYK{T} <: AlphaColor{CMYK{T},T,5}
    alpha::T; c::T; m::T; y::T; k::T
    ACMYK{T}(c, m, y, k, alpha=1) where T = new{T}(alpha, c, m, y, k)
end

iob = IOBuffer()
julia> show(iob, AnaglyphColor{Float32}(0.4, 0.2));

julia> String(take!(iob))
"AnaglyphColor{Float32}(0.4f0,1.0f0)"

julia> ans == "AnaglyphColor{Float32}(0.4f0,0.2f0)"
false

julia> show(iob, CMYK{Float64}(0.1, 0.2, 0.3, 0.4));

julia> String(take!(iob))
"CMYK{Float64}(0.1,0.2,0.3,1.0)"

julia> ans == "CMYK{Float64}(0.1,0.2,0.3,0.4)"
false

julia> show(iob, ACMYK{N0f8}(0.2, 0.4, 0.6, 0.8));
ERROR: MethodError: no method matching show_normed(::Base.GenericIOBuffer{Array{UInt8,1}}, ::ACMYK{Normed{UInt8,8}})

julia> String(take!(iob))
""

julia> ans == "ACMYK{N0f8}(0.2,0.4,0.6,0.8,1.0)"
false

@kimikage
Copy link
Collaborator Author

This is off-topic but... what is this!? 😱

@test String(take!(iob)) == "AGray32{N0f8}(0.8,1.0)"

@kimikage
Copy link
Collaborator Author

kimikage commented Jul 4, 2020

Although there are some problems with promotion rules etc., the original goal was almost achieved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants