110 lines
4.7 KiB
Python
110 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
tools/manual/build_manual.py: setzt das Handbuch zusammen (Kapitel aus tools/manual/handbuch/ch*.html + Bilder).
|
|
|
|
python build_manual.py <Bilder-Web> <Bilder-Windows> <Ausgabeordner> [Seitenzahlen.json]
|
|
|
|
Erzeugt <Ausgabeordner>/handbuch.html (und img/). Die PDF-Datei entsteht danach mit print_pdf.js (Electron).
|
|
Kapitel-Dateien nutzen: <h1>, <h2>, <h3> (Nummern und Inhaltsverzeichnis entstehen automatisch)
|
|
<fig n="bildname">Bildunterschrift</fig> (Bild aus den Ordnern der Aufnahmen)
|
|
<div class="tip|warn|note">…</div>, <table>, <kbd>
|
|
"""
|
|
import html
|
|
import io
|
|
import json
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
from PIL import Image
|
|
|
|
here = os.path.dirname(os.path.abspath(__file__))
|
|
web_dir, win_dir, out_dir = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
pages = {}
|
|
if len(sys.argv) > 4 and os.path.exists(sys.argv[4]):
|
|
pages = json.load(io.open(sys.argv[4], encoding='utf-8'))
|
|
img_out = os.path.join(out_dir, 'img')
|
|
os.makedirs(img_out, exist_ok=True)
|
|
|
|
VERSION = 'Server 1.1.0 · Windows-Programm 2.12.3 · Android-App 3.5.3 · Chrome-Erweiterung 2.1.1 · WordPress-Plugin 1.3.0 · Minecraft-Plugin 1.2.0'
|
|
used = set()
|
|
missing = []
|
|
fig_no = [0]
|
|
|
|
|
|
def prep_image(name):
|
|
"""Bild kopieren (als JPEG, zu hohe Bilder werden unten abgeschnitten)."""
|
|
src = os.path.join(win_dir if name.startswith('windows-') else web_dir, name + '.png')
|
|
if not os.path.exists(src):
|
|
missing.append(name)
|
|
return None
|
|
dst = os.path.join(img_out, name + '.jpg')
|
|
if not os.path.exists(dst) or os.path.getmtime(dst) < os.path.getmtime(src):
|
|
im = Image.open(src).convert('RGB')
|
|
if im.height > 1650 and im.width > 300:
|
|
im = im.crop((0, 0, im.width, 1650))
|
|
im.save(dst, 'JPEG', quality=86, optimize=True)
|
|
used.add(name)
|
|
return 'img/' + name + '.jpg'
|
|
|
|
|
|
def fig_sub(m):
|
|
name, cap = m.group(1), m.group(2).strip()
|
|
path = prep_image(name)
|
|
if not path:
|
|
return '<div class="warn">[Bild fehlt: %s]</div>' % html.escape(name)
|
|
fig_no[0] += 1
|
|
narrow = ' narrow' if Image.open(os.path.join(img_out, name + '.jpg')).width < 500 else ''
|
|
return ('<figure class="%s"><img src="%s" alt=""><figcaption><b>Abbildung %d:</b> %s</figcaption></figure>'
|
|
% (narrow.strip(), path, fig_no[0], cap))
|
|
|
|
|
|
chapters = []
|
|
for fn in sorted(os.listdir(os.path.join(here, 'handbuch'))):
|
|
if fn.startswith('ch') and fn.endswith('.html'):
|
|
chapters.append(io.open(os.path.join(here, 'handbuch', fn), encoding='utf-8').read())
|
|
body = '\n'.join(chapters)
|
|
body = re.sub(r'<fig n="([^"]+)">(.*?)</fig>', fig_sub, body, flags=re.S)
|
|
|
|
# Nummerieren, Anker und Inhaltsverzeichnis
|
|
toc = []
|
|
c1 = [0]
|
|
c2 = [0]
|
|
|
|
|
|
def head_sub(m):
|
|
lvl, text = int(m.group(1)), m.group(2).strip()
|
|
if lvl == 1:
|
|
c1[0] += 1
|
|
c2[0] = 0
|
|
num = str(c1[0])
|
|
elif lvl == 2:
|
|
c2[0] += 1
|
|
num = '%d.%d' % (c1[0], c2[0])
|
|
else:
|
|
return '<h3>%s</h3>' % text
|
|
anchor = 'k' + num.replace('.', '_')
|
|
plain = html.unescape(re.sub(r'<[^>]+>', '', text))
|
|
toc.append((lvl, num, plain, anchor))
|
|
return '<h%d id="%s"><span class="num">%s</span> %s</h%d>' % (lvl, anchor, num, text, lvl)
|
|
|
|
|
|
body = re.sub(r'<h([12])>(.*?)</h\1>', head_sub, body, flags=re.S)
|
|
|
|
toc_html = ['<div class="toc"><h1 class="plain">Inhaltsverzeichnis</h1>']
|
|
for lvl, num, plain, anchor in toc:
|
|
p = pages.get(anchor, '')
|
|
toc_html.append('<a class="t%d" href="#%s"><span class="tn">%s</span><span class="tt">%s</span><span class="tl"></span><span class="tp">%s</span></a>'
|
|
% (lvl, anchor, num, html.escape(plain), p))
|
|
toc_html.append('</div>')
|
|
|
|
css = io.open(os.path.join(here, 'handbuch', 'manual.css'), encoding='utf-8').read()
|
|
cover = io.open(os.path.join(here, 'handbuch', 'cover.html'), encoding='utf-8').read().replace('{{VERSION}}', VERSION)
|
|
front = io.open(os.path.join(here, 'handbuch', 'front.html'), encoding='utf-8').read()
|
|
doc = ('<!doctype html><html lang="de"><head><meta charset="utf-8"><title>DeskHub Handbuch</title><style>%s</style></head><body>'
|
|
'%s%s%s<main>%s</main></body></html>') % (css, cover, front, '\n'.join(toc_html), body)
|
|
io.open(os.path.join(out_dir, 'handbuch.html'), 'w', encoding='utf-8').write(doc)
|
|
io.open(os.path.join(out_dir, 'cover.html'), 'w', encoding='utf-8').write('<!doctype html><html lang="de"><head><meta charset="utf-8"><style>%s</style></head><body>%s</body></html>' % (css, cover))
|
|
json.dump([{'level': l, 'num': n, 'title': t, 'anchor': a} for l, n, t, a in toc], io.open(os.path.join(out_dir, 'toc.json'), 'w', encoding='utf-8'), ensure_ascii=False)
|
|
print('Kapitel/Abschnitte: %d, Abbildungen: %d, verwendete Bilder: %d, fehlend: %s' % (len(toc), fig_no[0], len(used), missing or 'keine'))
|