Using GDAL2Tiles for overlaying images in Google Maps

For a small personal project, I wanted to overlay a game board onto real-world maps in a small web app. I started by reading and lightly following this tutorial. Initially I downloaded the free version of MapTiler and expected the process to be straightforward. I quickly found out that the highest zoom level for the map tiles was level 4. My game needed a range of 15–20 in zoom. I was left with the option to buy the $30 software, or attempt it via command line. Because this was a quick personal project, I opted to try the command line. The tutorial above gives instructions for Windows machines, my tutorial below is for Macs.

First, let’s brew install that gdal.

brew install gdal

This took some time and when it was done, I received a message to also run a couple more commands. I just copy/pasted those in. You probably won’t need to do those, since I’m sure your python sys.path is pristine.

Then you go to the directory where the file that you are planning on overlaying is. Mine was a .png file because my image had some transparency.

Then I started typing in some commands, following the tutorial linked above, hoping they worked. Here we go.

gdal_translate -of VRT -a_srs EPSG:900913 -gcp 0 0 1106273.110371355 6410544.251192875 -gcp 3200 0 1107037.4806542061 6410544.251192875 -gcp 3200 1850 1107037.48065432061 6410085.6290231645 yourimage.png youmakeupthisname.vrt

What is that mess? This is telling gdal where we want to put our image on the globe. You’ll want to copy everything from gdal_translate to the -gcp, but the numbers after that reflect what you are looking for. There are 3 -gcp. The first represents the top left points on your image and map. The second is the top right poing of the image and map, and the third is the bottom right of the image and map. With those three points, it can derive the fourth.

The “0 0" in the first -gcp reflects the origin point in your image, or top left corner. That is matched with the northwest corner of your map. The two numbers after the “0 0" are the points on the google maps where you want the corner to be. You can find that at the Map Tiler page and by zooming the highest zoom where you want your image to be tiled over. Find the tile that is the most northwest and click on it. The 2 numbers you want are the ones in the first line under “Spherical Mercator (meters).” Repeat for the tiles on the northeast corner and southwest corner.

When you run the command, it’ll tell you the size of your original image. Mine told me “Input file size is 3200, 1850."

Now that you have your .vrt file, you need to turn it into a folder of your .png files for your tiles.

gdal2tiles.py -p mercator -z 12-19 out.vrt

“Mercator” is referencing the Mercator Spherical points that you used in the previous command. Go read about Mercator Projection over on wikipedia if you are into cartography. The -z refers to the level of zoom that you want your images to work for. I chose 12 through 19. 21 is the highest zoom level that Google Maps provides. On my map, if you zoom in between 12 and 19, my image scales perfectly!

That command will give you a directory of files, but they will be named based on the TMS (Tile Map Service) coordinates for the tiles and not the Google ones, which we need because we are using Google Maps.

The tutorial gives a shell script, but there are typos, so I’ll give it here.

#!/bin/sh
for thisPath in `ls -d */*/*`
do
thisFile=${thisPath#*/*/}
oldY=${thisFile%.png}
zoomX=${thisPath%/*}
zoom=${thisPath%/*/*}
newY=$(((1<<zoom) - oldY - 1))
mv ${zoomX}/${oldY}.png ${zoomX}/${newY}.png
done

Make sure it’s executable.

chmod a+x filename.sh

And then run it in the directory.

Now all your tiles are properly named! Go ahead and check them at the Map Tiler page for some peace of mind.

The original tutorial recommends compressing your .png files, but I didn’t. My images weren’t taking too long to load for my needs.

Now to see your tiles over the map, add some stuff your your javascript file:

var yourOverlay = new google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
return ‘yourdirectoryname/’ + zoom + ‘/’ + coord.x + ‘/’ + coord.y + ‘.png’;
},
tileSize: new google.maps.Size(256,256)
});

And go check out what your html file and see your beautiful map!

Click here to see my hexagonal overlay on the Wurzburg Residenz.