30
|
1 |
"""
|
|
2 |
Our WSGI web interface, which can serve the JS UI and any .png tiles via HTTP.
|
|
3 |
"""
|
|
4 |
|
|
5 |
from werkzeug import Request, Response, responder
|
|
6 |
from werkzeug import exceptions
|
|
7 |
import os.path
|
|
8 |
|
|
9 |
import pypngtile as pt
|
|
10 |
|
|
11 |
DATA_ROOT = os.path.abspath('data')
|
|
12 |
|
|
13 |
IMAGE_CACHE = {}
|
|
14 |
|
|
15 |
TILE_WIDTH = 256
|
|
16 |
TILE_HEIGHT = 256
|
|
17 |
|
|
18 |
def image_view (req, image_path, image) :
|
|
19 |
image_name = os.path.basename(image_path)
|
|
20 |
|
|
21 |
return """\
|
|
22 |
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
|
23 |
<head>
|
|
24 |
<title>%(title)s</title>
|
|
25 |
<script src="%(prefix)s/static/prototype.js" type="text/javascript"></script>
|
|
26 |
<script src="%(prefix)s/static/dragdrop.js" type="text/javascript"></script>
|
|
27 |
<script src="%(prefix)s/static/builder.js" type="text/javascript"></script>
|
|
28 |
<script src="%(prefix)s/static/tiles2.js" type="text/javascript"></script>
|
|
29 |
<link rel="Stylesheet" type="text/css" href="%(prefix)s/static/style.css">
|
|
30 |
</head>
|
|
31 |
<body>
|
|
32 |
<div id="wrapper">
|
|
33 |
<div id="viewport" style="width: 100%%; height: 100%%">
|
|
34 |
<div class="substrate"></div>
|
|
35 |
</div>
|
|
36 |
</div>
|
|
37 |
|
|
38 |
<script type="text/javascript">
|
|
39 |
var tile_source = new Source("%(tile_url)s", %(tile_width)d, %(tile_height)d, 0, 0);
|
|
40 |
var main = new Viewport(tile_source, "viewport");
|
|
41 |
</script>
|
|
42 |
</body>
|
|
43 |
</html>""" % dict(
|
|
44 |
title = image_name,
|
|
45 |
prefix = os.path.dirname(req.script_root).rstrip('/'),
|
|
46 |
tile_url = req.url,
|
|
47 |
|
|
48 |
tile_width = TILE_WIDTH,
|
|
49 |
tile_height = TILE_HEIGHT,
|
|
50 |
)
|
|
51 |
|
|
52 |
def render_tile (image, x, y) :
|
|
53 |
return image.tile_mem(TILE_WIDTH, TILE_HEIGHT, x, y)
|
|
54 |
|
|
55 |
def handle_main (req) :
|
|
56 |
# path to image
|
|
57 |
image = req.path.lstrip('/')
|
|
58 |
|
|
59 |
# check a .png filename was given
|
|
60 |
if not image or not image.endswith('.png') :
|
|
61 |
raise exceptions.BadRequest("no .png path given")
|
|
62 |
|
|
63 |
# build absolute path
|
|
64 |
image_path = os.path.abspath(os.path.join(DATA_ROOT, image))
|
|
65 |
|
|
66 |
# ensure the path points inside the data root
|
|
67 |
if not image_path.startswith(DATA_ROOT) :
|
|
68 |
raise exceptions.NotFound(image)
|
|
69 |
|
|
70 |
# get Image object
|
|
71 |
if image_path in IMAGE_CACHE :
|
|
72 |
# get from cache
|
|
73 |
image = IMAGE_CACHE[image_path]
|
|
74 |
|
|
75 |
else :
|
|
76 |
# ensure exists
|
|
77 |
if not os.path.exists(image_path) :
|
|
78 |
raise exceptions.NotFound(image)
|
|
79 |
|
|
80 |
# cache
|
|
81 |
image = IMAGE_CACHE[image_path] = pt.Image(image_path)
|
|
82 |
|
|
83 |
# what view?
|
|
84 |
if not req.args :
|
|
85 |
# viewport
|
|
86 |
return Response(image_view(req, image_path, image), content_type="text/html")
|
|
87 |
|
|
88 |
elif 'x' in req.args and 'y' in req.args :
|
|
89 |
# tile
|
|
90 |
x = int(req.args['x'])
|
|
91 |
y = int(req.args['y'])
|
|
92 |
|
|
93 |
# yay render
|
|
94 |
return Response(render_tile(image, x, y), content_type="image/png")
|
|
95 |
|
|
96 |
else :
|
|
97 |
raise exceptions.BadRequest("Unknown args")
|
|
98 |
|
|
99 |
|
|
100 |
@responder
|
|
101 |
def application (env, start_response) :
|
|
102 |
req = Request(env, start_response)
|
|
103 |
|
|
104 |
try :
|
|
105 |
return handle_main(req)
|
|
106 |
|
|
107 |
except exceptions.HTTPException, e :
|
|
108 |
return e
|
|
109 |
|