User:Stanton/Transparent Hillshading with Mapnik

From OpenStreetMap Wiki
Jump to navigation Jump to search

The approaches for rendering relief maps with Mapnik all have difficulties dealing with areas: The fill of the areas obstructs the relief unless modifications are made to the rendering style. Reducing the opacity of one layer reduces the contrast of the relief. Another approach renders the relief as separate tiles with the hillshading in the alpha channel, which are then overlaid over the map - however, this causes also labels or icons to be darkened by the shadow.

This article develops an approach which avoids all of these: Areas will appear shaded without sacrificing relief contrast but ways, labels and icons will be rendered on top of the relief.


  • You should have read and understood the article on Hillshading with Mapnik - these are the basics and this article is built on top of them. You will also need the software mentioned there and should have carried out all the steps described in the article.
  • You will also need the GeoTIFF utilities from [1]. On Ubuntu 10.10, simply install the geotiff-bin package.
  • Furthermore, you will need ImageMagick (again, available as a package for Ubuntu and probably for many other OSes).

The Approach

The image generated by the hillshade utility is a neutral gray (#B4B4B4) for a flat area. Slopes facing the sun are brightened up while everything "behind" a mountain will be darkened. All this is saved as a GeoTIFF file - a TIFF bitmap with some geography-related information (such as the bounding box) attached to it.

We are going to preserve the light and dark information but replace the "flat gray" background with our map background, consisting of the map's background color and any filled areas. This is achieved by rendering the areas first, then a semitransparent raster layer (containing the light and shadow areas) on top of that, and finally the rest of our map on top of all this.

For the light and shadow layer, we will take the hillshade image and modify it using ImageMagick: For each pixel, the difference to the "flat gray" color is calculated, normalized (using the range of possible values as a reference, not the values actually found) and stored in the alpha channel. Then, a threshold is applied to the image: anything that is brighter than "flat gray" will become pure white (#FFFFFF), anything that is darker will become pure black (#000000).

If displayed on top of a gray background, this image will look like the original relief. Any other background will remain fully visible but get brightened or darkened to reflect the relief of the terrain.

ImageMagick presently does not handle GeoTIFF images - the resulting image will not have the required metadata. We will need to copy that over from the original relief file - this works because the metadata to be copied over is the same. For this purpose we need the GeoTIFF utilities.

Converting the GeoTIFF Files

Take one of the relief files you created as described in Hillshading with Mapnik. I'll assume you are using N45E006_hillshade.tif.

First, extract the GeoTIFF data from the file:

listgeo N45E006_hillshade.tif > N45E006_hillshade.head

Then, transform the file with ImageMagick. This turns out to be somewhat difficult as some apparently straightforward commands give unexpected results. The color space may change from grayscale to RGBA (with some channels valid, others not) for no apparent reason, and in other cases, despite first having selected the alpha channel, the whole alpha channel and nothing but the alpha channel (so help me ImageMagick), everything else gets modified but not the alpha channel. And finally, in some cases all channels just get wiped.

convert N45E006_hillshade.tif -fixme figure_out_how N45E006_overlay_nogeo.tif

Finally, merge the resulting file and the GeoTIFF header:

geotifcp -g N45E006_hillshade.head N45E006_overlay_nogeo.tif N45E006_overlay.tif

Open N45E006_overlay.tif in an image viewer application, setting the background to #B4B4B4 (if possible). It should look just like the relief file you started out with. If you can, change the background color - the relief should remain visible on on top of the new background color.

Now you can delete N45E006_hillshade.head and N45E006_overlay_nogeo.tif - they are no longer needed and can be recreated if you want to repeat these steps.

Rendering the Map

Rearrange your map file:

  • Set the background (or landmass) color to something other than white - a light gray or beige may work well.
  • Move the layers for all areas you want filled and shaded to the top.
  • Place the raster layer(s) right after those.
  • Then add all other layers - ways, icons and labels.

You may want to experiment with bodies of water - these are typically flat and are the only areas which can be rendered on top of the relief. Try both and find out what works best for you.

If you find the light and shadow effect too hard, you can reduce the opacity of the RasterSymbolizer. If you find them too soft, you can either re-run hillshading with the -z parameter set to a higher value and regenerate the overlay as described above, or leave the relief image as is and regenerate the overlays with a slightly modified call to ImageMagick.


The above procedure can be used in many more ways: You can use any of the effects offered by ImageMagick, and instead of the relief file, you can also use the raw elevation data (N45E006_warped.tif) or the output of any of the other PerryGeo tools. For instance, you can use the raw elevation data and a palette effect to represent different altitudes in different colors.