Skip to content

Commit

Permalink
Merge branch 'master' into jc/mosaicview
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnychen94 authored Apr 8, 2020
2 parents 282de56 + dabb1b4 commit 5f42168
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Graphics = "0.4, 1.0"
MappedArrays = "0.2"
MosaicViews = "0.2"
OffsetArrays = "0.8, 0.9, 0.10, 0.11, 1.0.1"
PaddedViews = "0.4.1, 0.5"
PaddedViews = "0.5.4"
Reexport = "0.2"
Requires = "0.5, 1"
julia = "1"
Expand Down
24 changes: 22 additions & 2 deletions src/ImageCore.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ if !isdefined(ColorTypes, :XRGB)
end

@reexport using MosaicViews
using MappedArrays, PaddedViews, Graphics
@reexport using PaddedViews
using MappedArrays, Graphics
using OffsetArrays # for show.jl
using .ColorTypes: colorant_string
using Colors: Fractional
Expand Down Expand Up @@ -65,7 +66,6 @@ export
permuteddimsview,
rawview,
normedview,
paddedviews,
reinterpretc,
# conversions
# float16,
Expand Down Expand Up @@ -149,6 +149,26 @@ much faster to create, but generally slower to use.
"""
permuteddimsview(A, perm) = Base.PermutedDimsArrays.PermutedDimsArray(A, perm)

# PaddedViews support
# This make sure Colorants as `fillvalue` are correctly filled, for example, let
# `PaddedView(ARGB(0, 0, 0, 0), img)` correctly filled with transparent color even when
# `img` is of eltype `RGB`
function PaddedViews.filltype(::Type{FC}, ::Type{C}) where {FC<:Colorant, C<:Colorant}
# rand(RGB, 4, 4) has eltype RGB{Any} but it isn't a concrete type
# although the consensus[1] is to not make a concrete eltype, this op is needed to make a
# type-stable colorant construction in _filltype without error; there's no RGB{Any} thing
# [1]: https://github.com/JuliaLang/julia/pull/34948
T = eltype(C) === Any ? eltype(FC) : eltype(C)
_filltype(FC, base_colorant_type(C){T})
end
_filltype(::Type{<:Colorant}, ::Type{C}) where {C<:Colorant} = C
_filltype(::Type{FC}, ::Type{C}) where {FC<:Color3, C<:AbstractGray} =
base_colorant_type(FC){promote_type(eltype(FC), eltype(C))}
_filltype(::Type{FC}, ::Type{C}) where {FC<:TransparentColor, C<:AbstractGray} =
alphacolor(FC){promote_type(eltype(FC), eltype(C))}
_filltype(::Type{FC}, ::Type{C}) where {FC<:TransparentColor, C<:Color3} =
alphacolor(C){promote_type(eltype(FC), eltype(C))}

# Support transpose
Base.transpose(a::AbstractMatrix{C}) where {C<:Colorant} = permutedims(a, (2,1))
function Base.transpose(a::AbstractVector{C}) where C<:Colorant
Expand Down
84 changes: 84 additions & 0 deletions test/views.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# some views are in colorchannels.jl
using Colors, FixedPointNumbers, ImageCore, OffsetArrays, Test
using OffsetArrays: IdentityUnitRange
using PaddedViews: filltype

@testset "rawview" begin
a = map(N0f8, rand(3,5))
Expand Down Expand Up @@ -269,6 +270,89 @@ end
out = mosaicview(A, A; npad=2, fillvalue=GrayA(0.), nrow=2) |> collect
@test_reference "references/mosaicviews/4d_transparent_4.png" out by=isequal
end

@testset "PaddedViews" begin
# don't promote to Colorant if it's a numerical array
@test @inferred(filltype(Gray{N0f8}, Float32)) === Float32

# cases that don't promote array eltype:
# * (Number, Colorant)
# * (Gray, Gray)
# * (Gray, Color3)
# * (Color3, Color3)
# * (Color3, TransparentColor)
# * (TransparentColor, TransparentColor)
@test @inferred(filltype(Float32, Gray{N0f8})) == Gray{N0f8}
@test @inferred(filltype(Float32, RGB{N0f8})) == RGB{N0f8}
@test @inferred(filltype(Gray{Float32}, Gray{N0f8})) === Gray{N0f8}
@test @inferred(filltype(Gray{N0f8}, Gray{Float32})) === Gray{Float32}
@test @inferred(filltype(Gray{Float32}, RGB{N0f8})) === RGB{N0f8}
@test @inferred(filltype(Gray{N0f8}, RGB{Float32})) === RGB{Float32}
@test @inferred(filltype(RGB{Float32}, RGB{N0f8})) === RGB{N0f8}
@test @inferred(filltype(RGB{N0f8}, RGB{Float32})) === RGB{Float32}
@test @inferred(filltype(Lab{Float32}, RGB{N0f8})) === RGB{N0f8}
@test @inferred(filltype(RGB{N0f8}, Lab{Float32})) === Lab{Float32}

@test @inferred(filltype(Gray{N0f8}, AGray{Float32})) === AGray{Float32}
@test @inferred(filltype(Gray{Float32}, AGray{N0f8})) === AGray{N0f8}
@test @inferred(filltype(Gray{N0f8}, ARGB{Float32})) === ARGB{Float32}
@test @inferred(filltype(Gray{Float32}, ARGB{N0f8})) === ARGB{N0f8}
@test @inferred(filltype(BGR{N0f8}, ARGB{Float32})) === ARGB{Float32}
@test @inferred(filltype(BGR{Float32}, ARGB{N0f8})) === ARGB{N0f8}
@test @inferred(filltype(AGray{N0f8}, ARGB{Float32})) === ARGB{Float32}
@test @inferred(filltype(AGray{Float32}, ARGB{N0f8})) === ARGB{N0f8}

# cases that promote both colorant type and storage type
# * (Color3, Gray)
# * (TransparentColor, Colorant)
@test @inferred(filltype(RGB{N0f8}, Gray{Float32})) === RGB{Float32}
@test @inferred(filltype(RGB{Float32}, Gray{N0f8})) === RGB{Float32}
@test @inferred(filltype(Lab{Float32}, Gray{N0f8})) === Lab{Float32}
@test @inferred(filltype(Lab{Float32}, Gray{Float64})) === Lab{Float64}

@test @inferred(filltype(AGray{N0f8}, Gray{Float32})) === AGray{Float32}
@test @inferred(filltype(AGray{Float32}, Gray{N0f8})) === AGray{Float32}
@test @inferred(filltype(AGray{N0f8}, RGB{Float32})) === ARGB{Float32}
@test @inferred(filltype(AGray{Float32}, RGB{N0f8})) === ARGB{Float32}
@test @inferred(filltype(AGray{N0f8}, Lab{Float32})) === ALab{Float32}
@test @inferred(filltype(AGray{Float64}, Lab{Float32})) === ALab{Float64}

@test @inferred(filltype(ARGB{N0f8}, Gray{Float32})) === ARGB{Float32}
@test @inferred(filltype(ARGB{Float32}, Gray{N0f8})) === ARGB{Float32}
@test @inferred(filltype(ARGB{N0f8}, BGR{Float32})) === ABGR{Float32}
@test @inferred(filltype(ARGB{Float32}, BGR{N0f8})) === ABGR{Float32}
@test @inferred(filltype(ARGB{N0f8}, Lab{Float32})) === ALab{Float32}
@test @inferred(filltype(ARGB{Float64}, Lab{Float32})) === ALab{Float64}


A = Gray{N0f8}[Gray(0.) Gray(0.3); Gray(0.6) Gray(1.)]
fv = Gray{N0f8}(0)
Ap = PaddedView(fv, A, (-1:4, -1:4))
@test eltype(Ap) == Gray{N0f8}
@test @inferred(getindex(Ap, -1, -1)) === fv
@test @inferred(getindex(Ap, 2, 2)) === Gray{N0f8}(1.)
@test Ap[axes(A)...] == A

fv = RGB{Float32}(1., 0., 0.)
Ap = PaddedView(fv, A, (-1:4, -1:4))
@test eltype(Ap) == RGB{Float32}
@test @inferred(getindex(Ap, -1, -1)) === fv
@test @inferred(getindex(Ap, 2, 2)) === RGB{Float32}(1., 1., 1.)
@test Ap[axes(A)...] == RGB{Float32}.(A)

fv = AGray{Float32}(0.5, 0)
Ap = PaddedView(fv, A, (-1:4, -1:4))
@test eltype(Ap) == AGray{Float32}
@test @inferred(getindex(Ap, -1, -1)) === fv
@test @inferred(getindex(Ap, 2, 2)) === AGray{Float32}(1., 1.)
@test Ap[axes(A)...] == AGray{Float32}.(A)

fv = ARGB{Float32}(0.5, 0., 0., 0.)
Ap = PaddedView(fv, A, (-1:4, -1:4))
@test eltype(Ap) == ARGB{Float32}
@test @inferred(getindex(Ap, -1, -1)) === fv
@test @inferred(getindex(Ap, 2, 2)) === ARGB{Float32}(1., 1., 1., 1.)
@test Ap[axes(A)...] == ARGB{Float32}.(A)
end

nothing

0 comments on commit 5f42168

Please sign in to comment.