A colour is three numbers
A screen makes every colour by mixing red, green and blue light, so a computer stores a colour as three numbers. This is called RGB colour.
In this lesson you read colours as numbers, write them in hex, and blend one colour over another so that a shape can be see-through.
By the end of this lesson
Note
I can mix colours as numbers and blend one colour over another with alpha transparency.
Key words
| Word | What it means | Example |
|---|---|---|
| RGB | a colour as red, green and blue amounts | |
| Channel | one of the three numbers, from 0 to 255 | |
| Hex | a colour written in base 16 | #c82828 |
| Alpha | how solid a colour is, 0 clear to 100 solid | |
| Blend | to mix two colours by a weight |
The cells students fill in are left blank in this preview.
Colour mixes red, green and blue light
Each channel is a whole number from 0, none of that light, to 255, all of it. Mixing the three gives every colour a screen can show.
Light adds up, so red and green together make yellow, and all three at full strength make white. All three at 0 is black, because no light comes out.
Worked example: some colours as numbers
| Colour | Red | Green | Blue |
|---|---|---|---|
| Black | 0 | 0 | 0 |
| White | 255 | 255 | 255 |
| Yellow | 255 | 255 | 0 |
| A strong red | 200 | 40 | 40 |
| A mid grey | 128 | 128 | 128 |
The cells students fill in are left blank in this preview.
Hex writes each channel in two characters
Web pages and design tools write a colour in hex, base 16. The digits are 0 to 9 and then a to f, so f means 15.
Each channel becomes two characters. The channel 200 is 12 sixteens and 8 ones: c and 8, so c8. Red 200, green 40 and blue 40 is #c82828.
Turn three channels into hex
docker exec jupyter python3 -c "print((200, 40, 40), '#%02x%02x%02x' % (200, 40, 40))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Alpha says how solid a colour is
Glass tinted red lets some of the scene behind it show through. In graphics that is alpha. We give it as a percentage: 100 is solid, 0 is invisible.
To blend, take a weighted mix of each channel. The top colour counts alpha percent and the colour below counts the rest.
Worked example: red over a dark colour
| Alpha | Red channel | Green channel | Blue channel | Result |
|---|---|---|---|---|
| 0 | 100 | 60 | 20 | (100, 60, 20) |
| 25 | 125 | 55 | 25 | (125, 55, 25) |
| 50 | 150 | 50 | 30 | (150, 50, 30) |
| 100 | 200 | 40 | 40 | (200, 40, 40) |
The cells students fill in are left blank in this preview.
Blend the red channel at four alphas
docker exec jupyter python3 -c "print([(a * 200 + (100 - a) * 100 + 50) // 100 for a in (0, 25, 50, 100)])"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
The blend rule needs the plus 50
The Run prints [100, 125, 150, 200], the red channel column of the table. For each channel the rule is: alpha times top, plus (100 minus alpha) times bottom, plus 50, then // 100.
The 50 makes the division round to the nearest whole number instead of always rounding down.
A common mistake
Warning
Many people think blending two colours means adding their numbers. Adding 200 and 100 gives 300, which is past 255 and has no meaning. A blend is a weighted average: the two weights add up to 100 percent, so the answer always stays between the two inputs.
Fade from blue to red
red = [200, 40, 40]
blue = [40, 40, 200]
# alpha is how much of red shows, as a percentage.
for alpha in [0, 25, 50, 75, 100]:
mixed = []
for channel in range(3):
part = alpha * red[channel] + (100 - alpha) * blue[channel]
mixed.append((part + 50) // 100)
print(alpha, mixed)
# Change red to [255, 255, 0] and press Run. The middle becomes a dull green.
Ask Pillow to blend two pictures
docker exec jupyter python3 -c "from PIL import Image; a = Image.new('RGB', (2, 1), (200, 40, 40)); b = Image.new('RGB', (2, 1), (100, 60, 20)); print(Image.blend(b, a, 0.5).getpixel((0, 0)))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Pillow blends two whole pictures at once
The Run prints (150, 50, 30), the same result as the 50 percent row of the table. Image.blend(b, a, 0.5) mixes two pictures of the same size, half of each.
Pillow takes alpha as a number from 0 to 1, not a percentage. 0.5 here means 50 percent.
Save a blue to red fade
docker exec jupyter python3 -c "from PIL import Image; p = Image.new('RGB', (256, 20)); [p.putpixel((x, y), (x, 0, 255 - x)) for x in range(256) for y in range(20)]; p.save('fade.png'); print(p.getpixel((0, 0)), p.getpixel((255, 0)))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Open fade.png in JupyterLab
The Run prints (0, 0, 255) (255, 0, 0) and saves fade.png. Open it from the file list.
You see a wide thin strip. The left end is pure blue, the right end is pure red, and in between the colour passes through purple.