|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import print_function, division
|
|
|
|
from argparse import ArgumentParser
|
|
|
|
from imagetile2 import tile_image
|
|
|
|
from PIL import Image
|
|
|
|
import os, json, sys, re, datetime, urlparse
|
|
|
|
from math import ceil, log
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
Maybe a better name for this script is tiling or tiler as it's not particularly leaflet specific.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
def tiles_path_for (n):
|
|
|
|
return n + ".tiles"
|
|
|
|
|
|
|
|
def autolink (text):
|
|
|
|
def sub (m):
|
|
|
|
return u'<a href="{0}">LINK</a>'.format(m.group(0))
|
|
|
|
return re.sub(r"https?://[\S]+", sub, text, re.I)
|
|
|
|
|
|
|
|
def parse8601 (t, fmt=None):
|
|
|
|
""" simple 8601 parser that doesn't care about more than YMDHMS"""
|
|
|
|
# 2016-11-16T14:13:40.379857
|
|
|
|
m = re.search(r"(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d)T(?P<hour>\d\d):(?P<minute>\d\d):(?P<second>\d\d)", t)
|
|
|
|
if m:
|
|
|
|
d = m.groupdict()
|
|
|
|
ret = datetime.datetime(int(d['year']), int(d['month']), int(d['day']), int(d['hour']), int(d['minute']), int(d['second']))
|
|
|
|
if fmt:
|
|
|
|
return ret.strftime(fmt)
|
|
|
|
else:
|
|
|
|
return ret
|
|
|
|
|
|
|
|
class tiles_wrapper (object):
|
|
|
|
""" Image wrapper abstraction... include URL to original + caption
|
|
|
|
"""
|
|
|
|
def __init__(self, path, url=None, text=None, tilename="z{0[z]}y{0[y]}x{0[x]}.png"):
|
|
|
|
self.path = path
|
|
|
|
# self.item = item
|
|
|
|
self.url = url
|
|
|
|
self.text = text
|
|
|
|
self.tilename = tilename
|
|
|
|
|
|
|
|
def get_tile_path (self, z, y, x):
|
|
|
|
return os.path.join(self.path, self.tilename.format({'z':z,'y':y,'x':x}))
|
|
|
|
|
|
|
|
def zoom (self):
|
|
|
|
""" return serialized version of self """
|
|
|
|
node = {}
|
|
|
|
node['zoomable'] = True
|
|
|
|
if self.text:
|
|
|
|
node['text'] = self.text
|
|
|
|
else:
|
|
|
|
# autotext is a link to the url showing the basename
|
|
|
|
_, basename = os.path.split(self.url)
|
|
|
|
node['text'] = u"<a href=\"{0}\">{1}</a>".format(self.url, basename)
|
|
|
|
node['url'] = self.url
|
|
|
|
node['image'] = self.get_tile_path(0, 0, 0)
|
|
|
|
return node
|
|
|
|
|
|
|
|
def zoom_recursive (self, caption, x=0, y=0, z=0, maxzoom=3):
|
|
|
|
""" old style zoom in place -- ie render self to child nodes """
|
|
|
|
node = {}
|
|
|
|
node['text'] = self.text
|
|
|
|
node['image'] = self.get_tile_path(z, y, x)
|
|
|
|
if z < maxzoom:
|
|
|
|
kids = []
|
|
|
|
for r in range(2):
|
|
|
|
for c in range(2):
|
|
|
|
kids.append(self.zoom_recursive(caption, (x*2)+c, (y*2)+r, z+1, maxzoom))
|
|
|
|
node['children'] = kids
|
|
|
|
return node
|
|
|
|
|
|
|
|
def cell_layout(items, w=2):
|
|
|
|
i = 0
|
|
|
|
for r in range(w):
|
|
|
|
for c in range(w):
|
|
|
|
if i<len(items):
|
|
|
|
yield items[i], c, r
|
|
|
|
i+=1
|
|
|
|
|
|
|
|
def fourup (imgs, w, h):
|
|
|
|
print ("fourup", imgs, w, h, file=sys.stderr)
|
|
|
|
oi = Image.new("RGBA", (w, h))
|
|
|
|
cw = w//2
|
|
|
|
ch = h//2
|
|
|
|
i = 0
|
|
|
|
for impath, c, r in cell_layout(imgs):
|
|
|
|
if impath:
|
|
|
|
im = Image.open(impath)
|
|
|
|
im.thumbnail((cw, ch))
|
|
|
|
oi.paste(im, (c*cw, r*ch))
|
|
|
|
return oi
|
|
|
|
|
|
|
|
def split4(items):
|
|
|
|
""" returns 4 lists where len(l) is a power of 4 """
|
|
|
|
l = len(items)
|
|
|
|
p = int(ceil(log(l, 4)))
|
|
|
|
# print ("{0} items {1} {2} {3}".format(l, p, 2**p, 4**p))
|
|
|
|
c = int((4**p)/ 4)
|
|
|
|
|
|
|
|
# c = int(ceil(len(items) / 4))
|
|
|
|
def el (x, c): # ensurelength
|
|
|
|
while len(x) < c:
|
|
|
|
x.append(None)
|
|
|
|
return x
|
|
|
|
|
|
|
|
ret = [items[0:c],items[c:c*2],items[c*2:c*3],items[c*3:]]
|
|
|
|
return tuple([el(x, c) for x in ret])
|
|
|
|
|
|
|
|
def gridrender (items, basename, tilewidth=320, tileheight=320, z=0, y=0, x=0):
|
|
|
|
""" items are now nodes proper """
|
|
|
|
""" Takes a list of nodes and returns a new node where items are arranged in a cascade of nodes such that
|
|
|
|
all items appear at the same (z) level -- side by side
|
|
|
|
Uses fourup to (recursively) produce a composite image of the underlying tiles.
|
|
|
|
|
|
|
|
"""
|
|
|
|
print ("gridrender {0} items".format(len(items)), file=sys.stderr)
|
|
|
|
|
|
|
|
if len(items) == 1:
|
|
|
|
x = items[0]
|
|
|
|
if x == None:
|
|
|
|
return None
|
|
|
|
return x # x.zoom()
|
|
|
|
else:
|
|
|
|
node = {}
|
|
|
|
node['text'] = ''
|
|
|
|
kids = []
|
|
|
|
for group, x2, y2 in cell_layout(split4(items)):
|
|
|
|
kids.append(gridrender(group, basename, tilewidth, tileheight, z+1, (y*2)+y2, (x*2)+x2))
|
|
|
|
node['children'] = [j for j in kids if j != None]
|
|
|
|
newim = fourup([j.get("image") for j in node['children'] if j != None and j.get("image")], tilewidth, tileheight)
|
|
|
|
node['image'] = newim
|
|
|
|
newimpath = "{0}.z{1}y{2}x{3}.png".format(basename, z, y, x)
|
|
|
|
newim.save(newimpath)
|
|
|
|
node['image'] = newimpath
|
|
|
|
print ("Created 4up image {0}".format(newimpath), file=sys.stderr)
|
|
|
|
|
|
|
|
return node
|
|
|
|
|
|
|
|
def recursiverender (items, basename, tilewidth=320, tileheight=320, direction=3, z=0):
|
|
|
|
node = {}
|
|
|
|
node['text'] = ''
|
|
|
|
# if len(items) >=1 and 'date' in items[0].item:
|
|
|
|
# node['text'] = items[0].item['date']
|
|
|
|
# else:
|
|
|
|
# node['text'] = ''
|
|
|
|
# node['image'] = ''
|
|
|
|
node['children'] = cc = [None, None, None, None]
|
|
|
|
ai = 0
|
|
|
|
for x in items[:3]:
|
|
|
|
# cap = os.path.splitext(os.path.basename(x.path))[0]
|
|
|
|
# cc.append(x) # x.zoom()
|
|
|
|
if (ai == direction):
|
|
|
|
ai += 1
|
|
|
|
cc[ai] = x
|
|
|
|
ai += 1;
|
|
|
|
|
|
|
|
rest = items[3:]
|
|
|
|
if rest:
|
|
|
|
# recurse
|
|
|
|
# cc.append(recursiverender(rest, basename, tilewidth, tileheight, z+1))
|
|
|
|
cc[direction] = recursiverender(rest, basename, tilewidth, tileheight, direction, z+1)
|
|
|
|
|
|
|
|
newim = fourup([x.get("image") for x in node['children'] if x != None and x.get("image")], tilewidth, tileheight)
|
|
|
|
# simplified name works just because there's only one generated tile per level
|
|
|
|
newimpath = u"{0}.z{1}.png".format(basename, z)
|
|
|
|
newim.save(newimpath)
|
|
|
|
node['image'] = newimpath
|
|
|
|
|
|
|
|
return node
|
|
|
|
|
|
|
|
def layoutxyz (n, x=0, y=0, z=0, outnode={}):
|
|
|
|
# print ("layout", n, x, y, z, file=sys.stderr)
|
|
|
|
outnode["{0},{1},{2}".format(x,y,z)] = {
|
|
|
|
"text": n['text'],
|
|
|
|
"image": n['image']
|
|
|
|
}
|
|
|
|
if 'children' in n:
|
|
|
|
for child, cx, cy in cell_layout(n['children']):
|
|
|
|
layout(child, (x*2)+cx, (y*2)+cy, z+1, outnode)
|
|
|
|
return outnode
|
|
|
|
|
|
|
|
def html (node, title):
|
|
|
|
page = u"""<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<title>""" + title + u"""</title>
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
|
|
<script src="/lib/leaflet-1.0.1/leaflet.js"></script>
|
|
|
|
<link href="/lib/leaflet-1.0.1/leaflet.css" rel="stylesheet" type="text/css">
|
|
|
|
<link href="map.css" rel="stylesheet" type="text/css">
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="frame" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px">
|
|
|
|
<div id="map" style="width: 100%; height: 100%; background: black"></div>
|
|
|
|
<div id="text" style="position: absolute; left: 50px; top: 10px; width: auto; color: white">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
|
|
(function() {
|
|
|
|
// warning CHANGES TO THIS CODE NEED TO BE ROLLED BACK INTO leaflet.py
|
|
|
|
var cell_layout, expandzoom, fourup, layoutxyz, render, split4, tiler, tiles_wrapper, zoom;
|
|
|
|
|
|
|
|
window.tiler = tiler = {};
|
|
|
|
|
|
|
|
tiler.tiles_wrapper = tiles_wrapper = function(path, ext) {
|
|
|
|
if (ext == null) { ext = "jpg"; }
|
|
|
|
var ret = {};
|
|
|
|
ret.get_tile_path = function(z, y, x) {
|
|
|
|
return path + ("/z"+z+"y"+y+"x"+x+"."+ext);
|
|
|
|
};
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
tiler.zoom = zoom = function(tiles, caption, url, x, y, z, maxzoom) {
|
|
|
|
var c, i, k, kids, len, len1, node, r, ref, ref1;
|
|
|
|
if (x == null) {
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
if (y == null) {
|
|
|
|
y = 0;
|
|
|
|
}
|
|
|
|
if (z == null) {
|
|
|
|
z = 0;
|
|
|
|
}
|
|
|
|
if (maxzoom == null) {
|
|
|
|
maxzoom = 3;
|
|
|
|
}
|
|
|
|
node = {};
|
|
|
|
if (caption && x === 0 && y === 0) {
|
|
|
|
node['text'] = caption;
|
|
|
|
}
|
|
|
|
var lastc = Math.pow(2, z) - 1;
|
|
|
|
if (url && x === 0 && y === lastc) {
|
|
|
|
node['url'] = url
|
|
|
|
}
|
|
|
|
node['image'] = tiles.get_tile_path(z, y, x);
|
|
|
|
if (z < maxzoom) {
|
|
|
|
kids = [];
|
|
|
|
ref = [0, 1];
|
|
|
|
for (i = 0, len = ref.length; i < len; i++) {
|
|
|
|
r = ref[i];
|
|
|
|
ref1 = [0, 1];
|
|
|
|
for (k = 0, len1 = ref1.length; k < len1; k++) {
|
|
|
|
c = ref1[k];
|
|
|
|
kids.push(zoom(tiles, caption, url, (x * 2) + c, (y * 2) + r, z + 1, maxzoom));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
node['children'] = kids;
|
|
|
|
}
|
|
|
|
return node;
|
|
|
|
};
|
|
|
|
|
|
|
|
split4 = function(items) {
|
|
|
|
var c, el, i, l, len, p, ref, results, x;
|
|
|
|
l = items.length;
|
|
|
|
p = Math.ceil(Math.log(l) / Math.log(4));
|
|
|
|
c = Math.max(1, Math.pow(4, p) / 4);
|
|
|
|
el = function(x, c) {
|
|
|
|
while (x.length < c) {
|
|
|
|
x.push(null);
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
};
|
|
|
|
ref = [items.slice(0, c), items.slice(c, c * 2), items.slice(c * 2, c * 3), items.slice(c * 3)];
|
|
|
|
results = [];
|
|
|
|
for (i = 0, len = ref.length; i < len; i++) {
|
|
|
|
x = ref[i];
|
|
|
|
results.push(el(x, c));
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
};
|
|
|
|
|
|
|
|
cell_layout = function(items) {
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
y: 0,
|
|
|
|
x: 0,
|
|
|
|
item: items[0]
|
|
|
|
}, {
|
|
|
|
y: 0,
|
|
|
|
x: 1,
|
|
|
|
item: items[1]
|
|
|
|
}, {
|
|
|
|
y: 1,
|
|
|
|
x: 0,
|
|
|
|
item: items[2]
|
|
|
|
}, {
|
|
|
|
y: 1,
|
|
|
|
x: 1,
|
|
|
|
item: items[3]
|
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
tiler.render = render = function(items, tilewidth, tileheight, z, y, x) {
|
|
|
|
var g, i, j, kids, len, node, ref;
|
|
|
|
if (tilewidth == null) {
|
|
|
|
tilewidth = 256;
|
|
|
|
}
|
|
|
|
if (tileheight == null) {
|
|
|
|
tileheight = 256;
|
|
|
|
}
|
|
|
|
if (z == null) {
|
|
|
|
z = 0;
|
|
|
|
}
|
|
|
|
if (y == null) {
|
|
|
|
y = 0;
|
|
|
|
}
|
|
|
|
if (x == null) {
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
if (items.length === 1) {
|
|
|
|
x = items[0];
|
|
|
|
if (x === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return zoom(x, '');
|
|
|
|
} else {
|
|
|
|
node = {};
|
|
|
|
node['text'] = '';
|
|
|
|
kids = [];
|
|
|
|
ref = cell_layout(split4(items));
|
|
|
|
for (i = 0, len = ref.length; i < len; i++) {
|
|
|
|
g = ref[i];
|
|
|
|
kids.push(render(g.item, tilewidth, tileheight, z + 1, (y * 2) + g.y, (x * 2) + g.x));
|
|
|
|
}
|
|
|
|
node.children = (function() {
|
|
|
|
var k, len1, results;
|
|
|
|
results = [];
|
|
|
|
for (k = 0, len1 = kids.length; k < len1; k++) {
|
|
|
|
j = kids[k];
|
|
|
|
if (j !== null) {
|
|
|
|
results.push(j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
})();
|
|
|
|
node.image = fourup((function() {
|
|
|
|
var k, len1, ref1, results;
|
|
|
|
ref1 = node.children;
|
|
|
|
results = [];
|
|
|
|
for (k = 0, len1 = ref1.length; k < len1; k++) {
|
|
|
|
j = ref1[k];
|
|
|
|
if (j !== null) {
|
|
|
|
results.push(j.image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
})(), tilewidth, tileheight);
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
tiler.layoutxyz = layoutxyz = function(n, x, y, z, outnode) {
|
|
|
|
var g, i, len, ref;
|
|
|
|
if (x == null) {
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
if (y == null) {
|
|
|
|
y = 0;
|
|
|
|
}
|
|
|
|
if (z == null) {
|
|
|
|
z = 0;
|
|
|
|
}
|
|
|
|
if (outnode == null) {
|
|
|
|
outnode = {};
|
|
|
|
}
|
|
|
|
outnode[x + "," + y + "," + z] = n;
|
|
|
|
if (n.children) {
|
|
|
|
ref = cell_layout(n.children);
|
|
|
|
for (i = 0, len = ref.length; i < len; i++) {
|
|
|
|
g = ref[i];
|
|
|
|
if (g.item) {
|
|
|
|
layoutxyz(g.item, (x * 2) + g.x, (y * 2) + g.y, z + 1, outnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return outnode;
|
|
|
|
};
|
|
|
|
|
|
|
|
tiler.fourup = fourup = function(images, tilewidth, tileheight) {
|
|
|
|
if (tilewidth == null) {
|
|
|
|
tilewidth = 256;
|
|
|
|
}
|
|
|
|
if (tileheight == null) {
|
|
|
|
tileheight = 256;
|
|
|
|
}
|
|
|
|
return function(done) {
|
|
|
|
var i, img, imgelts, len, loadcount, results, src, x;
|
|
|
|
loadcount = 0;
|
|
|
|
images = (function() {
|
|
|
|
var i, len, results;
|
|
|
|
results = [];
|
|
|
|
for (i = 0, len = images.length; i < len; i++) {
|
|
|
|
x = images[i];
|
|
|
|
if (x !== null) {
|
|
|
|
results.push(x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
})();
|
|
|
|
imgelts = [];
|
|
|
|
results = [];
|
|
|
|
for (i = 0, len = images.length; i < len; i++) {
|
|
|
|
src = images[i];
|
|
|
|
img = new Image;
|
|
|
|
imgelts.push(img);
|
|
|
|
img.addEventListener("load", function() {
|
|
|
|
var canvas, ctx, g, hh, hw, k, len1, ref;
|
|
|
|
if (++loadcount >= images.length) {
|
|
|
|
canvas = document.createElement("canvas");
|
|
|
|
canvas.width = tilewidth;
|
|
|
|
canvas.height = tileheight;
|
|
|
|
ctx = canvas.getContext("2d");
|
|
|
|
hw = tilewidth / 2;
|
|
|
|
hh = tileheight / 2;
|
|
|
|
ref = cell_layout(imgelts);
|
|
|
|
for (k = 0, len1 = ref.length; k < len1; k++) {
|
|
|
|
g = ref[k];
|
|
|
|
if (g.item) {
|
|
|
|
ctx.drawImage(g.item, g.x * hw, g.y * hh, hw, hh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return done(null, canvas.toDataURL());
|
|
|
|
}
|
|
|
|
}, false);
|
|
|
|
if (typeof src === "function") {
|
|
|
|
console.log("inside 4up, deferring");
|
|
|
|
results.push(src(function(err, data) {
|
|
|
|
console.log(" inside 4up, GOT DATA");
|
|
|
|
return img.src = data;
|
|
|
|
}));
|
|
|
|
} else {
|
|
|
|
results.push(img.src = src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
tiler.expandzoom = expandzoom = function(node) {
|
|
|
|
var c, ret, tilespath;
|
|
|
|
if (node.zoomable) {
|
|
|
|
tilespath = node.image.replace(/\/[^\/]+$/, "");
|
|
|
|
var ext = node.image.match(/\.([^\.]+)$/);
|
|
|
|
if (ext != null) { ext = ext[1] };
|
|
|
|
ret = zoom(tiles_wrapper(tilespath, ext), node.text, node.url);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (node.children) {
|
|
|
|
node.children = (function() {
|
|
|
|
var i, len, ref, results;
|
|
|
|
ref = node.children;
|
|
|
|
results = [];
|
|
|
|
for (i = 0, len = ref.length; i < len; i++) {
|
|
|
|
c = ref[i];
|
|
|
|
if (c != null) {
|
|
|
|
results.push(expandzoom(c));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
})();
|
|
|
|
}
|
|
|
|
return node;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* DynamicTiles */
|
|
|
|
/*
|
|
|
|
A simple GridLayer extension that takes an external "nodes" object as option,
|
|
|
|
Nodes are keyed [x,y,z]
|
|
|
|
and expected to be of the form:
|
|
|
|
{
|
|
|
|
text: "My text",
|
|
|
|
image" "imagepath.jpg"
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
L.GridLayer.DynamicTiles = L.GridLayer.extend({
|
|
|
|
createTile: function (coords, done) { // done = (err, tile)
|
|
|
|
// console.log("createTile", coords, this.options, this.options.nodes);
|
|
|
|
var tile = document.createElement('div'),
|
|
|
|
node = this.options.nodes[coords.x+","+coords.y+","+coords.z],
|
|
|
|
defer = false;
|
|
|
|
|
|
|
|
tile.classList.add("tile");
|
|
|
|
if (node != undefined) {
|
|
|
|
// console.log("NODE", node);
|
|
|
|
if (node.image) {
|
|
|
|
var img = document.createElement("img");
|
|
|
|
defer = true;
|
|
|
|
img.addEventListener("load", function () {
|
|
|
|
done(null, tile);
|
|
|
|
})
|
|
|
|
img.src = node.image;
|
|
|
|
tile.appendChild(img);
|
|
|
|
img.classList.add("imagetile");
|
|
|
|
}
|
|
|
|
if (node.text) {
|
|
|
|
//console.log("text", node.text);
|
|
|
|
var textdiv = document.createElement("div");
|
|
|
|
textdiv.innerHTML = node.text;
|
|
|
|
tile.appendChild(textdiv);
|
|
|
|
textdiv.classList.add("text");
|
|
|
|
}
|
|
|
|
// if (node.url) {
|
|
|
|
// console.log("NODE HAS URL!", node.url);
|
|
|
|
// var urldiv = document.createElement("div"),
|
|
|
|
// urllink = document.createElement("a"),
|
|
|
|
// m = node.url.search(/\/([^\/]+)$/);
|
|
|
|
// urllink.innerHTML = (m != null) ? m[1] : "LINK";
|
|
|
|
// urldiv.appendChild(urllink);
|
|
|
|
// urldiv.classList.add("url");
|
|
|
|
// tile.appendChild(urldiv);
|
|
|
|
// }
|
|
|
|
if (node.background) {
|
|
|
|
tile.style.color = node.background;
|
|
|
|
}
|
|
|
|
if (node.class) {
|
|
|
|
tile.classList.add(node.class);
|
|
|
|
}
|
|
|
|
tile.classList.add("z"+coords.z);
|
|
|
|
} else {
|
|
|
|
tile.innerHTML = [coords.x, coords.y, coords.z].join(', ');
|
|
|
|
tile.classList.add("coords");
|
|
|
|
}
|
|
|
|
// tile.style.outline = '1px solid red';
|
|
|
|
if (!defer) {
|
|
|
|
window.setTimeout(function () {
|
|
|
|
done(null, tile);
|
|
|
|
}, 250);
|
|
|
|
}
|
|
|
|
return tile;
|
|
|
|
}
|
|
|
|
});""
|
|
|
|
|
|
|
|
L.gridLayer.dynamicTiles = function(opts) {
|
|
|
|
return new L.GridLayer.DynamicTiles(opts);
|
|
|
|
};
|
|
|
|
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
(function () {
|
|
|
|
|
|
|
|
|
|
|
|
function getjson (url, callback) {
|
|
|
|
var request = new XMLHttpRequest();
|
|
|
|
request.open('GET', url, true);
|
|
|
|
request.onload = function() {
|
|
|
|
if (request.readyState == XMLHttpRequest.DONE && request.status >= 200 && request.status < 400) {
|
|
|
|
callback(null, JSON.parse(request.responseText));
|
|
|
|
} else {
|
|
|
|
callback("server error");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
request.onerror = function() {
|
|
|
|
callback("connection error");
|
|
|
|
};
|
|
|
|
request.send();
|
|
|
|
}
|
|
|
|
|
|
|
|
var map = L.map('map', {
|
|
|
|
editable: true,
|
|
|
|
maxZoom: 100,
|
|
|
|
minZoom: 0,
|
|
|
|
zoom: 0,
|
|
|
|
crs: L.CRS.Simple,
|
|
|
|
center: new L.LatLng(0,0),
|
|
|
|
});
|
|
|
|
var data = """ + json.dumps(node) + """;
|
|
|
|
|
|
|
|
var nodes = (tiler.layoutxyz(tiler.expandzoom(data)));
|
|
|
|
map.addLayer( L.gridLayer.dynamicTiles({
|
|
|
|
minZoom: 0,
|
|
|
|
nodes: nodes
|
|
|
|
}) );
|
|
|
|
|
|
|
|
var yx = L.latLng,
|
|
|
|
xy = function(x, y) {
|
|
|
|
if (L.Util.isArray(x)) { // When doing xy([x, y]);
|
|
|
|
return yx(x[1], x[0]);
|
|
|
|
}
|
|
|
|
return yx(y, x); // When doing xy(x, y);
|
|
|
|
};
|
|
|
|
// map.setView(xy(0.5 * 256, -0.5 * 256), 0);
|
|
|
|
|
|
|
|
})();
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
"""
|
|
|
|
return page
|
|
|
|
|
|
|
|
def make_gallery(args):
|
|
|
|
"""
|
|
|
|
to do -- separate the actual tiling process...
|
|
|
|
make tiling a separate pass ON THE ACTUAL NODE jSON
|
|
|
|
|
|
|
|
NB: this command accepts two different kinds of input.
|
|
|
|
1. One or more images as (argv) arguments -or-
|
|
|
|
2. A JSON stream (one object per line) on stdin.
|
|
|
|
"""
|
|
|
|
|
|
|
|
bgcolor = None # (0, 0, 0)
|
|
|
|
|
|
|
|
items = []
|
|
|
|
if args.input:
|
|
|
|
for x in args.input:
|
|
|
|
i = {'url': x}
|
|
|
|
items.append(i)
|
|
|
|
else:
|
|
|
|
for line in sys.stdin:
|
|
|
|
line = line.rstrip()
|
|
|
|
if line and not line.startswith("#"):
|
|
|
|
item = json.loads(line)
|
|
|
|
items.append(item)
|
|
|
|
|
|
|
|
# Ensure / Generate tiles per image
|
|
|
|
items.sort(key=lambda x: x['url'])
|
|
|
|
tiles = []
|
|
|
|
for item in items:
|
|
|
|
n = item['url']
|
|
|
|
# print (n, file=sys.stderr)
|
|
|
|
path = os.path.join(args.tilespath, n)
|
|
|
|
# TODO date format...
|
|
|
|
caption = ''
|
|
|
|
if 'text' or 'date' in item:
|
|
|
|
caption += u'<p class="caption">';
|
|
|
|
if 'text' in item:
|
|
|
|
caption += u'<span class="text">{0}</span>'.format(autolink(item['text']))
|
|
|
|
if 'date' in item:
|
|
|
|
dt = parse8601(item['date'], "%d %b %Y")
|
|
|
|
caption += u'<span class="date">{0}</span>'.format(dt)
|
|
|
|
if 'url' in item:
|
|
|
|
ext = os.path.splitext(urlparse.urlparse(item['url']).path)[1]
|
|
|
|
if ext:
|
|
|
|
ext = ext[1:].upper()
|
|
|
|
caption += u'<a class="url" href="{0}">{1}</a>'.format(item['url'], ext)
|
|
|
|
if 'text' or 'date' in item:
|
|
|
|
caption += u'</p>';
|
|
|
|
|
|
|
|
t = tiles_wrapper(path, item['url'], text=caption)
|
|
|
|
tiles.append(t)
|
|
|
|
tile0 = t.get_tile_path(0, 0, 0) # os.path.join(path, args.tilename.format({'x': 0, 'y': 0, 'z': 0}))
|
|
|
|
if not os.path.exists(tile0) or args.force:
|
|
|
|
print ("Tiling {0}".format(n), file=sys.stderr)
|
|
|
|
try:
|
|
|
|
im = Image.open(n)
|
|
|
|
try:
|
|
|
|
os.makedirs(path)
|
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
tile_image(im, args.zoom, args.tilewidth, args.tileheight, path+"/", args.tilename, bgcolor)
|
|
|
|
# tiles.append(t)
|
|
|
|
|
|
|
|
except IOError as e:
|
|
|
|
print ("Missing {0}, skipping".format(n), file=sys.stderr)
|
|
|
|
tiles = tiles[:-1]
|
|
|
|
|
|
|
|
# DO THE LAYOUT, generating intermediate tiles (zoom outs)
|
|
|
|
if args.reverse:
|
|
|
|
tiles.reverse()
|
|
|
|
tiles = [t.zoom() for t in tiles]
|
|
|
|
basename = os.path.join(args.tilespath, args.name)
|
|
|
|
if args.recursive:
|
|
|
|
root_node = recursiverender(tiles, basename, args.tilewidth, args.tileheight, args.direction)
|
|
|
|
else:
|
|
|
|
root_node = gridrender(tiles, basename, args.tilewidth, args.tileheight)
|
|
|
|
|
|
|
|
# OUTPUT ROOT NODE
|
|
|
|
if args.html:
|
|
|
|
print (html(root_node, args.name))
|
|
|
|
else:
|
|
|
|
print (json.dumps(root_node, indent=args.indent))
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
|
|
ap = ArgumentParser("")
|
|
|
|
|
|
|
|
ap.add_argument("--basepath", default=".")
|
|
|
|
ap.add_argument("--baseuri", default="")
|
|
|
|
|
|
|
|
ap.add_argument("--tilespath", default="tiles")
|
|
|
|
|
|
|
|
ap.add_argument("--tilewidth", type=int, default=256)
|
|
|
|
ap.add_argument("--tileheight", type=int, default=256)
|
|
|
|
ap.add_argument("--zoom", type=int, default=3)
|
|
|
|
|
|
|
|
ap.add_argument("--tilename", default="z{0[z]}y{0[y]}x{0[x]}.png")
|
|
|
|
ap.add_argument("--reverse", default=False, action="store_true")
|
|
|
|
ap.add_argument("--indent", default=2, type=int)
|
|
|
|
ap.add_argument("--recursive", default=False, action="store_true")
|
|
|
|
|
|
|
|
ap.add_argument("--force", default=False, action="store_true")
|
|
|
|
|
|
|
|
subparsers = ap.add_subparsers(help='sub-command help')
|
|
|
|
ap_gallery = subparsers.add_parser('gallery', help='Create a grid gallery of images')
|
|
|
|
ap_gallery.add_argument("input", nargs="*")
|
|
|
|
ap_gallery.add_argument("--html", default=False, action="store_true")
|
|
|
|
ap_gallery.add_argument("--recursive", default=False, action="store_true")
|
|
|
|
ap_gallery.add_argument("--direction", type=int, default=3, help="cell to recursively expand into, 0-3, default: 3 (bottom-right)")
|
|
|
|
ap_gallery.add_argument("--name", default="gallery")
|
|
|
|
ap_gallery.set_defaults(func=make_gallery)
|
|
|
|
|
|
|
|
args = ap.parse_args()
|
|
|
|
args.func(args)
|