Interpolating UIColors

As I was building my (yes, awesome) Animation Engine, Kinieta, I bumped into the problem of color interpolation.

Sounds like an easy problem, animating between two UIColors… but it is not. The issue is that the mathematical properties of color components such as the red, green and blue values, into which colors are usually broken down into, are not always ideal to create intermediate colors that the human eye is going to perceive such.

Color Spaces

Color spaces are like physical spaces, they are the the combination of any number of independent variables, called coordinates. In a platform style arcade game, 2D space is composed by x and y coordinates while 3D space is composed by x, y and z. The RGB Space is similar, it is expressed as red, green and blue coordinate variables.

Any one color within RGB space is a unique combination of these 3 variables. The cube above tries to visualise all possible colors within this space. Notice something interesting: The corners of the cube are highly saturated (i.e. very bright) while the center is a boring gray. For the moment we will accept that this is just the way the space behaves, but think for a moment what happens when we move from one corner to another like for example from red, bottom left, to cyan, top right: We pass from gray, a color that does not look like it should be in the middle of the two. This is not of course catastrophic but can break the illusion of color continuity. Nevertheless, RGB is the most “native” of formats as it emulates the physical properties of light and for this reason there are are literally tiny red, green and blue lights packed closely together in every pixel of the screen. The combination of their intensities is what creates the particular color value that a given pixel takes.

Interpolating in RGB

Let’s start, well.. from the beginning. The native space to most display devices such as computer screens is RGB. So, what we want to do is:

  1. Break the start and end colors into RGB components.
  2. Interpolate between the components for a given number of steps.
  3. Create a new color for every step by recombining the components.

Let’s write an extension that does that.

With this tuple in hand we can use a standard UIColor initialiser:

Based on these tools we can create a spectrum as an array of intermediate UIColor values from (and including) a given color to another.

We just created to operator overloads to facilitate interpolation between our component tuples.

Interpolating in HCL

Hue-Chorma-Luminance is an alternative color space that was intentionally created to “look nice” rather than uphold the physical properties of light or ink (think RGB and CMYK respectively).

To transform RGB components to HCL components is quite expensive and requires a lot of mathematical operations. There is no coding interest in these as they are based on some decimal constants that might make sense an optics specialist.

We will use parts of a 3rd party library called HandyUIKit written by Flinesoft which in turn uses ColorSpaces code written by Tim Wood. The 2 files we need from HandyUIKit is

These provide for transformations between formats. All of these break down colors into a tuple of 4 floats where the 4th is the alpha. We will abstract our UIColor extension to be abstract to the color space when interpolating.

Above we have created a Space enum to specify what color space we are interpolating in. We will start with two colors and create a spectrum in each space: RGB and HCL respectively, and compare the results:

In the 1st row we have RGB interpolation which, as predicted, creates the “boring” greyish hues in the middle which do not look like the belong in a spectrum from “aqua” to “ruby”.

The 2nd row shows HCL interpolation which is closed to what I would consider a series of intermediate values.

We could also animate between them using an interpolation function like a Bezier Curve that I built here.