Skip to content

Instantly share code, notes, and snippets.

@sebastianknopf
Created January 12, 2023 18:28
Show Gist options
  • Save sebastianknopf/d1d1819181240e17b6c16ba44f3d6c11 to your computer and use it in GitHub Desktop.
Save sebastianknopf/d1d1819181240e17b6c16ba44f3d6c11 to your computer and use it in GitHub Desktop.
python script to fetch ZXY tiles from map servers
import os
import requests
import math
import zipfile
from optparse import OptionParser
# map server constants
MAP_SERVER_ADDRESS = '[YourMapServer]'
MAP_SERVER_USERNAME = ''
MAP_SERVER_PASSWORD = ''
MAP_SERVER_STYLE = 'default'
MAP_SERVER_IMAGE_EXTENSION = 'jpg'
# create option parser object
opt_parser = OptionParser()
opt_parser.add_option('-z', dest='min_z', help='minimum zoom level value to render', type='int', default=4)
opt_parser.add_option('-Z', dest='max_z', help='maximum zoom level value to load', type='int', default=5)
opt_parser.add_option('-x', dest='min_x', help='minimum longitude value to load', type='float', default=5.5381)
opt_parser.add_option('-X', dest='max_x', help='maximum longitude value to load', type='float', default=15.3711)
opt_parser.add_option('-y', dest='min_y', help='minimum latitude value to load', type='float', default=47.2363)
opt_parser.add_option('-Y', dest='max_y', help='maximum latitude value to load', type='float', default=54.9549)
options, args = opt_parser.parse_args()
# conversion function
def longitude2tile(longitude, zoom):
tile = math.floor((longitude + 180) / 360 * math.pow(2, zoom))
return tile
def latitude2tile(latitude, zoom):
tile = math.floor(
(1 - math.log(math.tan(latitude * math.pi / 180) + 1 / math.cos(latitude * math.pi / 180)) / math.pi) / 2
* math.pow(2, zoom)
)
return tile
# zip a whole directory
def zipdir(path, ziph):
for root, dirs, files in os.walk(path):
for file in files:
ziph.write(os.path.join(root, file),
os.path.relpath(os.path.join(root, file),
os.path.join(path, '..')))
# create output path for file
style_path = './output/{0}'.format(MAP_SERVER_STYLE)
if not os.path.exists(style_path):
os.makedirs(style_path)
# write info file
with open('./output/{0}/info.txt'.format(MAP_SERVER_STYLE), 'w') as file:
file.write(options.min_z)
file.write('\n')
file.write(options.max_z)
file.write('\n')
file.write()
file.write(MAP_SERVER_IMAGE_EXTENSION)
# download all tiles for given area
for z in range(options.min_z, options.max_z + 1):
min_x = longitude2tile(options.min_x, z)
max_x = longitude2tile(options.max_x, z)
delta_x = math.fabs(max_x - min_x)
min_y = min(latitude2tile(options.min_y, z), latitude2tile(options.max_y, z))
max_y = max(latitude2tile(options.min_y, z), latitude2tile(options.max_y, z))
delta_y = math.fabs(max_y - min_y)
print('loading {0} tiles of zoom level {1}'.format(delta_x * delta_y, z))
for x in range(min_x, max_x + 1):
local = './output/{0}/{1}/{2}'.format(MAP_SERVER_STYLE, z, x)
if not os.path.exists(local):
os.makedirs(local)
for y in range(min_y, max_y + 1):
url = '{0}/styles/{1}/{2}/{3}/{4}.{5}'.format(
MAP_SERVER_ADDRESS,
MAP_SERVER_STYLE, z, x, y,
MAP_SERVER_IMAGE_EXTENSION
)
response = requests.get(url, auth=(MAP_SERVER_USERNAME, MAP_SERVER_PASSWORD))
with open('{0}/{1}.{2}'.format(local, y, MAP_SERVER_IMAGE_EXTENSION), 'wb') as file:
file.write(response.content)
# generate zip archive of tile folder
with zipfile.ZipFile('{0}.zip'.format(MAP_SERVER_STYLE), 'w', zipfile.ZIP_DEFLATED) as zf:
zipdir('./output/{0}'.format(MAP_SERVER_STYLE), zf)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment