-
Notifications
You must be signed in to change notification settings - Fork 36
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 alpha(::Number) and ensure alpha/gray return compatible types #177
Conversation
Codecov Report
@@ Coverage Diff @@
## master #177 +/- ##
==========================================
+ Coverage 82.73% 82.75% +0.02%
==========================================
Files 8 8
Lines 753 754 +1
==========================================
+ Hits 623 624 +1
Misses 130 130
Continue to review full report at Codecov.
|
This is off-topic and optional, but see also #162 (comment) |
I added that. There's no performance improvement with these new implementations, but I agree it's a better approach. I also noticed an issue this caused with respect to alpha-constructors, but which was not tested in this package. I caught it by working on ColorVectorSpace; it makes sense to leave this open until that work comes to a conclusion. |
This comment has been minimized.
This comment has been minimized.
Oops. This seems to change the behavior of constructor with Lines 600 to 607 in 4bb8aa9
I think real() is more appropriate there than gray() semantically.
Changing the Therefore, we need to plan on which PR to make the changes to WRT julia> ARGB32(1, 1, 1, Gray(0.5)) # a special case due to the side-effect of inconsistent implementation
ARGB32(1.0N0f8,1.0N0f8,1.0N0f8,0.502N0f8)
julia> ARGB(1, 1, 1, Gray(0.5))
ERROR: MethodError: no method matching ARGB(::Int64, ::Int64, ::Int64, ::Gray{Float64})
julia> AGray{Float32}(1, Gray(0.5))
ERROR: MethodError: no method matching AGray{Float32}(::Int64, ::Gray{Float64}) I don't like to confuse
Is the problem related to this? |
test/types.jl
Outdated
@testset "transparent gray constructors" begin | ||
for x in (1, N0f8(0.5), 0.5f0, 0.5) | ||
T = isa(x, Int) ? N0f8 : typeof(x) | ||
@test @inferred(AGray(x)) === @inferred(AGray(x, 1)) === AGray{T}(x, 1) | ||
@test @inferred(GrayA(x)) === @inferred(GrayA(x, 1)) === GrayA{T}(x, 1) | ||
g = Gray(x) | ||
@test @inferred(AGray(g)) === @inferred(AGray(g, 1)) === AGray{T}(x, 1) | ||
@test @inferred(GrayA(g)) === @inferred(GrayA(g, 1)) === GrayA{T}(x, 1) | ||
end | ||
@test AGray32(Gray(0.5)) === AGray32(Gray(0.5), 1) === AGray32(N0f8(0.5)) === AGray32(N0f8(0.5), 1) === reinterpret(AGray32, 0xff808080) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of adding these tests? The name of the testset above is misleading?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without the change to src/types.jl
above, x = N0f8(0.5); AGray(x, 1)
returns an AGray{Float32}
because promote(x, 1)
chooses Float32
. But with an integer argument we know the only valid settings of alpha
are 0 and 1, so a valid implementation would be to convert it a Bool
first (drawing the error if that fails) and then call promote
. But note that promote(x, true)
chooses N0f8
, so the final type produced is strongly dependent on internal details of the implementation of the constructor.
To me it seems that a more agnostic approach is to first convert alpha
to a supported eltype and then do the promotion. Note that changing the signature of those same two methods to alpha::GrayLike
would circumvent the error you noted in #177 (comment). Though I don't feel strongly that we need to support Gray
values for the alpha channel, making it consistently throw an error would also be OK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I finally got the purpose. 👍 (For such a purpose, I prefer to write the types extensionally, though.)
But with an integer argument we know the only valid settings of
alpha
are 0 and 1
I agree for the most part. However, so far, we have not checked the range of valid values for each "color" component. Actually , we only check the valid range of Normed
"type", so AGray{N1f7}(1, 2)
does not throw errors.
Therefore, I prefer the more agnostic approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel strongly that we need to support
Gray
values for the alpha channel,
I agree. However, it is not only problem with the alpha channel.
julia> RGB{N0f8}(Gray(1), 1, 1)
RGB{N0f8}(1.0,1.0,1.0)
julia> ARGB{N0f8}(Gray(1), 1, 1, 0.5)
ERROR: MethodError: no method matching ARGB{Normed{UInt8,8}}(::Gray{Normed{UInt8,8}}, ::Int64, ::Int64, ::Float64)
"Unfortunately", the possible way to make them consistent may be to enhance the support for GrayLike
, and I support the status quo. 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think it's reasonable to construct an RGB from gray channels, as it is the inverse operation of color separation.
This is now being proposed for merging. |
I don't think there is any problem with this PR, but I am thinking of a radical overhaul of the constructors (cf. #197). I would like to merge PRs with less impacts first. |
Sorry I didn't merge #183. Done now. |
WRT the problem with the eltype promotion (#177 (comment)), I think the following rule (which does not explicitly depend on # the modified version of `promote_eltype()`
@inline function promote_args_type(::Type{C}, alpha::Ta, vals...) where {Ta, C <: TransparentColor}
T = promote_type(map(typeof, vals)...)
if T <: Union{Integer, FixedPoint} && Ta <: Integer
_promote_args_type(eltype_ub(C), eltype_default(C), T)
else
_promote_args_type(eltype_ub(C), eltype_default(C), promote_type(T, Ta))
end
end However, it is difficult to apply the rule consistently in the current constructor methods.Therefore, I think |
This is my oversight, but some tests should be added into "conversions from/to real numbers", "transparent rgb constructors" and so on, as mentioned in #162 (comment), Although the problem is rooted in the lack of consistency in the constructor design, but we need some regression tests to improve the constructors. Of course, we can also add the tests in a separate PR. |
Sure, wherever you want to add the tests is fine with me. Since this PR is late in the scheduled-merge queue, don't worry about conflicts, we can rebase when we get back to this. |
FixedPointNumbers v0.8.2, which includes JuliaMath/FixedPointNumbers.jl#177, was registered. |
FYI, I rewrote the tests for this in #240, so there is a conflict. I think it would be easier to just cherry-pick the changes in src and rewrite the tests. |
Breaking change: yes (conversions that can't be performed will now error)
I ran |
Although the relaxation to |
Note that the behavior of the constructors will be changed again in PR #197. It is not recommended to merge the fixes for this PR's changes into the main branches of the downstream packages. |
PR JuliaGraphics#243 and JuliaGraphics#177 had already fixed the `ones` throwing an exception. This updates the test.
Closes #162. I decided to continue to support any
::Number
as long as it can beconvert
ed to a supported type. Consequently(Not sure if that is worth adding to the tests.) This is consistent with the general philosophy that types are about dispatch and algorithmic efficiency, but that functionality should depend primarily on value.
Breaking change: yes (conversions that can't be performed will now error, and some return values will be of different types).