JuliaGraphics / ColorTypes.jl

Basic color definitions and traits
Other
77 stars 35 forks source link

ColorTypes

Build Status PkgEval codecov.io

This "minimalistic" package serves as the foundation for working with colors in Julia. It defines basic color types and their constructors, and sets up traits and show methods to make them easier to work with.

Of related interest is the Colors.jl package, which provides "colorimetry" and conversion functions for working with colors. You may also be interested in the ColorVectorSpace.jl package, which defines mathematical operations for certain color types. Both of these packages are based on ColorTypes, which ensures that any color objects will be broadly usable.

Types available in ColorTypes

The type hierarchy and abstract types

Here is the type hierarchy used in ColorTypes:

Types

Colors

RGB plus BGR, XRGB, RGBX, and RGB24: the AbstractRGB group

The sRGB colorspace.

struct RGB{T} <: AbstractRGB{T}
    r::T # Red in [0,1]
    g::T # Green in [0,1]
    b::T # Blue in [0,1]
end

RGBs may be defined with two broad number types: AbstractFloat and FixedPoint. FixedPoint types come from the FixedPointNumbers package, and essentially reinterpret "integers" (meaning, the bit-sequences used to represent machine integers) as fractional numbers. For example, N0f8(1) creates a Normed{UInt8,8} (N0f8 for short) number with value equal to 1.0 but which is represented internally with the same bit sequence as 0xff (which is numerically equal to 255). This strategy ensures that 1 always means "saturated color", regardless of whether that value is represented as a Float64 or with just 8 bits. (In the context of image-processing, this unifies "integer images" and "floating-point images" in a common scale.) A bright red color is created with RGB(1, 0, 0), a pale pink with RGB(1, 0.7, 0.7) or its 24-bit variant RGB{N0f8}(1, 0.7, 0.7), and RGB(255, 0, 0) throws an error.

The analogous BGR type is defined as

struct BGR{T} <: AbstractRGB{T}
    b::T
    g::T
    r::T
end

i.e., identical to RGB except in the opposite storage order. One crucial point: for all AbstractRGB types, the constructor accepts values in the order (r,g,b) regardless of how they are arranged internally in memory.

XRGB and RGBX seem exactly like RGB, but internally they insert one extra ("invisible") padding element; when the element type is N0f8, these have favorable memory alignment for interfacing with libraries like OpenGL.

Finally, one may encode an RGB or ARGB color as 8-bit values packed into a 32-bit integer:

struct RGB24 <: AbstractRGB{N0f8}
    color::UInt32
end

struct ARGB32 <: AbstractARGB{N0f8}
    color::UInt32
end

The storage order is 0xAARRGGBB, where RR means the red channel, GG means the green, and BB means the blue. AA means the alpha and is ignored for RGB24. Note that on little-endian machines, contrary to the names, they are stored in memory in BGRA order.

These types can be constructed as RGB24(1.0, 0.5, 0.0), not as RGB24(0xff, 0x80, 0x00) (for an orange #ff8000). However, since these types have no fields named r, g, b, it is better to extract values from an AbstractRGB/TransparentRGB object c using red(c), green(c), blue(c).

HSV

Hue-Saturation-Value. A common projection of RGB to cylindrical coordinates. This is also sometimes called "HSB" for Hue-Saturation-Brightness.

struct HSV{T} <: Color{T,3}
    h::T # Hue in [0,360]
    s::T # Saturation in [0,1]
    v::T # Value in [0,1]
end

For HSV (and all remaining color types), T must be of AbstractFloat type. Due to rounding errors in floating point arithmetic, 360 should also be handled as a valid hue.

HSL

Hue-Saturation-Lightness. Another common projection of RGB to cylindrical coordinates.

struct HSL{T} <: Color{T,3}
    h::T # Hue in [0,360]
    s::T # Saturation in [0,1]
    l::T # Lightness in [0,1]
end

HSI

Hue, saturation, intensity, a variation of HSL and HSV commonly used in computer vision.

struct HSI{T} <: Color{T,3}
    h::T # Hue in [0,360]
    s::T # Saturation in [0,1]
    i::T # Intensity in [0,1]
end

XYZ

The XYZ colorspace standardized by the CIE in 1931, based on experimental measurements of color perception culminating in the CIE standard observer (see Colors.jl's cie_color_match function).

struct XYZ{T} <: Color{T,3}
    x::T
    y::T
    z::T
end

This colorspace is noteworthy because it is linear---values may be added or scaled as if they form a vector space. See further discussion in the ColorVectorSpace.jl package.

xyY

The xyY colorspace is another CIE standardized color space, based directly off of a transformation from XYZ. It was developed specifically because the xy chromaticity space is invariant to the lightness of the patch.

struct xyY{T} <: Color{T,3}
    x::T
    y::T
    Y::T
end

Lab

A perceptually uniform colorspace standardized by the CIE in 1976. See also Luv, the associated colorspace standardized the same year.

struct Lab{T} <: Color{T,3}
    l::T # Lightness in [0,100]
    a::T # Red/Green
    b::T # Blue/Yellow
end

Luv

A perceptually uniform colorspace standardized by the CIE in 1976. See also Lab, a similar colorspace standardized the same year.

struct Luv{T} <: Color{T,3}
    l::T # Lightness in [0,100]
    u::T # Red/Green
    v::T # Blue/Yellow
end

LCHab and LCHuv

The Lab/Luv colorspace reparameterized using cylindrical coordinates.

struct LCHab{T} <: Color{T,3}
    l::T # Lightness in [0,100]
    c::T # Chroma
    h::T # Hue in [0,360]
end

struct LCHuv{T} <: Color{T,3}
    l::T # Lightness in [0,100]
    c::T # Chroma
    h::T # Hue in [0,360]
end

Oklab and Oklch

A perceptually uniform colorspace developed by Björn Ottosson and its reparameterization using cylindrical coordinates.

struct Oklab{T} <: Color{T,3}
    l::T # Lightness in [0,1]
    a::T # Red/Green
    b::T # Blue/Yellow
end

struct Oklch{T} <: Color{T,3}
    l::T # Lightness in [0,1]
    c::T # Chroma
    h::T # Hue in [0,360]
end

DIN99

The DIN99 uniform colorspace as described in the DIN 6176 specification.

struct DIN99{T} <: Color{T,3}
    l::T # L99 (Lightness)
    a::T # a99 (Red/Green)
    b::T # b99 (Blue/Yellow)
end

DIN99d and DIN99o

The DIN99d and DIN99o are revised version of the DIN99. These colorspaces are mainly used to calculate color differences.

struct DIN99d{T} <: Color{T,3}
    l::T # L99d (Lightness)
    a::T # a99d (Red/Green)
    b::T # b99d (Blue/Yellow)
end

struct DIN99o{T} <: Color{T,3}
    l::T # L99o (Lightness)
    a::T # a99o (Red/Green)
    b::T # b99o (Blue/Yellow)
end

LMS

Long-Medium-Short cone response values. Multiple methods of converting to LMS space have been defined. Here the CAT02 chromatic adaptation matrix is used.

struct LMS{T} <: Color{T,3}
    l::T # Long
    m::T # Medium
    s::T # Short
end

Like XYZ, LMS is a linear color space.

YIQ

A color-encoding format used by the NTSC broadcast standard.

struct YIQ{T} <: Color{T,3}
    y::T
    i::T
    q::T
end

Y'CbCr

A color-encoding format common in video and digital photography (also known as Y'UV or simply YUV).

struct YCbCr{T} <: Color{T,3}
    y::T
    cb::T
    cr::T
end

Grayscale "colors"

Gray

Gray is a simple wrapper around a real number, where 0 means black and 1 means white.

struct Gray{T} <: AbstractGray{T}
    val::T
end

In many situations you don't need a Gray wrapper, but there are times when it can be helpful to clarify meaning or assist with dispatching to appropriate methods. It is also present for consistency with the two corresponding grayscale-plus-transparency types, AGray and GrayA.

Gray24 and AGray32

Gray24 is a grayscale value encoded as a UInt32:

struct Gray24 <: AbstractGray{N0f8}
    color::UInt32
end

The storage format is 0xAAIIIIII, where each II (intensity) pair must be identical. The AA is ignored, but in the corresponding AGray32 type it encodes alpha.

Traits (utility functions for instances and types)

One of the nicest things about this package is that it provides a rich set of trait-functions for working with color types:

All of these methods are individually documented (typically with greater detail); just type ?ccolor at the REPL.

Getters

Functions

Extending ColorTypes and Colors

In most cases, adding a new color space is quite straightforward:

In special cases, there may be other considerations: