pngtile.store: change list() to yield name, type tuples rather than appending / to dirs
"""
Image handling.
"""
from werkzeug import Request, Response, exceptions
from werkzeug.utils import html, redirect
import werkzeug.urls
import pngtile.tile
import pngtile.application
import pypngtile
import json
import os, os.path
class ImageApplication (pngtile.application.PNGTileApplication):
STYLESHEETS = (
'https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css',
'https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css',
'http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css',
'/static/pngtile/map.css',
)
SCRIPTS = (
'https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js',
'https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js',
'http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js',
'/static/pngtile/map.js',
)
def __init__ (self, tiles_server=None, **opts):
"""
http://.../ path to tileserver root
"""
super(ImageApplication, self).__init__(**opts)
self.tiles_server = tiles_server
def tiles_url (self, name, **args):
return werkzeug.urls.Href(self.tiles_server)(name, **args)
def render_html (self, title, body, stylesheets=None, scripts=None, end=()):
if stylesheets is None:
stylesheets = self.STYLESHEETS
if scripts is None:
scripts = self.SCRIPTS
return html.html(lang='en', *[
html.head(
html.title(title),
*[
html.link(rel='stylesheet', href=href) for href in stylesheets
]
),
html.body(
*(body + tuple(
html.script(src=src) for src in scripts
) + end)
),
])
def render_dir_breadcrumb (self, name):
href = werkzeug.urls.Href('/')
path = []
yield html.li(html.a(href='/', *[u"Index"]))
if name:
for part in name.split('/'):
path.append(part)
yield html.li(html.a(href=href(*path), *[part]))
def render_dir_item (self, name, type):
if type:
return html.a(href=name, *[name])
else:
dir = name + '/'
return html.a(href=dir, *[dir])
def render_dir (self, request, name, items):
"""
request: werkzeug.Request
name: /.../... url to dir
items: [...] items in dir
"""
if name:
title = name
else:
title = "Index"
return self.render_html(
title = name,
body = (
html.div(class_='container', *[
html.h1(title),
html.div(*[
html.ol(class_='breadcrumb', *self.render_dir_breadcrumb(name)),
]),
html.div(class_='list', *[
html.ul(class_='list-group', *[
html.li(class_='list-group-item', *[
self.render_dir_item(name, type) for name, type in items
]) for name, type in items
]),
]),
]),
),
)
def render_image (self, request, image, name):
"""
request: werkzeug.Request
image: pypngtile.Image
name: request path for .../.../*.png image
"""
image_info = image.info()
map_config = dict(
tiles_url = self.tiles_url(name),
tiles_mtime = image_info['cache_mtime'],
tile_url = '{tiles_url}?t={tiles_mtime}&x={x}&y={y}&zoom={z}',
tile_size = pngtile.tile.TILE_SIZE,
tile_zoom = pngtile.tile.MAX_ZOOM,
# do NOT include a mtime in these urls.. we should always revalidate them
image_url = '{tiles_url}?w={w}&h={h}&x={x}&y={y}&zoom={z}',
image_width = image_info['img_width'],
image_height = image_info['img_height'],
)
return self.render_html(
title = name,
body = (
html.div(id='wrapper', *[
html.div(id='map')
]),
),
end = (
html.script("""$(function() {{ map_init({map_config}); }});""".format(map_config=json.dumps(map_config))),
),
)
def handle_dir (self, request, name, path):
"""
Generate response for directory listing.
"""
if not request.path.endswith('/'):
# we generate HTML with relative links
return redirect(request.path + '/')
items = sorted(self.list(request.path))
html = self.render_dir(request, name, items)
return Response(html, content_type="text/html")
def handle_image (self, request, name, path):
"""
Generate Response for image request.
"""
# backwards-compat redirect from frontend -> tile-server
if all(attr in request.args for attr in ('cx', 'cy', 'w', 'h', 'zl')):
return redirect(self.tiles_url(name,
w = request.args['w'],
h = request.args['h'],
x = request.args['cx'],
y = request.args['cy'],
zoom = request.args['zl'],
))
image, name = self.open(request.path)
html = self.render_image(request, image, name)
return Response(html, content_type="text/html")
def handle (self, request):
"""
Handle request for an image
"""
name, path, type = self.lookup(request.path)
# determine handler
if not type:
return self.handle_dir(request, name, path)
else:
return self.handle_image(request, name, path)
@Request.application
def __call__ (self, request):
"""
WSGI entry point.
"""
try:
return self.handle(request)
except exceptions.HTTPException as error:
return error