You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.7 KiB
Plaintext
119 lines
3.7 KiB
Plaintext
6 years ago
|
#!/usr/bin/env python
|
||
|
from __future__ import print_function
|
||
|
from PIL import Image
|
||
|
import re, sys, json, os
|
||
|
|
||
|
try:
|
||
|
from urllib import quote as urlquote # Python 2.X
|
||
|
except ImportError:
|
||
|
from urllib.parse import quote as urlquote # Python 3+
|
||
|
|
||
|
|
||
|
def fitbox (boxw, boxh, w, h):
|
||
|
rw = boxw
|
||
|
rh = int(rw * (float(h) / w))
|
||
|
if (rh >= boxh):
|
||
|
rh = boxh
|
||
|
rw = int(rh * (float(w) / h))
|
||
|
return rw, rh
|
||
|
|
||
|
def tile_image (im, maxz=0, tilew=256, tileh=256, base=".", template="z{0[z]}y{0[y]}x{0[x]}.jpg", bgcolor=(0,0,0), margin_right=0, margin_bottom=0):
|
||
|
z = 0
|
||
|
boxw, boxh = tilew, tileh
|
||
|
|
||
|
alpha = bgcolor != None # not template.endswith("jpg")
|
||
|
|
||
|
while True:
|
||
|
rw, rh = fitbox(boxw, boxh, im.size[0], im.size[1])
|
||
|
rim = im.resize((rw-margin_right, rh-margin_bottom), Image.ANTIALIAS)
|
||
|
if bgcolor:
|
||
|
tim = Image.new("RGB", (boxw, boxh), bgcolor)
|
||
|
tim.paste(rim, (0, 0))
|
||
|
else:
|
||
|
tim = Image.new("RGBA", (boxw, boxh))
|
||
|
tim.paste(rim, (0, 0))
|
||
|
|
||
|
rows, cols = 2**z, 2**z
|
||
|
for r in range(rows):
|
||
|
for c in range(cols):
|
||
|
ix = c*tilew
|
||
|
iy = r*tileh
|
||
|
cim = tim.crop((ix, iy, ix+tilew, iy+tileh))
|
||
|
op = base + template.format({'z':z, 'x':c, 'y':r})
|
||
|
# if not alpha:
|
||
|
# cim = cim.convert("RGB")
|
||
|
cim.save(op)
|
||
|
|
||
|
z += 1
|
||
|
if z>maxz:
|
||
|
break
|
||
|
boxw *= 2
|
||
|
boxh *= 2
|
||
|
|
||
|
def expand_template (x):
|
||
|
return re.sub(r"{(\w+?)}", "{0[\\1]}", x)
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
from argparse import ArgumentParser
|
||
|
|
||
|
ap = ArgumentParser("Generate image tiles and output JSON for a collection of images")
|
||
|
ap.add_argument("input", nargs="+")
|
||
|
|
||
|
ap.add_argument("--basepath", default=".")
|
||
|
ap.add_argument("--baseuri", default="")
|
||
|
|
||
|
ap.add_argument("--tilespath", default="tiles", help="name of path to create in the same folder as the original")
|
||
|
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{z}y{y}x{x}.png")
|
||
|
ap.add_argument("--force", default=False, action="store_true")
|
||
|
|
||
|
args = ap.parse_args()
|
||
|
|
||
|
"""
|
||
|
leafygal format: {id: original, tiles: "template", name: filename}
|
||
|
"""
|
||
|
|
||
|
tilenamex = expand_template(args.tilename)
|
||
|
#bgcolor = (0, 0, 0)
|
||
|
bgcolor = None
|
||
|
items = []
|
||
|
|
||
|
for imgpath in args.input:
|
||
|
parent = os.path.split(imgpath)[0]
|
||
|
basename = os.path.basename(imgpath)
|
||
|
path = os.path.join(parent, args.tilespath, basename)
|
||
|
item = {
|
||
|
'id': urlquote(imgpath),
|
||
|
'name': basename,
|
||
|
'tiles': os.path.join(path, args.tilename)
|
||
|
}
|
||
|
tile0 = os.path.join(path, tilenamex.format({'x': 0, 'y': 0, 'z': 0}))
|
||
|
items.append(item)
|
||
|
if not os.path.exists(tile0) or args.force:
|
||
|
print ("Tiling {0}".format(imgpath), file=sys.stderr)
|
||
|
try:
|
||
|
im = Image.open(imgpath)
|
||
|
try:
|
||
|
os.makedirs(path)
|
||
|
except OSError:
|
||
|
pass
|
||
|
tile_image(im, args.zoom, args.tilewidth, args.tileheight, path+"/", tilenamex, bgcolor)
|
||
|
# tiles.append(t)
|
||
|
|
||
|
except IOError as e:
|
||
|
print ("Missing {0}, skipping".format(n), file=sys.stderr)
|
||
|
items = items[:-1]
|
||
|
|
||
|
data = {
|
||
|
'@context': {
|
||
|
'id': '@id',
|
||
|
'aa': 'http://activearchives.org/terms',
|
||
|
'name': 'aa:filename',
|
||
|
'tiles': 'aa:tiles'
|
||
|
},
|
||
|
'@graph': items
|
||
|
}
|
||
|
print (json.dumps(data, indent=2))
|