<commit_before>#### Types and constructors ####

# Plain arrays can be treated as images. Other types will have
# metadata associated, make yours a child of one of the following:
abstract AbstractImage{T,N} <: AbstractArray{T,N}         # image with metadata
abstract AbstractImageDirect{T,N} <: AbstractImage{T,N}   # each pixel has own value/color
abstract AbstractImageIndexed{T,N} <: AbstractImage{T,N}  # indexed images (i.e., lookup table)

# Direct image (e.g., grayscale, RGB)
type Image{T,N,A<:AbstractArray} <: AbstractImageDirect{T,N}
    data::A
    properties::Dict{ASCIIString,Any}
end
Image(data::AbstractArray, props::Dict) = Image{eltype(data),ndims(data),typeof(data)}(data,props)
Image(data::AbstractArray; kwargs...) = Image(data, kwargs2dict(kwargs))

# Indexed image (colormap)
type ImageCmap{T<:ColorType,N,A<:AbstractArray} <: AbstractImageIndexed{T,N}
    data::A
    cmap::Vector{T}
    properties::Dict{ASCIIString,Any}
end
ImageCmap(data::AbstractArray, cmap::AbstractVector, props::Dict) = ImageCmap{eltype(cmap),ndims(data),typeof(data)}(data, cmap, props)
ImageCmap(data::AbstractArray, cmap::AbstractVector; kwargs...) = ImageCmap(data, cmap, kwargs2dict(kwargs))

# Convenience constructors
grayim(A::AbstractImage) = A
grayim(A::AbstractArray{Uint8,2})  = grayim(reinterpret(Ufixed8, A))
grayim(A::AbstractArray{Uint16,2}) = grayim(reinterpret(Ufixed16, A))
grayim(A::AbstractArray{Uint8,3})  = grayim(reinterpret(Ufixed8, A))
grayim(A::AbstractArray{Uint16,3}) = grayim(reinterpret(Ufixed16, A))
grayim{T}(A::AbstractArray{T,2}) = Image(A; colorspace="Gray", spatialorder=["x","y"])
grayim{T}(A::AbstractArray{T,3}) = Image(A; colorspace="Gray", spatialorder=["x","y","z"])

colorim(A::AbstractImage) = A
function colorim{T}(A::AbstractArray{T,3})
    if size(A, 1) == 4 || size(A, 3) == 4
        error("The array looks like a 4-channel color image. Please specify the colorspace explicitly (e.g. \"ARGB\" or \"RGBA\".)")
    end

    colorim(A, "RGB")
end

function colorim{T}(A::AbstractArray{T,3}, colorspace)
    if 3 <= size(A, 1) <= 4 && 3 <= size(A, 3) <= 4
        error("Both first and last dimensions are of size 3 or 4; impossible to guess which is for color. Use the Image constructor directly.")
    elseif 3 <= size(A, 1) <= 4  # Image as returned by imread for regular 2D RGB images
        if T<:Fractional
            CT = getcolortype(colorspace, eltype(A))
            Image(reinterpret(CT, A); spatialorder=["x","y"])
        else
            Image(A; colorspace=colorspace, colordim=1, spatialorder=["x","y"])
        end
    elseif 3 <= size(A, 3) <= 4  # "Matlab"-style image, as returned by convert(Array, im).
        Image(A; colorspace=colorspace, colordim=3, spatialorder=["y","x"])
    else
        error("Neither the first nor the last dimension is of size 3. This doesn't look like an RGB image.")
    end
end

colorim(A::AbstractArray{Uint8,3})  = colorim(reinterpret(Ufixed8, A))
colorim(A::AbstractArray{Uint16,3}) = colorim(reinterpret(Ufixed16, A))
colorim(A::AbstractArray{Uint8,3},  colorspace) = colorim(reinterpret(Ufixed8, A), colorspace)
colorim(A::AbstractArray{Uint16,3}, colorspace) = colorim(reinterpret(Ufixed16, A), colorspace)


#### Core operations ####

eltype{T}(img::AbstractImage{T}) = T

size(img::AbstractImage) = size(img.data)
size(img::AbstractImage, i::Integer) = size(img.data, i)
size(img::AbstractImage, dimname::String) = size(img.data, dimindex(img, dimname))

ndims(img::AbstractImage) = ndims(img.data)

strides(img::AbstractImage) = strides(img.data)

copy(img::AbstractImage) = deepcopy(img)

# copy, replacing the data
copy(img::AbstractArray, data::AbstractArray) = data

copy(img::AbstractImageDirect, data::AbstractArray) = Image(data, copy(img.properties))

copy(img::AbstractImageIndexed, data::AbstractArray) = ImageCmap(data, copy(img.cmap), copy(img.properties))

copy(img::AbstractImageDirect, _data::AbstractImageDirect) = copy(img, data(_data))

# Provide new data but reuse the properties & cmap
share(img::AbstractArray, data::AbstractArray) = data

share(img::AbstractImageDirect, data::AbstractArray) = Image(data, img.properties)

share(img::AbstractImageIndexed, data::AbstractArray) = ImageCmap(data, img.cmap, img.properties)

# similar
similar(img::AbstractImageDirect) = Image(similar(img.data), copy(img.properties))
similar(img::AbstractImageDirect, ::NTuple{0}) = Image(similar(img.data), copy(img.properties))

similar(img::AbstractImageDirect, dims::Dims) = Image(similar(img.data, dims), copy(img.properties))

similar{T}(img::AbstractImageDirect, ::Type{T}) = Image(similar(img.data, T), copy(img.properties))

similar{T}(img::AbstractImageDirect, ::Type{T}, dims::Dims) = Image(similar(img.data, T, dims), copy(img.properties))

similar(img::AbstractImageIndexed) = ImageCmap(similar(img.data), copy(img.cmap), copy(img.properties))
similar(img::AbstractImageIndexed, ::NTuple{0}) = ImageCmap(similar(img.data), copy(img.cmap), copy(img.properties))

similar(img::AbstractImageIndexed, dims::Dims) = ImageCmap(similar(img.data, dims), copy(img.cmap), copy(img.properties))

similar{T}(img::AbstractImageIndexed, ::Type{T}) = ImageCmap(similar(img.data, T), copy(img.cmap), copy(img.properties))

similar{T}(img::AbstractImageIndexed, ::Type{T}, dims::Dims) = ImageCmap(similar(img.data, T, dims), copy(img.cmap), copy(img.properties))

# copy properties
function copy!(imgdest::AbstractImage, imgsrc::AbstractImage, prop1::ASCIIString, props::ASCIIString...)
    imgdest[prop1] = imgsrc[prop1]
    for p in props
        imgdest[p] = imgsrc[p]
    end
    imgdest
end

# reinterpret: ColorValue->Fractional
reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, img::Vector{CV}) = _reinterpret(T, eltype(CV), img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, img::Array{CV})  = _reinterpret(T, eltype(CV), img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, img::AbstractArray{CV}) = _reinterpret(T, eltype(CV), img)
_reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, ::Type{T}, img::AbstractArray{CV}) =
    reinterpret(T, img, tuple(length(CV), size(img)...))
function _reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, ::Type{T}, img::AbstractImageDirect{CV})
    A = _reinterpret(T, T, data(img))
    props = copy(properties(img))
    props["colorspace"] = colorspace(img)
    props["colordim"] = 1
    Image(A, props)
end
_reinterpret{T,S,CV<:ColorType}(::Type{T}, ::Type{S}, img::AbstractArray{CV}) =
    error("reinterpret cannot change the element type, try reinterpret($S, img)")

# reinterpret: Fractional->ColorValue
# We have to distinguish two forms of call:
#   form 1: reinterpret(RGB, img)
#   form 2: reinterpret(RGB{Ufixed8}, img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, img::Vector{T}) = _reinterpret(CV, eltype(CV), img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, img::Array{T})  = _reinterpret(CV, eltype(CV), img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, img::AbstractArray{T}) = _reinterpret(CV, eltype(CV), img)
_reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, ::Type{Any}, img::AbstractArray{T}) =
    __reinterpret(CV{T}, T, img)   # form 1 (turn into a form 2 call by filling in the element type of the array)
_reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, TT::DataType, img::AbstractArray{T}) =
    __reinterpret(CV, TT, img)    # form 2
__reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, ::Type{T}, img::AbstractArray{T}) =
    reinterpret(CV, img, size(img)[2:end])
__reinterpret{T<:Fractional,CV<:AbstractGray}(::Type{CV}, ::Type{T}, img::AbstractArray{T}) =
    reinterpret(CV, img, size(img))
# In the following, the second argument is the concrete element type of CV
__reinterpret{T<:Fractional,CV<:AbstractGray}(::Type{CV}, ::Type{T}, img::AbstractImageDirect{T}) =<commit_msg>reinterpret: don't add a color dimension for grayscale<commit_after>#### Types and constructors ####

# Plain arrays can be treated as images. Other types will have
# metadata associated, make yours a child of one of the following:
abstract AbstractImage{T,N} <: AbstractArray{T,N}         # image with metadata
abstract AbstractImageDirect{T,N} <: AbstractImage{T,N}   # each pixel has own value/color
abstract AbstractImageIndexed{T,N} <: AbstractImage{T,N}  # indexed images (i.e., lookup table)

# Direct image (e.g., grayscale, RGB)
type Image{T,N,A<:AbstractArray} <: AbstractImageDirect{T,N}
    data::A
    properties::Dict{ASCIIString,Any}
end
Image(data::AbstractArray, props::Dict) = Image{eltype(data),ndims(data),typeof(data)}(data,props)
Image(data::AbstractArray; kwargs...) = Image(data, kwargs2dict(kwargs))

# Indexed image (colormap)
type ImageCmap{T<:ColorType,N,A<:AbstractArray} <: AbstractImageIndexed{T,N}
    data::A
    cmap::Vector{T}
    properties::Dict{ASCIIString,Any}
end
ImageCmap(data::AbstractArray, cmap::AbstractVector, props::Dict) = ImageCmap{eltype(cmap),ndims(data),typeof(data)}(data, cmap, props)
ImageCmap(data::AbstractArray, cmap::AbstractVector; kwargs...) = ImageCmap(data, cmap, kwargs2dict(kwargs))

# Convenience constructors
grayim(A::AbstractImage) = A
grayim(A::AbstractArray{Uint8,2})  = grayim(reinterpret(Ufixed8, A))
grayim(A::AbstractArray{Uint16,2}) = grayim(reinterpret(Ufixed16, A))
grayim(A::AbstractArray{Uint8,3})  = grayim(reinterpret(Ufixed8, A))
grayim(A::AbstractArray{Uint16,3}) = grayim(reinterpret(Ufixed16, A))
grayim{T}(A::AbstractArray{T,2}) = Image(A; colorspace="Gray", spatialorder=["x","y"])
grayim{T}(A::AbstractArray{T,3}) = Image(A; colorspace="Gray", spatialorder=["x","y","z"])

colorim(A::AbstractImage) = A
function colorim{T}(A::AbstractArray{T,3})
    if size(A, 1) == 4 || size(A, 3) == 4
        error("The array looks like a 4-channel color image. Please specify the colorspace explicitly (e.g. \"ARGB\" or \"RGBA\".)")
    end

    colorim(A, "RGB")
end

function colorim{T}(A::AbstractArray{T,3}, colorspace)
    if 3 <= size(A, 1) <= 4 && 3 <= size(A, 3) <= 4
        error("Both first and last dimensions are of size 3 or 4; impossible to guess which is for color. Use the Image constructor directly.")
    elseif 3 <= size(A, 1) <= 4  # Image as returned by imread for regular 2D RGB images
        if T<:Fractional
            CT = getcolortype(colorspace, eltype(A))
            Image(reinterpret(CT, A); spatialorder=["x","y"])
        else
            Image(A; colorspace=colorspace, colordim=1, spatialorder=["x","y"])
        end
    elseif 3 <= size(A, 3) <= 4  # "Matlab"-style image, as returned by convert(Array, im).
        Image(A; colorspace=colorspace, colordim=3, spatialorder=["y","x"])
    else
        error("Neither the first nor the last dimension is of size 3. This doesn't look like an RGB image.")
    end
end

colorim(A::AbstractArray{Uint8,3})  = colorim(reinterpret(Ufixed8, A))
colorim(A::AbstractArray{Uint16,3}) = colorim(reinterpret(Ufixed16, A))
colorim(A::AbstractArray{Uint8,3},  colorspace) = colorim(reinterpret(Ufixed8, A), colorspace)
colorim(A::AbstractArray{Uint16,3}, colorspace) = colorim(reinterpret(Ufixed16, A), colorspace)


#### Core operations ####

eltype{T}(img::AbstractImage{T}) = T

size(img::AbstractImage) = size(img.data)
size(img::AbstractImage, i::Integer) = size(img.data, i)
size(img::AbstractImage, dimname::String) = size(img.data, dimindex(img, dimname))

ndims(img::AbstractImage) = ndims(img.data)

strides(img::AbstractImage) = strides(img.data)

copy(img::AbstractImage) = deepcopy(img)

# copy, replacing the data
copy(img::AbstractArray, data::AbstractArray) = data

copy(img::AbstractImageDirect, data::AbstractArray) = Image(data, copy(img.properties))

copy(img::AbstractImageIndexed, data::AbstractArray) = ImageCmap(data, copy(img.cmap), copy(img.properties))

copy(img::AbstractImageDirect, _data::AbstractImageDirect) = copy(img, data(_data))

# Provide new data but reuse the properties & cmap
share(img::AbstractArray, data::AbstractArray) = data

share(img::AbstractImageDirect, data::AbstractArray) = Image(data, img.properties)

share(img::AbstractImageIndexed, data::AbstractArray) = ImageCmap(data, img.cmap, img.properties)

# similar
similar(img::AbstractImageDirect) = Image(similar(img.data), copy(img.properties))
similar(img::AbstractImageDirect, ::NTuple{0}) = Image(similar(img.data), copy(img.properties))

similar(img::AbstractImageDirect, dims::Dims) = Image(similar(img.data, dims), copy(img.properties))

similar{T}(img::AbstractImageDirect, ::Type{T}) = Image(similar(img.data, T), copy(img.properties))

similar{T}(img::AbstractImageDirect, ::Type{T}, dims::Dims) = Image(similar(img.data, T, dims), copy(img.properties))

similar(img::AbstractImageIndexed) = ImageCmap(similar(img.data), copy(img.cmap), copy(img.properties))
similar(img::AbstractImageIndexed, ::NTuple{0}) = ImageCmap(similar(img.data), copy(img.cmap), copy(img.properties))

similar(img::AbstractImageIndexed, dims::Dims) = ImageCmap(similar(img.data, dims), copy(img.cmap), copy(img.properties))

similar{T}(img::AbstractImageIndexed, ::Type{T}) = ImageCmap(similar(img.data, T), copy(img.cmap), copy(img.properties))

similar{T}(img::AbstractImageIndexed, ::Type{T}, dims::Dims) = ImageCmap(similar(img.data, T, dims), copy(img.cmap), copy(img.properties))

# copy properties
function copy!(imgdest::AbstractImage, imgsrc::AbstractImage, prop1::ASCIIString, props::ASCIIString...)
    imgdest[prop1] = imgsrc[prop1]
    for p in props
        imgdest[p] = imgsrc[p]
    end
    imgdest
end

# reinterpret: ColorValue->Fractional
reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, img::Vector{CV}) = _reinterpret(T, eltype(CV), img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, img::Array{CV})  = _reinterpret(T, eltype(CV), img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, img::AbstractArray{CV}) = _reinterpret(T, eltype(CV), img)
_reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, ::Type{T}, img::AbstractArray{CV}) =
    reinterpret(T, img, length(CV) > 1 ? tuple(length(CV), size(img)...) : size(img))
function _reinterpret{T<:Fractional,CV<:ColorType}(::Type{T}, ::Type{T}, img::AbstractImageDirect{CV})
    A = _reinterpret(T, T, data(img))
    props = copy(properties(img))
    props["colorspace"] = colorspace(img)
    if ndims(A) > ndims(img)
        props["colordim"] = 1
    end
    Image(A, props)
end
_reinterpret{T,S,CV<:ColorType}(::Type{T}, ::Type{S}, img::AbstractArray{CV}) =
    error("reinterpret cannot change the element type, try reinterpret($S, img)")

# reinterpret: Fractional->ColorValue
# We have to distinguish two forms of call:
#   form 1: reinterpret(RGB, img)
#   form 2: reinterpret(RGB{Ufixed8}, img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, img::Vector{T}) = _reinterpret(CV, eltype(CV), img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, img::Array{T})  = _reinterpret(CV, eltype(CV), img)
reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, img::AbstractArray{T}) = _reinterpret(CV, eltype(CV), img)
_reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, ::Type{Any}, img::AbstractArray{T}) =
    __reinterpret(CV{T}, T, img)   # form 1 (turn into a form 2 call by filling in the element type of the array)
_reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, TT::DataType, img::AbstractArray{T}) =
    __reinterpret(CV, TT, img)    # form 2
__reinterpret{T<:Fractional,CV<:ColorType}(::Type{CV}, ::Type{T}, img::AbstractArray{T}) =
    reinterpret(CV, img, size(img)[2:end])
__reinterpret{T<:Fractional,CV<:AbstractGray}(::Type{CV}, ::Type{T}, img::AbstractArray{T}) =
    reinterpret(CV, img, size(img))
# In the following, the second argument is the concrete element type of CV
__reinterpret{T<:Fractional,CV<:AbstractGray}(::Type{CV}, ::Type{T}, img::AbstractImageDirect{T}) =
{'fraction_non_alphanumeric': 0.17453759613551134, 'fraction_numerical': 0.009470539630076909, 'mean_word_length': 6.863068465767117, 'pattern_counts': {'":': 0, '<': 91, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5950093', 'n_tokens_mistral': 5560, 'n_tokens_neox': 5425, 'n_words': 1094}