├── gmap.png ├── gmap_utils.py ├── README.markdown ├── merge_tiles.py └── download_tiles.py /gmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/gmap_tiles/master/gmap.png -------------------------------------------------------------------------------- /gmap_utils.py: -------------------------------------------------------------------------------- 1 | # http://oregonarc.com/2011/02/command-line-tile-cutter-for-google-maps-improved/ 2 | # http://media.oregonarc.com/fish/tile.py 3 | 4 | import math 5 | 6 | def latlon2px(z,lat,lon): 7 | x = 2**z*(lon+180)/360*256 8 | y = -(.5*math.log((1+math.sin(math.radians(lat)))/(1-math.sin(math.radians(lat))))/math.pi-1)*256*2**(z-1) 9 | return x,y 10 | 11 | def latlon2xy(z,lat,lon): 12 | x,y = latlon2px(z,lat,lon) 13 | x = int(x/256)#,int(x%256) 14 | y = int(y/256)#,int(y%256) 15 | return x,y 16 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | ### Download Google Maps tiles 2 | 3 | Edit `download_tiles.py` to specify the area and the zoom level you want. 4 | 5 | zoom = 15 6 | 7 | lat_start, lon_start = 46.53, 6.6 8 | lat_stop, lon_stop = 46.49, 6.7 9 | 10 | satellite = True # roads if false 11 | 12 | You can easily find coordinates with [https://getlatlong.net/](https://getlatlong.net/). 13 | 14 | Then, run `$ python download_tiles.py` and get individual tiles: 15 | 16 | ... 17 | 15_16989_11588_s.jpg 18 | 15_16989_11589_s.jpg 19 | 15_16989_11590_s.jpg 20 | ... 21 | 22 | ### Merge Google Maps tiles 23 | 24 | Edit `merge_tiles.py` to specify the area and the zoom level you want, it's just the same as before. 25 | 26 | zoom = 15 27 | 28 | lat_start, lon_start = 46.53, 6.6 29 | lat_stop, lon_stop = 46.49, 6.7 30 | 31 | satellite = True # roads if false 32 | 33 | Then, run `$ python merge_tiles.py` and get `map_s.jpg` for satellite or `map_r.png` for roads. 34 | 35 | ![Google Maps Tiles](https://raw.github.com/nst/gmap_tiles/master/gmap.png) 36 | 37 | Note: merging the tiles requires [Python Image Library](http://www.pythonware.com/products/pil/). 38 | 39 | ### Swiss Topo Tiles 40 | 41 | You can do the same with Swiss Topo maps: [https://www.github.com/nst/swiss_topo_tiles](https://www.github.com/nst/swiss_topo_tiles). 42 | -------------------------------------------------------------------------------- /merge_tiles.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | import sys, os 3 | from gmap_utils import * 4 | 5 | def merge_tiles(zoom, lat_start, lat_stop, lon_start, lon_stop, satellite=True): 6 | 7 | TYPE, ext = 'r', 'png' 8 | if satellite: 9 | TYPE, ext = 's', 'jpg' 10 | 11 | x_start, y_start = latlon2xy(zoom, lat_start, lon_start) 12 | x_stop, y_stop = latlon2xy(zoom, lat_stop, lon_stop) 13 | 14 | print "x range", x_start, x_stop 15 | print "y range", y_start, y_stop 16 | 17 | w = (x_stop - x_start) * 256 18 | h = (y_stop - y_start) * 256 19 | 20 | print "width:", w 21 | print "height:", h 22 | 23 | result = Image.new("RGBA", (w, h)) 24 | 25 | for x in xrange(x_start, x_stop): 26 | for y in xrange(y_start, y_stop): 27 | 28 | filename = "%d_%d_%d_%s.%s" % (zoom, x, y, TYPE, ext) 29 | 30 | if not os.path.exists(filename): 31 | print "-- missing", filename 32 | continue 33 | 34 | x_paste = (x - x_start) * 256 35 | y_paste = h - (y_stop - y) * 256 36 | 37 | try: 38 | i = Image.open(filename) 39 | except Exception, e: 40 | print "-- %s, removing %s" % (e, filename) 41 | trash_dst = os.path.expanduser("~/.Trash/%s" % filename) 42 | os.rename(filename, trash_dst) 43 | continue 44 | 45 | result.paste(i, (x_paste, y_paste)) 46 | 47 | del i 48 | 49 | result.save("map_%s.%s" % (TYPE, ext)) 50 | 51 | if __name__ == "__main__": 52 | 53 | zoom = 15 54 | 55 | lat_start, lon_start = 46.53, 6.6 56 | lat_stop, lon_stop = 46.49, 6.7 57 | 58 | merge_tiles(zoom, lat_start, lat_stop, lon_start, lon_stop, satellite=True) 59 | -------------------------------------------------------------------------------- /download_tiles.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import urllib2 4 | import os, sys 5 | from gmap_utils import * 6 | 7 | import time 8 | import random 9 | 10 | def download_tiles(zoom, lat_start, lat_stop, lon_start, lon_stop, satellite=True): 11 | 12 | start_x, start_y = latlon2xy(zoom, lat_start, lon_start) 13 | stop_x, stop_y = latlon2xy(zoom, lat_stop, lon_stop) 14 | 15 | print "x range", start_x, stop_x 16 | print "y range", start_y, stop_y 17 | 18 | user_agent = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1' 19 | headers = { 'User-Agent' : user_agent } 20 | 21 | for x in xrange(start_x, stop_x): 22 | for y in xrange(start_y, stop_y): 23 | 24 | url = None 25 | filename = None 26 | 27 | if satellite: 28 | url = "http://khm1.google.com/kh?v=87&hl=en&x=%d&y=%d&z=%d" % (x, y, zoom) 29 | filename = "%d_%d_%d_s.jpg" % (zoom, x, y) 30 | else: 31 | url = "http://mt1.google.com/vt/lyrs=h@162000000&hl=en&x=%d&s=&y=%d&z=%d" % (x, y, zoom) 32 | filename = "%d_%d_%d_r.png" % (zoom, x, y) 33 | 34 | if not os.path.exists(filename): 35 | 36 | bytes = None 37 | 38 | try: 39 | req = urllib2.Request(url, data=None, headers=headers) 40 | response = urllib2.urlopen(req) 41 | bytes = response.read() 42 | except Exception, e: 43 | print "--", filename, "->", e 44 | sys.exit(1) 45 | 46 | if bytes.startswith(""): 47 | print "-- forbidden", filename 48 | sys.exit(1) 49 | 50 | print "-- saving", filename 51 | 52 | f = open(filename,'wb') 53 | f.write(bytes) 54 | f.close() 55 | 56 | time.sleep(1 + random.random()) 57 | 58 | if __name__ == "__main__": 59 | 60 | zoom = 15 61 | 62 | lat_start, lon_start = 46.53, 6.6 63 | lat_stop, lon_stop = 46.49, 6.7 64 | 65 | download_tiles(zoom, lat_start, lat_stop, lon_start, lon_stop, satellite=True) 66 | --------------------------------------------------------------------------------