Our Blog

Offline slippy maps with Open Street Map

Svetoslav Sinyovski
by Svetoslav Sinyovski on Sat 3 November 2012 1 comment

OpenStreetMap

Internet can be expensive these days, especially if you’re a tourist in a foreign country. In situation like this, bringing a map along is a must. Paper maps are an option.. you could also buy software maps. But if you’re by any chance a nerd tourist with some JavaScript coding skill, there’s something a lot more interesting you can do. This reading elaborates on the task of downloading a free Amsterdam area extract from OpenStreetMap.org and viewing it in a browser. To do this, you need to have Java and JTileDownloader. At the time of writing there’s a problem with the latest version 0-6-0 and Java 1.6 and below. If you run into it you could try this solution.

Area extraction from OpenStreetMap

Since zooming a large image is technically difficult slippy maps are split into tiles – small square images grouped in folders. The folders are named after the number of the map zoom level. This could also be imagined as a Z coordinate in 3D space where several maps with different scale overlay progressively from smaller to larger scale. As you zoom in you’re taken to the next map (or the next zoom level). Zoom level folders contain subfolders named after the X coordinate of a tile. And the file name of the tile without its extension represents its Y coordinate in the large map image.

To select the area to extract go to openstreetmap.org and click export, then select the Amsterdam area as shown on the screenshot below.

Downloading the tiles

Create a bbox.xml file in the JTileDownloader folder and copy-paste the following xml there:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="Type">BBoxLatLon</entry>
<entry key="OutputLocation">tiles</entry>
<entry key="TileServer">http://tile.openstreetmap.org</entry>
<entry key="MinLat">52.1655</entry>
<entry key="MaxLat">52.6164</entry>
<entry key="MinLon">4.4673</entry>
<entry key="MaxLon">5.3421</entry>
<entry key="OutputZoomLevel">10,11,12,13,14</entry>
</properties>
 

Open a terminal, cd to the JTileDownloader folder and run this command to start downloading:

java -jar JTileDownloader-0-6-0.jar dl=bbox.xml
 

While JTileDownloader has a GUI I prefer this more static method of inputting the parameters. However you could just double click the executable and try the interface if that works better for you.

Deploying your own Slippy Map

To run the samples you should include the corresponding library in a html file and make sure there is a div with id “map” which has some values set for its CSS width and height properties.

OpenLayers sample code

var map, layer;
function init(){
	map = new OpenLayers.Map({
		div: "map",
		projection: "EPSG:4326",
		fractionalZoom: true
	});
	layer = new OpenLayers.Layer.OSM("OpenStreetMap", "tiles/${z}/${x}/${y}.png", {numZoomLevels: 15});
	map.addLayer(layer);
	map.addControls([
		new OpenLayers.Control.Navigation({dragPanOptions: {enableKinetic: true}}),
		new OpenLayers.Control.Attribution(),
		new OpenLayers.Control.PanZoomBar()
	]);
	map.setCenter(
		new OpenLayers.LonLat(4.899902,52.371198).transform(
			new OpenLayers.Projection("EPSG:4326"),
			map.getProjectionObject()
		), 10
	);
}
 

*the init function could be executed on the body onload event – body onload=”init()”

Leaflet sample code

var map = new L.Map('map', { });

var amsterdam = new L.TileLayer("tiles/{z}/{x}/{y}.png",
{
	layers: 'amsterdam',
	attribution: 'attr',
	minZoom:10,
	maxZoom:14
});

map.addLayer(amsterdam).fitWorld();
map.setView([52.371198, 4.899902],10);
 

Google maps sample code

var element = document.getElementById("map");

var map = new google.maps.Map(element, {
	center: new google.maps.LatLng(52.371198,4.899902),
	zoom: 10,
	mapTypeId: "OSM",
	mapTypeControlOptions: {
		mapTypeIds: ["OSM"]
	}
});

map.mapTypes.set("OSM", new google.maps.ImageMapType({
	getTileUrl: function(coord, zoom) {
		return "tiles/" + zoom + "/" + coord.x + "/" + coord.y + ".png";
	},
	tileSize: new google.maps.Size(256, 256),
	name: "OpenStreetMap",
	maxZoom: 14
}));
 

Bonus – Applying a blur effect with ImageMagick

If we work on a unix based system such as Mac OS we could apply a little bash magick to make some additional adjustments to the images. This doesn’t really improve anything, just shows how to modify a large number of images. Please note it could take a while to process all the tiles of a large map:

#!/bin/bash

find . -regex ".*\.png" -type f > output.txt

grep -o '.*\.' output.txt | while read line; do
    convert $line'png' -blur 0x0.4 -quality 90 $line'jpg'
    rm $line'png'
done
 

Place the above in a cpng.sh file and put the file in the tiles folder. Then run this command from the terminal:

bash cpng.sh
 

The script erases the original png files. If you don’t want this comment out the line:

# rm $line'png'
 

OpenStreetMap.org runs on donations and bulk downloading is discouraged so it’s a good idea to backup your downloaded tiles and use that when possible instead of downloading them again from the OSM servers. Downloading at zoom levels above 16 could get you banned from their servers. There are a number of other tile providers as well.

Where to go from here

If you like Python you should definitely check out Mapnik, the Open Street Map rendering engine. Mapnik can process C++, XML and Python code to style and render text and vector data from sources such as Esri shapefiles and PostgreSQL databases into images. This can be a very difficult task since at the time of writing documentation is scarce and some components for the software are difficult to install. A much more user friendly solution exists – TileMill. Instead of using full blown programming languages styling is done via CartoCSS and the user interface really helps a lot as well. You may still need some scripting to extract tiles from the .mbtiles format (which is essentially an SQLite3 database) and will most certainly need a lot of time to style a map.

For a deep dive into OSM technologies I would recommend checking out this article.

Svetoslav SinyovskiOffline slippy maps with Open Street Map

1 comment

Join the conversation
  • A. A. - Mon 30 January 2017 reply

    THANK YOU! You saved my life! This is the most comprehensive tutorial on how to use Leaflet, in the entire WEB. Hands down.
    Really, many other sites make things really difficult, and you made this in such an easy and understandable way. THANK YOU VERY MUCH!!!!

Join the conversation