Topographic maps use two main elements to visualize terrain: hillshading and contour lines. The hillshading serves as a background and mimics the behavior of sunshine and shadows. The contour lines are superimposed on this background and allow the map reader to estimate the altitude at any point. How the contour lines are superimposed on the hillshading matters for the visual quality of the map. A common goal is that the lines should be easy to see on both dark and bright regions of the hillshading while at the same time not taking too much prominence on the map. Here we will learn what multiply color blending does and why it is a good choice for contour lines on topographic maps.
In the image below we see three different techniques for superimposing contour lines on hillshading.
Different blending modes for contour lines on hillshading. Blending top to bottom: Opaque normal blending, normal blending with transparency (alpha=0.7), multiply blending. Image credits: Swisstopo. Location: Rheinwald valley, Switzerland.
In the first image, the contour lines are put on the hillshading with a constant color independent of the background color. In areas with dark hillshading, the lines are hard to discern from the background.
In the second image, the contour lines are transparently superimposed on the hillshading in the hope that taking the background color into account would improve visibility in dark regions. However, the lines are still hard to see on a dark background.
Finally in the third image, the contour lines are superimposed using what is called multiply color blending. We see that the lines are always clearly visible, both in dark and bright hillshading regions. The darkness of the line adjusts to the darkness of the background color. Multiply blending therefore seems to be the ideal option for contour lines.
Let us now look at how colors are implemented in computers and then go to the math of blending.
A computer screen has a square grid of pixels. In a simplified view, every pixel consists of three LEDs: red (R), green (G), and blue (B). The brightness of the three independent LEDs can be controlled continuously from 0 (fully turned off) to 1 (fully turned on). With this definition, black is RGB = (0, 0, 0), white is RGB = (1, 1, 1), purple is RGB = (0.8, 0, 0.8), etc... Some encodings use integers to represent the color channel values. For example with 8-bit integers, fully on would be 255. But to simplify the equations we discuss later on, we will stick to the normalized color ranges, i.e, 0 to 1.
In applications that consist of multiple visual layers, such as maps, the colors of a layer can blend in different fashions with the colors of the layer beneath. One speaks of different color blending modes.
Let us denote the color of a pixel of the upper layer by RGB, the color of a pixel in the lower layer by RGB, and the resulting color after blending by RGB.
In opaque normal blending, the resulting color is simply given by the upper color:
R = R
G = G
B = B
This is the blending mode that was used to create the first image above.
In this example of opaque normal blending, the background color is varied from RGB = (0.8, 0.8, 0.8) to RGB = (0.4, 0.4, 0.4). The superimposed line color is always RGB = (0.6, 0.6, 0.6). As a result, the line is well visible in the outer background colors, but in the middle, where the background color matches the line color, the line cannot be differentiated anymore from the background.
In a transparent overlay, the upper layer is made semi-transparent and its opacity is called the alpha value A. If A is 0, the upper layer is fully transparent, and if A is 1, the upper layer is fully opaque. The resulting color is given by a linear combination of the upper and lower color:
R = A · R + (1 - A) · R
G = A · G + (1 - A) · G
B = A · B + (1 - A) · B
Alpha blending was used to create the second image above.
In this example of normal blending with transparency, the line color was set to RGB = (0.6, 0.6, 0.6) and the opacity was set to A = 0.7. While this approach results in a non-constant color for different backgrounds, the problem remains that when the background color matches the original line color, the line becomes invisible.
As one might guess by the name, multiply blending uses the product of the upper and lower color:
R = R · R
G = G · G
B = B · B
Since color channel values are never greater than one, multiply blending always results in color channel values that are identical or smaller than the original values, i.e., the color gets darker. This is why the contour lines in the third example are clearly visible on any background.
In this example of multiply blending, the original color of the line was set to RGB = (0.7, 0.7, 0.7). Since multiply blending always results in darker final colors, the line is well visible on any background color.
Multiply blending is a good choice for superimposing contour lines on hillshading because no matter how dark the background is, the line will always be well visible. Using multiply blending in desktop graphics applications such as GIMP or Photoshop is easy and readily available. However, in the realm of web maps, color blending modes other than normal blending with transparency seem much less supported. MapLibre GL JS for example is not able to handle multiply blending.
It might be interesting to investigate where the limitation to normal blending comes from and if more blending modes could be added to MapLibre GL JS in the future. Not only topographic maps with contour lines would benefit from this, but also other visualization use-cases might just look better with more blending options.