Let’s do Color & Math
Understanding the formulas of color conversion
At Shazam, we introduced a brand new, visually more appealing way to accommodate ads in the app. This new ad format overtakes the whole screen with a smooth animation. The experience not only looks better, but also feels less interruptive and way more engaging.
Designers tend to think of advertising as a necessary evil. Ads are external content that need real estate on our pixel-perfect, unique design. The UI has colors, the ads have colors. It’s not easy to apply a dozen of them to our interfaces and make them work together. It takes a process of studying color theory and playing around with rules to have confidence and control over what looks and functions well on the screen.
In this case, the ads need to stand out without interrupting the core experience. What we want to achieve here is a tool for third party clients that excludes certain colors from the acceptable mix. A tool that works with a single HEX code as input and tells if a particular color matches our defined criteria. We would like to filter out too light colors that damage usability and washed-out colors that make the experience less desirable. In order to do this, we will need to squeeze out these values from a single HEX code.
Colors are the way our brain, through our eyes, interprets electromagnetic radiation of a wavelength within the visible spectrum. Yum. Visible light lies between 400 and 700 nanometers. Radiation with a wavelength of over 750 nm is called infra-red and radiation under 350 nm is ultra-violet.
A color wheel is really just the spectrum twisted around so that the violet and red ends are joined. This wheel is particularly useful for showing how the colors relate to each other and how you can create new ones by mixing two or more of them.
RGB refers to a system for representing the colors to be used on a computer display. RGB is a combination of Red, Green and Blue. These colors can be combined in various proportions to obtain any color in the visible spectrum.
Each level is measured by the range of decimal numbers from 0 to 255 (256 levels for each color). For example, if a color has zero Blue, it will be a mixture of Red and Green. This means we can generate 256 x 256 x 256 = 16.777.216 different colors with this model.
It is important to note that different devices detect or reproduce a given RGB value differently. An RGB color format is represented by its Red, Green and Blue values, no surprises here:
RGB = (54, 155, 229) | Note: 54 = Red, 155 = Green and 229 = Blue
HEX is a widely known and used format for defining colors on the web. The name comes from the phrase hexadecimal, which is used by humans to shorten binary to a more easily understandable form. Each of the HEX numbers use numbers and letters to represent values between 0–16. Numbers are used for the range 0–9 and letters A, B, C, D, E, F for the range 10–16.
The code itself is a HEX triplet, which represents 3 separate values that specify the levels of the component colors. These 3 values are called bytes and make up a six-digit hexadecimal number used in HTML, CSS, SVG and other computing applications.
The first value pair refers to Red, the second to Green and the third to Blue. One byte represents a number in the range 0 to 255 in decimal notation. In hexadecimal notation, the scale goes from the lowest (00) to the highest (FF) intensity of each color. HEX codes start with a hashtag sign and are followed by the mentioned format:
HEX = #A3D645 | Note: A3 = Red, D6 = Green and 45 = Blue
Conversion between RGB & HEX
We will transform an RGB code into a HEX code. What this truly means is that we need to convert decimal numbers from given RGB values to hexadecimals. In order to do this, we will divide our values by 16.
R / 16 = X1 + Y1G / 16 = X2 + Y2B / 16 = X3 + Y3
In the above mentioned formula, X is called the quotient and Y is the remainder. These two numbers are used to represent the HEX value pair for each particular color, Red, Green and Blue. A HEX code can be calculated from these values as #X1Y1X2Y2X3Y3 where X1Y1 are the values for Red, X2Y2 for Green and X3Y3 for Blue. Let’s have a look at this with the following RGB values: (54, 155, 229)
R = 54 / 16 = 3 + 6G = 155 / 16 = 9 + 11 | Note: 11 = B in hexadecimalB = 229 / 16 = 14 + 5 | Note: 14 = E in hexadecimal
Voila, our code (54, 155, 229) in RGB becomes #369BE5 in HEX
We can also make the conversion work in reverse. In case we would like to transform HEX codes into RGB codes, all we have to do is to multiply the quotients by 16 and add the remainders.
R = X1 x 16 + Y1G = X2 x 16 + Y2B = X3 x 16 + Y3
We already know the quotients (X1, X2, X3) and remainders (Y1, Y2, Y3). A HEX code consists of these values as #X1Y1X2Y2X3Y3. Let’s try converting back our HEX code: #369BE5
R = 3 x 16 + 6 = 54G = 9 x 16 + 11 = 155 | Note: 11 = B in hexadecimalB = 14 x 16 + 5 = 229 | Note: 14 = E in hexadecimal
There we go, our code #369BE5 in HEX becomes (54, 155, 229) in RGB
What do you call friends who like maths?
Keep smiling. We’re off to continue our journey to the world of HSL.
HSL is a common cylindrical coordinate representation of points in an RGB color model. HSL stands for Hue, Saturation and Luminosity. Hue refers to the colour family of the specific color we’re looking at. It indicates the actual dominant color on the RGB color wheel. Luminosity refers to how much white or black is mixed in the color. Saturation indicates the amount of grey in the same color.
Conversion between RGB & HSL
Luminosity (also called brightness, lightness or luminance) stands for the intensity of the energy output of a visible light source. It basically tells how light a color is and is measured on the following scale: L = [0, 1]
It’s time to introduce the maximum and minimum values among our RGB numbers. Max(RGB) stands for the highest and Min(RGB) for the lowest value across Red, Green and Blue. In order to make our further calculations work, we need to convert the RGB values to the range 0–1. This can be done by dividing them by 255. Let’s take our existing RGB values for example: (54, 155, 229)
R = 54 / 255 = 0,212G = 155 / 255 = 0,608B = 229 / 255 = 0,898
The Luminosity of the RGB color (54, 155, 229) can be calculated from the Max(RGB) and Min(RGB) values as follows:
L = (1 / 2) x (Max(RGB) + Min(RGB))
From our R, G and B numbers, R seems to be the smallest and B the largest. We now know the Max(RGB) = B = 0,898 and Min(RGB) = R = 0,212 values.
L = (1 / 2) x (0,898 + 0,212) = 0,555 ~ 56%
Most sources of visible light contain energy over a band of wavelengths. Hue is the wavelength within the visible light spectrum at which the energy output from a source is greatest. It is indicated by its position (in degrees) on the RGB color wheel: H= [0°, 360°]
The formula for Hue depends on how RGB values relate to each other. In other words, it depends on which one represents the Max(RGB) and Min(RGB) values.
(A) If R ≥ G ≥ B | H = 60° x [(G-B)/(R-B)](B) If G > R ≥ B | H = 60° x [2 - (R-B)/(G-B)](C) If G ≥ B > R | H = 60° x [2 + (B-R)/(G-R)](D) If B > G > R | H = 60° x [4 - (G-R)/(B-R)](E) If B > R ≥ G | H = 60° x [4 + (R-G)/(B-G)](F) If R ≥ B > G | H = 60° x [6 - (B-G)/(R-G)]
The Hue of the RGB color (54, 155, 229) can be calculated using the right formula from the pool above. Don’t forget to divide by 255 before going any further.
R = 54 / 255 = 0,212G = 155 / 255 = 0,608B = 229 / 255 = 0,898
B > G > R seems to stand true, our match is (D).
H = 60° x [4 - (0,608-0,212)/(0,898-0,212)] = 205,4°
Saturation is an expression for the relative bandwidth of the visible output from a light source. As saturation increases, colors appear more pure. As saturation decreases, colors appear more washed-out. It is measured on the following scale: S = [0, 1]
The formula for Saturation uses the Min(RGB), Max(RGB) values and Luminosity.
(A) If L < 1 | S = (Max(RGB) — Min(RGB)) / (1 — |2L - 1|)(B) If L = 1 | S = 0
We have calculated the Luminosity before, L = 0,555. Our formula will be (A) as L = 0,555 < 1. We also know Max(RGB) = 0,898 and Min(RGB) = 0,212. We finally have everything we needed for Saturation. Good stuff.
S = (0,898 — 0,212) / (1 — |2 x 0,555 - 1|) = 0,770 ~ 77%
We have successfully calculated Luminosity, Hue and Saturation from a single HEX code
Now we can define our own rules for accepting colors solely relying on a HEX code. For example, we can set a desired range for the Luminosity or exclude certain colors from the color wheel with Hue. With Saturation we can also influence how washed-out or colorful our screens look.
L = 56%H = 205,4°S = 77%
At Shazam we have decided to only accept colors with a Luminosity value smaller than a certain level (excluding too light ones) and changed this rule for a specific spectrum on the color wheel. This way we could get rid of some bright yellows and greens. By using the conversion formulas in a script, we can also build a simple tool that helps with this process.
You can download a sample Colour Picker using these formulas.
Thanks (and claps) to Nikita Kardakov for helping with the code.