Skip to content

Instantly share code, notes, and snippets.

@sebastianleonte
Forked from eskriett/GoogleMapDownloader.py
Last active October 31, 2022 17:03
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save sebastianleonte/617628973f88792cd097941220110233 to your computer and use it in GitHub Desktop.
Save sebastianleonte/617628973f88792cd097941220110233 to your computer and use it in GitHub Desktop.
A python script to download high resolution Google map images given a longitude, latitude and zoom level. (Works with Python 3)
#!/usr/bin/python
# GoogleMapDownloader.py
# Created by Hayden Eskriett [http://eskriett.com]
#
# A script which when given a longitude, latitude and zoom level downloads a
# high resolution google map
# Find the associated blog post at: http://blog.eskriett.com/2013/07/19/downloading-google-maps/
import urllib.request
from PIL import Image
import os
import math
class GoogleMapsLayers:
ROADMAP = "v"
TERRAIN = "p"
ALTERED_ROADMAP = "r"
SATELLITE = "s"
TERRAIN_ONLY = "t"
HYBRID = "y"
class GoogleMapDownloader:
"""
A class which generates high resolution google maps images given
a longitude, latitude and zoom level
"""
def __init__(self, lat, lng, zoom=12, layer=GoogleMapsLayers.ROADMAP):
"""
GoogleMapDownloader Constructor
Args:
lat: The latitude of the location required
lng: The longitude of the location required
zoom: The zoom level of the location required, ranges from 0 - 23
defaults to 12
"""
self._lat = lat
self._lng = lng
self._zoom = zoom
self._layer = layer
def getXY(self):
"""
Generates an X,Y tile coordinate based on the latitude, longitude
and zoom level
Returns: An X,Y tile coordinate
"""
tile_size = 256
# Use a left shift to get the power of 2
# i.e. a zoom level of 2 will have 2^2 = 4 tiles
numTiles = 1 << self._zoom
# Find the x_point given the longitude
point_x = (tile_size / 2 + self._lng * tile_size / 360.0) * numTiles // tile_size
# Convert the latitude to radians and take the sine
sin_y = math.sin(self._lat * (math.pi / 180.0))
# Calulate the y coorindate
point_y = ((tile_size / 2) + 0.5 * math.log((1 + sin_y) / (1 - sin_y)) * -(
tile_size / (2 * math.pi))) * numTiles // tile_size
return int(point_x), int(point_y)
def generateImage(self, **kwargs):
"""
Generates an image by stitching a number of google map tiles together.
Args:
start_x: The top-left x-tile coordinate
start_y: The top-left y-tile coordinate
tile_width: The number of tiles wide the image should be -
defaults to 5
tile_height: The number of tiles high the image should be -
defaults to 5
Returns:
A high-resolution Goole Map image.
"""
start_x = kwargs.get('start_x', None)
start_y = kwargs.get('start_y', None)
tile_width = kwargs.get('tile_width', 5)
tile_height = kwargs.get('tile_height', 5)
# Check that we have x and y tile coordinates
if start_x == None or start_y == None:
start_x, start_y = self.getXY()
# Determine the size of the image
width, height = 256 * tile_width, 256 * tile_height
# Create a new image of the size require
map_img = Image.new('RGB', (width, height))
for x in range(0, tile_width):
for y in range(0, tile_height):
url = f'https://mt0.google.com/vt?lyrs={self._layer}&x=' + str(start_x + x) + '&y=' + str(start_y + y) + '&z=' + str(
self._zoom)
current_tile = str(x) + '-' + str(y)
urllib.request.urlretrieve(url, current_tile)
im = Image.open(current_tile)
map_img.paste(im, (x * 256, y * 256))
os.remove(current_tile)
return map_img
def main():
# Create a new instance of GoogleMap Downloader
gmd = GoogleMapDownloader(51.5171, 0.1062, 13, GoogleMapsLayers.SATELLITE)
print("The tile coorindates are {}".format(gmd.getXY()))
try:
# Get the high resolution image
img = gmd.generateImage()
except IOError:
print("Could not generate the image - try adjusting the zoom level and checking your coordinates")
else:
# Save the image to disk
img.save("high_resolution_image.png")
print("The map has successfully been created")
if __name__ == '__main__': main()
@sebastianleonte
Copy link
Author

okay, I went a converted the code into python, here you go:
https://gist.github.com/sebastianleonte/69a5f62220fbf25dca7de86c3b6d23ac

You can go for example to https://mapstyle.withgoogle.com/ or https://snazzymaps.com to create a style and the apply it, like so:

https://mt0.google.com/vt?x=4102&y=2726&z=13&apistyle=s.e%3Ag%7Cp.c%3A%23ff1d2c4d%7C%2Cs.e%3Al%7Cp.v%3Aoff%7C%2Cs.e%3Al.t.f%7Cp.c%3A%23ff8ec3b9%7C%2Cs.e%3Al.t.s%7Cp.c%3A%23ff1a3646%7C%2Cs.t%3A17%7Cs.e%3Ag.s%7Cp.c%3A%23ff4b6878%7C%2Cs.t%3A21%7Cp.v%3Aoff%7C%2Cs.t%3A21%7Cs.e%3Al.t.f%7Cp.c%3A%23ff64779e%7C%2Cs.t%3A20%7Cp.v%3Aoff%7C%2Cs.t%3A18%7Cs.e%3Ag.s%7Cp.c%3A%23ff4b6878%7C%2Cs.t%3A81%7Cs.e%3Ag.s%7Cp.c%3A%23ff334e87%7C%2Cs.t%3A82%7Cs.e%3Ag%7Cp.c%3A%23ff023e58%7C%2Cs.t%3A2%7Cs.e%3Ag%7Cp.c%3A%23ff283d6a%7C%2Cs.t%3A2%7Cs.e%3Al.t.f%7Cp.c%3A%23ff6f9ba5%7C%2Cs.t%3A2%7Cs.e%3Al.t.s%7Cp.c%3A%23ff1d2c4d%7C%2Cs.t%3A40%7Cs.e%3Ag.f%7Cp.c%3A%23ff023e58%7C%2Cs.t%3A40%7Cs.e%3Al.t.f%7Cp.c%3A%23ff3C7680%7C%2Cs.t%3A3%7Cs.e%3Ag%7Cp.c%3A%23ff304a7d%7C%2Cs.t%3A3%7Cs.e%3Al.t.f%7Cp.c%3A%23ff98a5be%7C%2Cs.t%3A3%7Cs.e%3Al.t.s%7Cp.c%3A%23ff1d2c4d%7C%2Cs.t%3A49%7Cs.e%3Ag%7Cp.c%3A%23ff2c6675%7C%2Cs.t%3A49%7Cs.e%3Ag.s%7Cp.c%3A%23ff255763%7C%2Cs.t%3A49%7Cs.e%3Al.t.f%7Cp.c%3A%23ffb0d5ce%7C%2Cs.t%3A49%7Cs.e%3Al.t.s%7Cp.c%3A%23ff023e58%7C%2Cs.t%3A4%7Cs.e%3Al.t.f%7Cp.c%3A%23ff98a5be%7C%2Cs.t%3A4%7Cs.e%3Al.t.s%7Cp.c%3A%23ff1d2c4d%7C%2Cs.t%3A65%7Cs.e%3Ag.f%7Cp.c%3A%23ff283d6a%7C%2Cs.t%3A66%7Cs.e%3Ag%7Cp.c%3A%23ff3a4762%7C%2Cs.t%3A6%7Cs.e%3Ag%7Cp.c%3A%23ff0e1626%7C%2Cs.t%3A6%7Cs.e%3Al.t.f%7Cp.c%3A%23ff4e6d70%7C%2C

@Scriptingunsam
Copy link

Scriptingunsam commented Apr 20, 2020

OH MY GOD! you are awesome! that absolutely made the trick! Solve! Thank you very much!!! @sebastian

okay, I went a converted the code into python, here you go:
https://gist.github.com/sebastianleonte/69a5f62220fbf25dca7de86c3b6d23ac

You can go for example to https://mapstyle.withgoogle.com/ or https://snazzymaps.com to create a style and the apply it, like so:

https://mt0.google.com/vt?x=4102&y=2726&z=13&apistyle=s.e%3Ag%7Cp.c%3A%23ff1d2c4d%7C%2Cs.e%3Al%7Cp.v%3Aoff%7C%2Cs.e%3Al.t.f%7Cp.c%3A%23ff8ec3b9%7C%2Cs.e%3Al.t.s%7Cp.c%3A%23ff1a3646%7C%2Cs.t%3A17%7Cs.e%3Ag.s%7Cp.c%3A%23ff4b6878%7C%2Cs.t%3A21%7Cp.v%3Aoff%7C%2Cs.t%3A21%7Cs.e%3Al.t.f%7Cp.c%3A%23ff64779e%7C%2Cs.t%3A20%7Cp.v%3Aoff%7C%2Cs.t%3A18%7Cs.e%3Ag.s%7Cp.c%3A%23ff4b6878%7C%2Cs.t%3A81%7Cs.e%3Ag.s%7Cp.c%3A%23ff334e87%7C%2Cs.t%3A82%7Cs.e%3Ag%7Cp.c%3A%23ff023e58%7C%2Cs.t%3A2%7Cs.e%3Ag%7Cp.c%3A%23ff283d6a%7C%2Cs.t%3A2%7Cs.e%3Al.t.f%7Cp.c%3A%23ff6f9ba5%7C%2Cs.t%3A2%7Cs.e%3Al.t.s%7Cp.c%3A%23ff1d2c4d%7C%2Cs.t%3A40%7Cs.e%3Ag.f%7Cp.c%3A%23ff023e58%7C%2Cs.t%3A40%7Cs.e%3Al.t.f%7Cp.c%3A%23ff3C7680%7C%2Cs.t%3A3%7Cs.e%3Ag%7Cp.c%3A%23ff304a7d%7C%2Cs.t%3A3%7Cs.e%3Al.t.f%7Cp.c%3A%23ff98a5be%7C%2Cs.t%3A3%7Cs.e%3Al.t.s%7Cp.c%3A%23ff1d2c4d%7C%2Cs.t%3A49%7Cs.e%3Ag%7Cp.c%3A%23ff2c6675%7C%2Cs.t%3A49%7Cs.e%3Ag.s%7Cp.c%3A%23ff255763%7C%2Cs.t%3A49%7Cs.e%3Al.t.f%7Cp.c%3A%23ffb0d5ce%7C%2Cs.t%3A49%7Cs.e%3Al.t.s%7Cp.c%3A%23ff023e58%7C%2Cs.t%3A4%7Cs.e%3Al.t.f%7Cp.c%3A%23ff98a5be%7C%2Cs.t%3A4%7Cs.e%3Al.t.s%7Cp.c%3A%23ff1d2c4d%7C%2Cs.t%3A65%7Cs.e%3Ag.f%7Cp.c%3A%23ff283d6a%7C%2Cs.t%3A66%7Cs.e%3Ag%7Cp.c%3A%23ff3a4762%7C%2Cs.t%3A6%7Cs.e%3Ag%7Cp.c%3A%23ff0e1626%7C%2Cs.t%3A6%7Cs.e%3Al.t.f%7Cp.c%3A%23ff4e6d70%7C%2C

@acrete
Copy link

acrete commented Apr 18, 2021

This works great but is there an easy way to change it so the screenshot is on the 'satellite' view instead of the map?

@sebastianleonte
Copy link
Author

Hi @acrete, I have added a new parameter for the class.

So you can simply do:
gmd = GoogleMapDownloader(51.5171, 0.1062, 13, GoogleMapsLayers.SATELLITE)

Or the layer you want!

@Militoarg
Copy link

As a way of thank you for your help guys I want to share this version that works perfectly fine. Enjoy!

https://gist.github.com/Militoarg/e33a843ed4caed3a60561edb69d75f3d

@r3aper2020
Copy link

Is there a way to get this to collect all the images at a given zoom level for an entire area?

@Anjali1808
Copy link

Why does it always show for me - "Could not generate the image - try adjusting the zoom level and checking your coordinates"?

@farhadinima75
Copy link

farhadinima75 commented Apr 16, 2022

Hi there. @jackhirsh @Anjali1808
I've made an edited gist to download the image with the center of the given lat and long.
And also, the way of sending download request has changed. So images can be downloaded at any zoom and any size without a single problem in 2022.
https://gist.github.com/farhadinima75/c3e73f8d7d9f8d2e452063e611fb9a8c
Have fun :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment