ColorTypes.jl is a package that defines various data types that represent colors. In practice, there are many ways in which a color can be defined: Red-Green-Blue (RGB), Hue-Saturation-Value (HSV), and so on. Most of the time, a color can be defined using three real numbers. In the case of grayscale, only a single number is required to represent the level of darkness. To support transparent colors, an additional value can be used to store an opacity value. First, let's take a look at the type definitions:
""" `Colorant{T,N}` is the abstract super-type of all types in ColorTypes, and refers to both (opaque) colors and colors-with-transparency (alpha channel) information. `T` is the element type (extractable with `eltype`) and `N` is the number of *meaningful* entries (extractable with `length`), that is, the number of arguments you would supply to the constructor. """ abstract type Colorant{T,N} end
# Colors (without transparency) """ `Color{T,N}` is the abstract supertype for a color (or grayscale) with no transparency. """ abstract type Color{T, N} <: Colorant{T,N} end
""" `AbstractRGB{T}` is an abstract supertype for red/green/blue color types that can be constructed as `C(r, g, b)` and for which the elements can be extracted as `red(c)`, `green(c)`, `blue(c)`. You should *not* make assumptions about internal storage order, the number of fields, or the representation. One `AbstractRGB` color-type, `RGB24`, is not parametric and does not have fields named `r`, `g`, `b`. """ abstract type AbstractRGB{T} <: Color{T,3} end
The Colorant{T,N} type can represent all kinds of colors, with or without transparency. The T parameter represents the type of each individual value in the color definition; for example, Int, Float64, and so on. The N parameter represents the number of values in the color definition, which is usually three.
Color{T,N} is a subtype of Colorant{T,N} and represents non-transparent colors. Finally, AbstractRGB{T} is a subtype of Color{T,N}. Note that the N parameter is no longer needed as a parameter in AbstractRGB{T} because it is already defined with N=3. Now, the concrete parametric type, RGB{T}, is defined as follows:
const Fractional = Union{AbstractFloat, FixedPoint}
""" `RGB` is the standard Red-Green-Blue (sRGB) colorspace. Values of the individual color channels range from 0 (black) to 1 (saturated). If you want "Integer" storage types (for example, 255 for full color), use `N0f8(1)` instead (see FixedPointNumbers). """ struct RGB{T<:Fractional} <: AbstractRGB{T} r::T # Red [0,1] g::T # Green [0,1] b::T # Blue [0,1] RGB{T}(r::T, g::T, b::T) where {T} = new{T}(r, g, b) end
The definition of RGB{T <: Fractional} is fairly straightforward. It contains three values of type T, which can be a subtype of Fractional. Since the Fractional type is defined as a union of AbstractFloat and FixedPoint, the r, g, and b fields may be used as any subtype of AbstractFloat, such as Float64 and Float32, or any of the FixedPoint number types.
If you examine the source code further, you will find that many types are defined in a similar fashion.