flask表单查询经纬度获取瓦片地图并拼接
瓦片服务器:tileserver-gl
启动命令:docker run --rm -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl
1. templates文件
404.html
{% extends "base.html" %}
{% block title %}Map Search - Page Not Found{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Not Found</h1>
</div>
{% endblock %}
500.html
{% extends "base.html" %}
{% block title %}Map Search - Internal Server Error{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Internal Server Error</h1>
</div>
{% endblock %}
base.html
{% extends "bootstrap/base.html" %}
{% block title %}Map Search{% endblock %}
{% block head %}
{{ super() }}
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Map Search</a>
</div>
<div class="navbar-collapse collapse">
{# <ul class="nav navbar-nav">#}
{# <li><a href="/">Home</a></li>#}
{# </ul>#}
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ message }}
</div>
{% endfor %}
{% block page_content %}{% endblock %}
</div>
{% endblock %}
{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}
index.html
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Map Search{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>您好,请输入您要查询的地图经纬度坐标:</h1>
</div>
{{ wtf.quick_form(form) }}
{% endblock %}
2. app.py(主要逻辑)
import math
import os
import re
from flask import Flask, render_template, redirect, url_for
from flask_bootstrap import Bootstrap
from flask_moment import Moment
from flask_wtf import FlaskForm
from wtforms import FloatField, SubmitField
from wtforms.validators import DataRequired
import requests
import PIL.Image as Image
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
bootstrap = Bootstrap(app)
moment = Moment(app)
class QueryForm(FlaskForm):
longitude = FloatField('经度:', validators=[DataRequired()])
latitude = FloatField('纬度:', validators=[DataRequired()])
query = SubmitField('查询')
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
@app.route('/', methods=['GET', 'POST'])
def index():
longitude = None
latitude = None
pic_folder = 'pics'
form = QueryForm()
if form.validate_on_submit():
longitude = form.longitude.data
latitude = form.latitude.data
tile_x, tile_y = deg2num(latitude, longitude)
if not os.path.exists(pic_folder):
os.mkdir(pic_folder)
os.chdir(os.getcwd() + '/' + pic_folder)
get_tiles(tile_x, tile_y)
tiles_path = os.getcwd()
merge_tiles(tiles_path)
return redirect(url_for('index'))
return render_template('index.html', form=form)
def deg2num(lat_deg, lon_deg, zoom=11):
lat_rad = math.radians(lat_deg)
n = 2.0 ** zoom
tile_x = int((lon_deg + 180.0) / 360.0 * n)
tile_y = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
return tile_x, tile_y
def get_tiles(tile_x, tile_y):
count = 0
offset = 2
for y in range(tile_y-offset, tile_y+offset):
for x in range(tile_x-offset, tile_x+offset):
url = 'http://localhost:8080/styles/klokantech-basic/11/{0}/{1}@2x.png'.format(x, y)
print(url)
img = requests.get(url).content
count += 1
img_name = '{0}-{1}-{2}.png'.format(count, x, y)
with open(img_name, 'wb+') as file:
file.write(img)
def merge_tiles(tiles_path):
IMAGE_SIZE = 256
IMAGE_ROW = 4
IMAGE_COLUMN = 4
IMAGE_PATH = tiles_path
image_names = [name for name in os.listdir(IMAGE_PATH)]
# 图片名字格式为'16-1073-718.png',因为每张瓦片图需要按序排列,所以需要按第一个数字排序
re_digits = re.compile(r'(\d+)')
image_names = sorted(image_names, key=lambda s: int(re_digits.split(s)[1]))
to_image = Image.new('RGB', (IMAGE_COLUMN * IMAGE_SIZE, IMAGE_ROW * IMAGE_SIZE))
for y in range(1, IMAGE_ROW + 1):
for x in range(1, IMAGE_COLUMN + 1):
from_image = Image.open(IMAGE_PATH + '/' + image_names[IMAGE_COLUMN * (y - 1) + x - 1]).resize(
(IMAGE_SIZE, IMAGE_SIZE), Image.ANTIALIAS)
print(image_names[IMAGE_COLUMN * (y - 1) + x - 1])
to_image.paste(from_image, ((x - 1) * IMAGE_SIZE, (y - 1) * IMAGE_SIZE))
return to_image.save(IMAGE_PATH + '/final.jpg')
if __name__ == '__main__':
app.run(debug=True)
- 输入经纬度8.5375和47.3790查询,可以得到对应的小瓦片图,合并后效果如下: