#!/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 [Seitenzahlen.json] Erzeugt /handbuch.html (und img/). Die PDF-Datei entsteht danach mit print_pdf.js (Electron). Kapitel-Dateien nutzen:

,

,

(Nummern und Inhaltsverzeichnis entstehen automatisch) Bildunterschrift (Bild aus den Ordnern der Aufnahmen)
…
, , """ 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 '
[Bild fehlt: %s]
' % html.escape(name) fig_no[0] += 1 narrow = ' narrow' if Image.open(os.path.join(img_out, name + '.jpg')).width < 500 else '' return ('
Abbildung %d: %s
' % (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_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 '

%s

' % text anchor = 'k' + num.replace('.', '_') plain = html.unescape(re.sub(r'<[^>]+>', '', text)) toc.append((lvl, num, plain, anchor)) return '%s %s' % (lvl, anchor, num, text, lvl) body = re.sub(r'(.*?)', head_sub, body, flags=re.S) toc_html = ['

Inhaltsverzeichnis

'] for lvl, num, plain, anchor in toc: p = pages.get(anchor, '') toc_html.append('%s%s%s' % (lvl, anchor, num, html.escape(plain), p)) toc_html.append('
') 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 = ('DeskHub Handbuch' '%s%s%s
%s
') % (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('%s' % (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'))