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.
Here is the type hierarchy used in ColorTypes:
-
Colorant
is the general term used for any object exported by this package. True colors are calledColor
;TransparentColor
indicates an object that also has alpha-channel information. -
Color{T,3}
is a 3-component color (like RGB = red, green, blue);Color{T,1}
is a 1-component color (i.e., grayscale).AbstractGray{T}
is a typealias forColor{T,1}
. -
Most colors have both
AlphaColor
andColorAlpha
variants; for example,RGB
has bothARGB
andRGBA
. These indicate different underlying storage in memory:AlphaColor
stores the alpha-channel first, then the color, whereasColorAlpha
stores the color first, then the alpha-channel. Storage order can be particularly important for interfacing with certain external libraries (e.g., OpenGL and Cairo). -
To support generic programming,
TransparentColor
constructors always take the alpha channel last, independent of their internal storage order. That is, one usesRGBA(red, green, blue, alpha) ARGB(red, green, blue, alpha) # note alpha is last RGBA(RGB(red, green, blue), alpha) ARGB(RGB(red, green, blue), alpha)
This way you can write code with a generic
C<:Colorant
type and not worry about the proper order for supplying arguments to the constructor. See the traits section for some useful utilities.
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)
.
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.
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
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
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.
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
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
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
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
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
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
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
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.
A color-encoding format used by the NTSC broadcast standard.
struct YIQ{T} <: Color{T,3}
y::T
i::T
q::T
end
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
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
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.
One of the nicest things about this package is that it provides a rich set of trait-functions for working with color types:
-
eltype(c)
extracts the underlying element type, e.g.,Float32
-
length(c)
extracts the number of components (includingalpha
, if present) -
alphacolor(c)
andcoloralpha(c)
convert aColor
to an object with transparency (eitherARGB
orRGBA
, respectively). -
color_type(c)
extracts the opaque (color-only) type of the object (e.g.,RGB{N0f8}
from an object of typeARGB{N0f8}
). -
base_color_type(c)
andbase_colorant_type(c)
extract type information and discard the element type (e.g.,base_colorant_type(ARGB{N0f8})
yieldsARGB
) -
ccolor(Cdest, Csrc)
helps pick a concrete element type for methods where the output may be left unstated, e.g.,convert(RGB, c)
rather thanconvert(RGB{N0f8}, c)
.
All of these methods are individually documented (typically with
greater detail); just type ?ccolor
at the REPL.
-
red
,green
,blue
extract channels fromAbstractRGB
types;gray
extracts the intensity from a grayscale object -
alpha
extracts the alpha channel from anyColorant
object (returning 1 if there is no alpha channel) -
comp1
,comp2
,comp3
,comp4
andcomp5
extract color components in the order expected by the constructor -
hue
extracts the hue from anHSV
-like orLab
-like object -
chroma
extracts the chroma (not the saturation) from aLab
-like object
-
mapc(f, c)
executes the functionf
on each color channel ofc
, returning a new color in the same colorspace. -
reducec(op, v0, c)
returns a single number based on a binary operatorop
across the color channels ofc
.v0
is the initial value. -
mapreducec(f, op, v0, c)
is similar toreducec
except it appliesf
to each color channel before combining values withop
.
In most cases, adding a new color space is quite straightforward:
- Add your new type to
types.jl
, following the model of the other color types; - Add the type to the list of exports in
ColorTypes.jl
; - In the Colors package, add conversions to and from your new colorspace.
In special cases, there may be other considerations:
- For
AbstractRGB
/AbstractGray
types,0
means "black" and1
means "saturated." - If your type has extra fields, check the "Generated code" section of
types.jl
carefully. You may need to define acolorfields
function and/or call@make_alpha
manually.