expoweb/noinfo/prospecting_guide_scripts/make-prospectingguide-new.py
2013-06-19 03:35:59 +01:00

583 lines
21 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Script to create a slightly more useful attempt
# at a prospecting guide.
areas = ['', '1a','1b','1c','1d', '2a', '2b', '2c', '2d', '3', '4', '5', '6','7', '8a', '8b', '8c', '8d', '9', '10', '11']
areanames = {
'': 'Location unclear',
'1a': '1a – Plateau: around Top Camp',
'1b': '1b – Western plateau near 182',
'1c': '1c – Eastern plateau near 204 walk-in path',
'1d': '1d – Further plateau around 76',
'2a': '2a – Southern Schwarzmooskogel near 201 path and the Nipple',
'2b': '2b – Eishöhle area',
'2c': '2c – Kaninchenhöhle area',
'2d': '2d – Steinbrückenhöhle area',
'3': '3 – Bräuning Alm',
'4': '4 – Kratzer valley',
'5': '5 – Schwarzmoos-Wildensee',
'6': '6 – Far plateau',
'7': '7 – Egglgrube',
'8a': '8a – Loser south face',
'8b': '8b – Loser below Dimmelwand',
'8c': '8c – Augst See',
'8d': '8d – Loser-Hochganger ridge',
'9': '9 – Gschwandt Alm',
'10': '10 – Altaussee',
'11': '11 – Augstbach'
}
areacolours = {
'1a' : '#00ffff',
'1b' : '#ff00ff',
'1c' : '#ffff00',
'1d' : '#ffffff',
'2a' : '#ff0000',
'2b' : '#00ff00',
'2c' : '#008800',
'2d' : '#ff9900',
'3' : '#880000',
'4' : '#0000ff',
'6' : '#000000', # doubles for surface fixed pts, and anything else
'7' : '#808080'
}
cavelists={}
for a in areas: cavelists[a]=[]
#check to see if cmd is on $PATH
def exists_in_path(cmd):
# can't search the path if a directory is specified
assert not os.path.dirname(cmd)
extensions = os.environ.get("PATHEXT", "").split(os.pathsep)
for directory in os.environ.get("PATH", "").split(os.pathsep):
base = os.path.join(directory, cmd)
options = [base] + [(base + ext) for ext in extensions]
for filename in options:
if os.path.exists(filename):
return True
return False
def chomp(s):
if not s: return s
if(s[-1]=="\n"): return s[:-1]
else: return s
def find_effective_number(c):
"""Determine an appropriate number to use."""
if c["Kataster Number"]:
return c["Kataster Number"]
else:
return c["Unofficial number"]
def longnumber(c, number):
"""Both numbers"""
if (c["Unofficial number"] and c["Unofficial number"] != number):
return number + " (" + c["Unofficial number"] + ")"
else:
return number
def find_location(cave):
for fixtype in ["tag point in dataset", "other point in dataset", "exact entrance in dataset (drip line/highest enclosed contour)", "GPS post SA", "GPS pre SA"]:
if(cave[fixtype]):
return positions[cave[fixtype]]
return 0
def is_explored(cave):
s = cave["Kat Status Code"]
if(not s): return "<td></td>"
s = s.replace("(?)","")
if s[-1] == " ": s=s[:-1]
if (not s):
print "Rogue space in " + find_effective_number(cave)
return "<td></td>"
code = s[-1]
if code == '+': status = "good"
elif code in ['=', 'x']: status = "bad"
elif code in ['-', '?']: status = "awful"
else: return "<td>%s</td>" % code
return "<td class=\"%s\">%s</td>" % (status, code)
def is_tagged(cave):
s = chomp(cave["Marking"])
s = re.sub(r'\s+(?:\(\?\))?$', "", s)
if not s and cave["Multiple entrances"] in ["yes", "entrance", "last entrance"]:
return "<td></td>"
if s == "Tag": return "<td class=\"good\">%s</td>" % s
if s in ["Retag", "Paint", "Spit"]: return "<td class=\"bad\">%s</td>" % s
if s == "Unmarked": return "<td class=\"awful\">None</td>"
if s == "": return "<td class=\"awful\"></td>"
print "Unrecognised marking status on %s: %s" % (find_effective_number(cave), repr(s))
return "<td>ERROR</td>"
def findability_color(cave):
if cave["Findability"] == "Surveyed": return "good"
elif cave["Findability"] == "Refindable": return "bad"
elif cave["Findability"] == "Lost": return "awful"
else: return ""
def is_underground_surveyed(cave):
s = chomp(cave["Underground drawn survey"])
if(cave["Multiple entrances"] not in ["", "yes"]): return "<td></td>"
if not s:
return "<td class=\"awful\">None</td>"
if s and (s.find("<img") > -1 or s.find("<a") > -1):
return "<td class=\"good\">Yes</td>"
else:
return "<td class=\"bad\">Missing</td>"
def have_survey_data(cave):
if(cave["Multiple entrances"] not in ["", "yes"]): return "<td></td>"
s = chomp(cave["Underground centre line"])
if s: return "<td class=\"good\">Yes</td>"
s = chomp(cave["Survex file to get length and depth"])
if s: return "<td class=\"good\">Yes</td>"
if cave["Kat Status Code"] and cave["Kat Status Code"][0] == '1':
# Cave < 50m deep and < 50m long...
# Sadly this band includes caves we really ought to have data for as
# well as caves small enough that a grade 1 sketch is justifiable.
return "<td class=\"bad\"><small>&lt;50m</small></td>"
s = chomp(cave["Underground drawn survey"])
if s: return "<td class=\"bad\">Missing</td>"
return "<td class=\"awful\">None</td>"
def has_photo(cave):
s = chomp(cave["Photo of location"])
if ((cave["Multiple entrances"] not in ["", "yes"]) and chomp(cave["Autogen file"]) == ""):
return "<td></td>"
if not s:
return "<td class=\"awful\">None</td>"
if s and (s.find("<img") > -1 or s.find("<a") > -1):
return "<td class=\"good\">Yes</td>"
else:
return "<td class=\"bad\">Missing</td>"
def find_label(cave, number):
t = longnumber(cave, number) + " "
if(cave["Name"] and cave["Unofficial Name"]): t += cave["Name"] + " (" + cave["Unofficial Name"] + ")"
elif cave["Name"]: t += cave["Name"]
else: t += cave["Unofficial Name"]
try:
n = number
if(n[-1] in string.lowercase): n = n[:-1]
except:
n = "NONE"
if lengths.has_key(n):
t += (" %sm long %sm deep" % (lengths[n][0], lengths[n][1]))
return t
def get_img_name(maparea):
filename = "prospecting_guide"
if maparea != "all":
filename += "_" + maparea + "area"
if showbg:
filename += ".jpg"
else:
filename += ".png"
return filename
# Parameters for big map and zoomed subarea maps:
# big map first (zoom factor ignored)
maps = {
# id left top right bottom zoom
# G&K G&K G&K G&K factor
"all": [34950.9, 86300.0, 38325.0, 80895.6, 1.0,
"All"],
"40": [36275.6, 82392.5, 36780.3, 81800.0, 3.0,
"Eish&ouml;hle"],
"76": [35440.0, 83220.0, 36090.0, 82670.0, 3.0,
"Eislufth&ouml;hle"],
"204": [36354.1, 84154.5, 37047.4, 83399.7, 3.0,
"Steinbr&uuml;ckenh&ouml;hle"],
"tc": [35230.0, 82690.0, 36110.0, 82100.0, 3.0,
"Near Top Camp"],
"grieß":
[36000.0, 86300.0, 38320.0, 84400.0, 4.0,
"Grießkogel Area"],
}
# Keys in the order in which we want the maps output
mapcodes = ["all", "grieß","40", "76", "204", "tc"]
# Field codes
L = 0
T = 1
R = 2
B = 3
ZOOM = 4
DESC = 5
import Image, ImageDraw, ImageFont, string, os, sys
for FONT in [
"/usr/share/fonts/truetype/freefont/FreeSans.ttf",
"/usr/X11R6/lib/X11/fonts/truetype/arial.ttf",
"C:\WINNT\Fonts\ARIAL.TTF"
]:
if os.path.isfile(FONT): break
SIZE = 8
myFont = ImageFont.truetype(FONT, SIZE)
showbg = not(len(sys.argv) > 1 and sys.argv[1] == '--white')
mainImage = Image.open("pguidemap.jpg")
if not showbg:
mainImage = Image.new("RGB", mainImage.size, '#ffffff')
imgs = {}
draws = {}
imgmaps = {}
factors = {}
for maparea in maps.keys():
m = maps[maparea]
if maparea == "all":
img = mainImage
else:
M = maps['all']
W, H = mainImage.size
l = int((m[L] - M[L]) / (M[R] - M[L]) * W)
t = int((m[T] - M[T]) / (M[B] - M[T]) * H)
r = int((m[R] - M[L]) / (M[R] - M[L]) * W)
b = int((m[B] - M[T]) / (M[B] - M[T]) * H)
img = mainImage.crop((l, t, r, b))
w = int(round(m[ZOOM] * (m[R] - m[L]) / (M[R] - M[L]) * W))
h = int(round(m[ZOOM] * (m[B] - m[T]) / (M[B] - M[T]) * H))
print "%s: H %d W %d" % (maparea, h, w)
img = img.resize((w, h), Image.BICUBIC)
imgs[maparea] = img
draw = ImageDraw.Draw(img)
draw.setfont(myFont)
draws[maparea] = draw
imgmaps[maparea] = []
# Draw scale bar
m100 = int(100 / (m[R] - m[L]) * img.size[0])
draw.line([10, SIZE*3, 10, SIZE*2], fill='#000000')
draw.line([10, SIZE*2, 10+m100, SIZE*2], fill='#000000')
draw.line([10+m100, SIZE * 3, 10+m100, SIZE*2], fill='#000000')
label = "100m"
draw.text([10 + (m100 - draw.textsize(label)[0]) / 2, SIZE/2], label, fill='#000000')
factors[maparea] = img.size[0] / (m[R] - m[L]), img.size[1] / (m[T] - m[B])
def mungecoord(x, y, mapcode):
# Top of Zinken is 73 1201 = dataset 34542 81967
# Top of Hinter is 1073 562 = dataset 36670 83317
# image is 1417 by 2201
# FACTOR1 = 1000.0 / (36670.0-34542.0)
# FACTOR2 = (1201.0-562.0) / (83317 - 81967)
# FACTOR = (FACTOR1 + FACTOR2)/2
# The factors aren't the same as the scanned map's at a slight angle. I
# can't be bothered to fix this. Since we zero on the Hinter it makes
# very little difference for caves in the areas round 76 or 204.
# xoffset = (x - 36670)*FACTOR
# yoffset = (y - 83317)*FACTOR
# return (1073 + xoffset, 562 - yoffset)
m = maps[mapcode]
return ((x - m[L]) * factors[mapcode][0], (m[T] - y) * factors[mapcode][1])
def plot(loctuple, number, area, label):
shortnumber = number.replace("&mdash;","")
if area in areacolours:
fillcol = areacolours[area]
else:
fillcol = 6
for maparea in maps.keys():
(x,y) = map(int, mungecoord(loctuple[0], loctuple[1], maparea))
draw = draws[maparea]
imgmaps[maparea].append( [x-4, y-SIZE/2, x+4+draw.textsize(shortnumber)[0], y+SIZE/2, shortnumber, label] )
draw.rectangle([(x+4, y-SIZE/2), (x+4+draw.textsize(shortnumber)[0], y+SIZE/2)], fill="#ffffff")
draw.text((x+6,y-SIZE/2), shortnumber, fill="#000000")
draw.ellipse([(x-4,y-4),(x+4,y+4)], fill=fillcol, outline="#000000")
def writeout_imagemap(data, mapname):
# Munge the list of coordinates into a proper image map.
# There is a wrinkle here: the HTML spec gives priority
# to the _first_ defined elt, so we swap the order!
n = len(data)
htmlfile.write("<map id=\"%s\" name=\"%s\">" % (mapname, mapname))
for j in xrange(n):
try:
i = data[n-j-1]
htmlfile.write("<area shape=\"rect\" coords=\"%d, %d, %d, %d\" href=\"#id%s\" title=\"%s\" />\n" % (i[0],i[1],i[2],i[3],i[4],i[5]))
except:
print "Died on", repr( data[n-j-1] )
#raise
htmlfile.write("</map>")
import csv, re, time
cavetabfile = file("../CAVETAB2.CSV")
fieldnames=chomp(cavetabfile.next()).replace('"','').split(",")
cavetab = csv.DictReader(cavetabfile, fieldnames)
print "Munging lengths.dat"
lengthsfile = file("../lengths.dat")
lengths = {}
for l in lengthsfile:
t = l.replace("\"","").replace("\n", "").split("\t")
lengths[t[0]] = (t[1], t[2])
print "Done"
# Draw cave passage
print "Munging dump3d output"
if exists_in_path("dump3d"):
dump3d_binary = "dump3d"
else:
# assume it's in this directory
dump3d_binary = os.path.join(os.path.dirname(os.path.realpath(__file__)),"./dump3d")
positions = {}
surfacecolour = "#808080"
repath = re.compile(r'^(?:182to(?:tc|184)|tctocol|82to97|vd1to161d|161ftod|161etof|161etog|40entlink2|surfnr161|surf161|kansurf)$')
for fnm in ("../all.3d", "../alltracks.3d"):
for mapcode in draws.keys():
try:
file3d = os.popen(dump3d_binary + " " + fnm)
except:
#dump3d doesn't return an error code on "Couldnt open data file". It should.
print "Running command: %s %s failed: %s" % (dump3d_binary, fnm, file3d)
draw = draws[mapcode]
lastx, lasty = 0, 0
for l in file3d:
match = re.match(r'''
^ #start
(MOVE|LINE|NODE) #command type
\s+(-?[0-9.]+) #X-co-ord
\s+(-?[0-9.]+) #Y-co-ord
\s+(-?[0-9.]+) #altitude
(?:\s+\[(\S*)\])* #node name inside []
(?:\s+(.*))* #all optional flags
$ #till the end of the line
''', l, re.VERBOSE)
if not match:
continue
act,E,N,alt,name,flags = match.groups()
# print "act:%s, E:%s, N:%s, name:%s flags:%s" % (act,E,N,name,flags)
# Only need to process NODEs once
if act == "NODE" and mapcode != "all": continue
if not flags: flags = ""
E,N = map(float, (E,N))
if act == "NODE":
positions[name] = (E,N,float(alt))
continue
x,y = map(int, mungecoord(E, N, mapcode))
if act == "LINE":
if re.search(r'\bSURFACE\b', flags):
if re.search(repath, name):
draw.line([lastx, lasty, x, y], fill='#008000')
else:
draw.line([lastx, lasty, x, y], fill='#808080')
else:
draw.line([lastx, lasty, x, y], fill="#800080")
lastx,lasty = x,y
surfacecolour = "#008000"
repath = re.compile(r'^')
print "Done"
cavestoplot = []
for cave in cavetab:
if cave["Link file"]: continue
number = find_effective_number(cave)
if(cave["Multiple entrances"] not in ["", "yes"]):
number = "&mdash;" + cachednumber + cave["Entrances"]
shortnumber = cachednumber
if not cave["Area"]: cave["Area"] = cachedarea
if not cave["Name"]: cave["Name"] = cachedname
else:
cachednumber = number
shortnumber = number
cachedname = cave["Name"] or cave["Unofficial Name"]
cachedarea = cave["Area"]
area = cave["Area"]
# We have some areas like '2b or 4 (unclear)' - just chop the space
# and everything after it for these.
area = re.sub(r' .*', "", area)
if area == '1626' or area == 'nonexistent': continue
try:
loctuple = find_location(cave)
except:
print "Unable to find location for %s" % (number)
else:
label = find_label(cave, shortnumber)
if(cave["Multiple entrances"] == "yes"):
locn = "<td colspan=\"3\">&nbsp;</td>"
elif(loctuple):
locn = "<td class=\"locn good\">%d</td><td class=\"locn good\">%d</td><td class=\"locn good\">%d</td>" % loctuple
cavestoplot.append((loctuple, number, area, label))
else:
locn = "<td colspan=\"3\" class=%s>" % findability_color(cave) + (cave["Findability"] or '?') + "</td>"
try:
cavelists[area].append((number, cave, locn))
except:
print "Bad area '%s' for cave %s" % (area, number)
if showbg:
htmlfile = file("/dev/null", "w")
else:
htmlfile = file("../../handbook/prospecting_guide.html", "w")
htmlfile.write("<html><head><title>Prospecting Guide</title>\n")
htmlfile.write("<script lang=\"Javascript\"><!--\n");
for maparea in mapcodes:
htmlfile.write("bg%s = false;\n" % maparea);
htmlfile.write("//-->\n</script>\n");
htmlfile.write("""
<style type="text/css">
.locn { font-size: x-small }
.bad { background-color: #ff9955; text-align: center }
.good { background-color: #99f<p><b>Notes:</b></p><ul><li>A marking status of \"Retag\" means a tag is in place but it carries a provisional number, or in some cases an incorrect number, and needs replacing with a new tag.</li>\n<li>Kataster status codes indicate the size of a cave, its character and its exploration status, as described <a href=\"../katast.htm\">here</a>.</li><li>For more info on each cave, see the links to detailed description pages.</li></ul>\nf99; text-align: center }
.awful { background-color: #ff5555; text-align: center }
.notours .good { background-color: #ffffff; }
.notours .bad { background-color: #ffffff; }
.notours .awful { background-color: #ffffff; }
</style></head>""")
htmlfile.write("<body><h1>Prospecting Guide</h1>")
htmlfile.write("<p><small>Generated " + time.strftime("%Y-%m-%d %H:%M:%S %Z") + " by " + sys.argv[0] + "</small></p>\n")
htmlfile.write("<p><b>Notes:</b></p><ul><li>A marking status of \"Retag\" means a tag is in place but it carries a provisional number, or in some cases an incorrect number, and needs replacing with a new tag.</li>\n<li>Kataster status codes indicate the size of a cave, its character and its exploration status, as described <a href=\"../katast.htm\">here</a>.</li><li>For more info on each cave, see the links to detailed description pages.</li></ul>\n")
for maparea in mapcodes:
filename = get_img_name(maparea)
if maparea != "all":
htmlfile.write("<h3 id=\"idsubmap%s\">%s area detail</h3>\n" % (maparea, maps[maparea][DESC]))
basename = filename[0:-3]
htmlfile.write("<button onclick=\"if (bg%s) img%s.src = '%spng'; else img%s.src = '../noinfo/%sjpg'; bg%s = !bg%s;\">Toggle Background</button>\n" % (maparea, maparea, basename, maparea, basename, maparea, maparea))
htmlfile.write("<small>Note: this requires a login to work!</small>\n")
htmlfile.write("<p><img src=\"%s\" usemap=\"#map%s\" ismap=\"ismap\" name=\"img%s\"" % (filename, maparea, maparea))
htmlfile.write(" width=\"%d\" height=\"%d\" /></p>\n" % imgs[maparea].size)
cachednumber = ""
cachedarea = ""
cachedname = ""
# Plot the subareas on the full map
for maparea in maps.keys():
if maparea == "all":
continue
m = maps[maparea]
l,t = mungecoord(m[L], m[T], "all")
r,b = mungecoord(m[R], m[B], "all")
text = maparea + " map"
textlen = draws['all'].textsize(text)[0] + 3
draws['all'].rectangle([l, t, l+textlen, t+SIZE+2], fill='#ffffff')
draws['all'].text((l+2, t+1), text, fill="#000000")
imgmaps['all'].append( [l, t, l+textlen, t+SIZE+2, "submap" + maparea, maparea + " subarea map"] )
draws['all'].rectangle([l, t, r, b], outline='#777777')
draws['all'].rectangle([l, t, l+textlen, t+SIZE+2], outline='#777777')
# Plot faked positions first so that real caves go on top of the large circles
fakedpositions = file("fakedpositions.dat")
for p in fakedpositions:
try:
(x,y,d,name) = re.match(r'\(([0-9.]*?),\t([0-9.]*?),\t([0-9.]*?)\)\t(.*?)[\t ]*#', chomp(p)).groups()
except:
print "Couldn't understand" + repr(chomp(p))
continue
# Find the area with this cave in
area = ''
for tryarea in areas:
for (number, cave, locn) in cavelists[tryarea]:
if name == number:
area = tryarea
break
# FIXME really want to break from both loops at once
# but I don't know how to in Python
if area != '':
break
(x,y,d) = map(float, (x,y,d))
for maparea in maps.keys():
lo = mungecoord(x-d, y+d, maparea)
hi = mungecoord(x+d, y-d, maparea)
lpos = mungecoord(x-d, y, maparea)
draw = draws[maparea]
draw.ellipse([lo,hi], outline="#000000")
draw.ellipse([lo[0]+1, lo[1]+1,hi[0]-1, hi[1]-1], outline=areacolours[area])
draw.ellipse([lo[0]+2, lo[1]+2,hi[0]-2, hi[1]-2], outline=areacolours[area])
draw.rectangle([lpos[0],lpos[1]-SIZE/2, lpos[0] + draw.textsize(name)[0], lpos[1]+SIZE/2], fill="#ffffff")
imgmaps[maparea].append( [lpos[0],lpos[1]-SIZE/2, lpos[0] + draw.textsize(name)[0], lpos[1]+SIZE/2, name, "Approx position of %s" % name] )
draw.text((lpos[0], lpos[1]-SIZE/2), name, fill="#000000")
plot(positions["laser.0_7"], "BNase", "6", "Br&auml;uning Nase laser point")
plot(positions["226-96"], "BZkn", "6", "Br&auml;uning Zinken trig point")
plot(positions["vd1"],"VD1","6", "VD1 survey point")
plot(positions["laser.kt114_96"],"HSK","6", "Hinterer Schwarzmooskogel trig point")
plot(positions["2000"],"Nipple","6", "Nipple (Wei&szlig;e Warze)")
plot(positions["3000"],"VSK","6", "Vorderer Schwarzmooskogel summit")
plot(positions["topcamp"], "TC", "6", "Top Camp")
plot(positions["laser.0"], "LSR0", "6", "Laser Point 0")
plot(positions["laser.0_1"], "LSR1", "6", "Laser Point 0/1")
plot(positions["laser.0_3"], "LSR3", "6", "Laser Point 0/3")
plot(positions["laser.0_5"], "LSR5", "6", "Laser Point 0/5")
plot(positions["225-96"], "BAlm", "6", "Br&auml;uning Alm trig point")
for (loctuple, number, area, label) in cavestoplot:
plot(loctuple, number, area, label)
for area in areas:
if area:
htmlfile.write("<h3><span style=\"background-color: %s; border: 1px solid black\">&nbsp;&nbsp;</span> %s</h3>" % (areacolours.get(area, "#ffffff"), areanames[area]))
else:
htmlfile.write("<h3>Location unclear</h3>")
htmlfile.write("<table border=\"1\">\n")
htmlfile.write("<tr><th>Cave Number</th><th>Name</th><th>Finished</th><th>Survey<br>Data</th><th>Survey<br>Drawn</th><th>Marked</th><th>Photo</th><th>E</th><th>N</th><th>Alt</th><th>Location</th>")
for (number, cave, locn) in cavelists[area]:
# We only check the "oursness" for the first entrance.
if cave["Multiple entrances"] in ["", "yes"]:
notours = not re.search(r'CUCC', cave['Explorers'])
if notours:
htmlfile.write("<tr class=\"notours\">")
else:
htmlfile.write("<tr>")
if cave["Autogen file"]:
htmlfile.write("<td><a href=\"../%s\">%s</a></td><td><a id=\"id%s\">%s</a></td>" % (cave["Autogen file"], longnumber(cave, number), number.replace("&mdash;", ""), cave["Name"] or cave["Unofficial Name"]))
else:
htmlfile.write("<td>%s</td><td><a id=\"id%s\">%s</a></td>" % (longnumber(cave, number), number.replace("&mdash;", ""), cave["Name"] or cave["Unofficial Name"]))
htmlfile.write(is_explored(cave))
htmlfile.write(have_survey_data(cave))
htmlfile.write(is_underground_surveyed(cave))
htmlfile.write(is_tagged(cave))
htmlfile.write(has_photo(cave))
htmlfile.write(locn)
if(cave["Findability"] != "Surveyed" and cave["Multiple entrances"] != "yes"):
htmlfile.write("<td class=\"locn\">%s %s</td>" % (cave["Location"], cave["Bearings"]))
htmlfile.write("</tr>\n")
htmlfile.write("</table>\n")
for maparea in imgmaps.keys():
writeout_imagemap(imgmaps[maparea], "map" + maparea)
htmlfile.write("</body></html>")
htmlfile.close()
if showbg:
imgpath = "../"
else:
imgpath = "../../handbook/"
for maparea in imgs.keys():
del draws[maparea]
filename = get_img_name(maparea)
imgs[maparea].save(imgpath + filename)
# vim:syntax=python:set ts=4: