Apr 02
downloading google maps tiles using modestmaps
ModestMaps is one the nicest mapping API out there: it just feels right. I especially love the python version, which I used to download some Google Maps tiles (anyone remember gMerge?). The following script gets a Google Maps permalink and downloads the tiles all the way down to the maximum zoom level. You may need to alter the file retrieval and naming logic. The beauty here lies in the fact that ModestMaps allows you to download any layer from many APIs (Google, Virtual Earth, Yahoo Maps and OpenStreetMaps) by changing the Google.AerialProvider() call.
import sys, urllib2, re,os, Image, httplib def parselink(link): qs = link[link.index('?')+1:] vals = [v.split('=') for v in qs.split('&')] params = {} for v in vals: params[v[0]] = v[1] zoom = int(params['z'] or '0') center = map(float, params['ll'].split(',')) span = map(float, params['spn'].split(',')) ne, sw = list(center), list(center) ne[0] += span[0] ne[1] += span[1] sw[0] -= span[0] sw[1] -= span[1] return ne, sw, zoom def fetch(pt): if pt.zoom > Core.Coordinate.MAX_ZOOM: return if download(pt): z = pt.zoomBy(1) fetch(z) fetch(z.right()) fetch(z.down()) fetch(z.down().right()) def download(pt): url = layer.getTileUrls(pt)[0] try: os.makedirs("tiles/%d/%d" % (pt.zoom, pt.row)) except: pass fn = "tiles/%d/%d/%d_%d.jpg" % (pt.zoom, pt.row, pt.row, pt.column) if os.path.exists(fn): try: m = Image.open(fn) a,b,c,d = m.getbbox() return d > 1 except: return False print url try: # should use urllib2 to fake user agent here data = urllib.urlopen(url).read() out = open(fn, 'w') out.write(data) out.close() return True except urllib2.HTTPError, e: if e.code == 404: #empty tile out = Image.new('RGB', (1,1)) out.save(fn) return False #should not reach this point. add better error handling sys.exit(-1) if __name__ == "__main__": sys.path.append('trunk/py/') from ModestMaps import * layer = Google.AerialProvider() bbox = parselink('http://maps.google.com/maps?f=q&hl=en&geocode=&q=new++york,+ny&ie=UTF8&ll=40.75506,-73.969917&spn=0.100907,0.197926&t=h&z=13&iwloc=addr') ne = layer.locationCoordinate(Geo.Location(bbox[0][0], bbox[0][1])).zoomTo(bbox[-1]).container() sw = layer.locationCoordinate(Geo.Location(bbox[1][0], bbox[1][1])).zoomTo(bbox[-1]).container() cur = ne.copy() while cur.row <= sw.row: while cur.column >= sw.column: fetch(cur.copy()) cur = cur.left() cur.column = ne.column cur = cur.down()
Or get the file here








April 20th, 2008 at 9:02 pm
Hi Denis, I discovered ModestMaps reading your blog. And I’m interested on using your script above, but I’m also new at Python. I didn’t have trouble using ModestMaps with Flash, but I think it would be also nice to download the tiles for my city and serve them locally while testing. Could you explain if this script runs on a Web Sever or on a python console application and where do I need to place this file in relation to the modestmaps api.
Thanks for your help,
April 20th, 2008 at 9:16 pm
Hello Leonel,
Try this:
Create a new directory (let’s say its mm). Go in that directory. Checkout ModestMaps from SVN (using svn checkout http://modestmaps.mapstraction.com/svn/trunk )
Run the script above from the mm directory (using the python shell will work). You may want to edit the main (the code in if __name__ == “__main__”) to get different areas.
The sys.path.append call is used to tell Python to look for modules in trunk/py. You can change it to your ModestMaps python path if it’s somewhere else.
Tiles will be stored in the tiles folder (located in the same path from which you started the script)
Let me know if it helps,
Denis
April 20th, 2008 at 10:04 pm
Thanks Denis, for other users. I downloaded Python (2.5) from python.org. Then I downloaded PIL (Python Image Library) from pythonware.com. Installed both and change the sys.path.append parameter to the full path of the py API directory from ModestMaps. This last thing, I guess if for Windows.
The script successfully runs but the image downloaded are “corrupted” many colors appear but no map. Maybe Google did something. I uploaded a sample tile here http://www.leonelgalan.com/mm.jpg.
Thank you for your help.
April 20th, 2008 at 10:20 pm
Did you try using another provider (Yahoo Maps for example)? Just have to change Google.AerialProvider() to Yahoo.AerialProvider()
Let me know
Denis
April 20th, 2008 at 10:36 pm
Yahoo and Microsoft both download images but, they can’t be open with any program. Win XP “Windows Picture Viewer” displays “No Preview Available”.
And when trying with Google Road Provider: I get this links on Python Shell:
http://mt3.google.com/mt?n=404&v=w2.69&x=2038&y=3757&zoom=4
http://mt3.google.com/mt?n=404&v=w2.69&x=4076&y=7514&zoom=3
http://mt0.google.com/mt?n=404&v=w2.69&x=8152&y=15028&zoom=2
http://mt0.google.com/mt?n=404&v=w2.69&x=16304&y=30056&zoom=1
http://mt0.google.com/mt?n=404&v=w2.69&x=32608&y=60112&zoom=0
http://mt2.google.com/mt?n=404&v=w2.69&x=65216&y=120224&zoom=-1
http://mt2.google.com/mt?n=404&v=w2.69&x=130432&y=240448&zoom=-2
The ones with a positive zoom open with QuickTime on my browser (not a standard behavior for jpg), but the ones with a negative zoom give a 404 error.
I really appreciate all your help. I hope this troubleshooting helps other readers as well.
April 21st, 2008 at 11:04 am
Few things:
Don’t know if wordpress escaped the urls correctly but there as HTML entities in your url (replace the & for &)
Zoom levels range from 0 to ~20 (depending on the layer you’re using)
High-res imagery is not available everywhere so you might get 404’s for unpopulated areas.