S07: Teilgebiet 01 Iteration B (Iterationen B1, B1.5, B2) durchgezogen. Neue Datei build/build-reference-docx.py baut templates/reference.docx programmatisch aus Pandocs Default-Reference (Python-Stdlib only, kein pip; pandoc --print-default-data-file zur Laufzeit, ZIP entpacken, ElementTree-XML-Anpassungen, repacken). B1: Theme major+minor und alle direkten Schrift-Refs in styles.xml auf Calibri umgestellt (Code-Schriften wie Consolas bleiben), Tabellen-Default-Stil mit tblBorders=none auf allen Sides. B1.5: Body-DocDefault 11 pt, Heading 1/2/3 auf 15/13/12 pt analog PDF. B2: header1.xml (Default ab Seite 2 mit Name links und Lebenslauf rechts), header2.xml (leer fuer Seite 1 via titlePg), footer1.xml (rechts Seite n / m mit PAGE/NUMPAGES-Feldern, doppelt referenziert als default und first damit Seite 1 trotz titlePg den Footer hat). Page-Setup explizit in sectPr: A4 mit 2.2 cm oben/unten und 2.5 cm links/rechts analog PDF, Tab-Stop am rechten Textrand 9072 dxa. Beziehungen mit dynamisch naechster freier rId in document.xml.rels, Content-Types-Overrides in [Content_Types].xml, sectPr regex-ersetzt idempotent. Sandbox-End-to-End mit Pandoc 2.9 verifiziert (sectPr und Header/Footer im generierten DOCX vorhanden). Auf Thomas System: DOCX visuell bestaetigt. teilgebiete/01-lebenslauf.md um vollstaendigen Iteration-B-Block ergaenzt, Naechste-Schritte-Liste auf B3, B4, C, D umstrukturiert. agent-prompt.md Aktueller-Stand-Abschnitt fortgeschrieben mit Hinweisen zur reference-docx-Pipeline (manuell vor build.ps1 aufrufen, nicht von Hand in Word editieren) und zur Edit-Tool-Truncation auf dem NTFS-Mount. Build-UX-Fix in build.ps1 mit 3-Sekunden-Pause pro fehlgeschlagenem Schritt war ebenfalls Teil dieser Session.
This commit is contained in:
401
artefakte/01-lebenslauf/build/build-reference-docx.py
Normal file
401
artefakte/01-lebenslauf/build/build-reference-docx.py
Normal file
@@ -0,0 +1,401 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
build-reference-docx.py
|
||||
=======================
|
||||
|
||||
Baut die templates/reference.docx fuer die Pandoc-DOCX-Pipeline aus der
|
||||
Pandoc-Default-Reference, mit gezielten Anpassungen.
|
||||
|
||||
Iteration B1 + B1.5 + B2 (aktuell):
|
||||
B1 - Theme-Schriften (majorFont und minorFont) beide auf Calibri.
|
||||
B1 - Direkte Schriftnamen-Referenzen in styles.xml auf Calibri
|
||||
(Code-Schriften wie Consolas bleiben).
|
||||
B1 - Tabellen-Default-Stil "Table" mit tblBorders=none.
|
||||
B1.5 - Body-DocDefault 11pt, Heading 1/2/3 auf 15/13/12 pt.
|
||||
B2 - Header (Name links, "Lebenslauf" rechts) ab Seite 2; Seite 1 mit
|
||||
leerem Header (titlePg-Mechanik). Footer (rechts: Seite n / m) auf
|
||||
allen Seiten inkl. Seite 1 (footer-Ref fuer "first" zeigt auf den
|
||||
gleichen Footer wie "default"). Page-Setup explizit: A4, Raender
|
||||
analog PDF (top/bottom 2.2 cm, left/right 2.5 cm). Damit ist der
|
||||
Tab-Stop deterministisch unabhaengig von Word-Locale-Defaults.
|
||||
|
||||
Geplant in Folge-Iterationen:
|
||||
B3 - Heading-Stile mit "keep with next", Widow/Orphan-Control auf Stilebene
|
||||
B4 - optional Heading-Farben auf DesTEngS-Blau analog PDF
|
||||
|
||||
Vorgehen:
|
||||
1. Pandoc-Default-Reference per `pandoc --print-default-data-file
|
||||
reference.docx` extrahieren.
|
||||
2. Als ZIP entpacken.
|
||||
3. Relevante XML-Dateien anpassen, neue Header/Footer-XMLs anlegen,
|
||||
Beziehungen und ContentTypes ergaenzen, sectPr setzen.
|
||||
4. Als neue ZIP-Datei (templates/reference.docx) speichern.
|
||||
|
||||
Voraussetzungen: nur Python-Stdlib + Pandoc im PATH.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
# --- Pfade -----------------------------------------------------------------
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
BASE_DIR = SCRIPT_DIR.parent
|
||||
TEMPLATES_DIR = BASE_DIR / "templates"
|
||||
OUTPUT_FILE = TEMPLATES_DIR / "reference.docx"
|
||||
|
||||
# --- XML-Namespaces --------------------------------------------------------
|
||||
|
||||
NS = {
|
||||
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||
"a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||
"r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||
"rel": "http://schemas.openxmlformats.org/package/2006/relationships",
|
||||
"ct": "http://schemas.openxmlformats.org/package/2006/content-types",
|
||||
}
|
||||
for prefix, uri in NS.items():
|
||||
ET.register_namespace(prefix, uri)
|
||||
ET.register_namespace("", NS["rel"])
|
||||
|
||||
W = "{%s}" % NS["w"]
|
||||
A = "{%s}" % NS["a"]
|
||||
|
||||
# --- Konfiguration ---------------------------------------------------------
|
||||
|
||||
CODE_FONTS = {"consolas", "courier", "courier new", "liberation mono",
|
||||
"monaco", "menlo", "fira mono", "fira code"}
|
||||
TARGET_FONT = "Calibri"
|
||||
|
||||
SIZE_BODY = 22
|
||||
SIZE_HEADING1 = 30
|
||||
SIZE_HEADING2 = 26
|
||||
SIZE_HEADING3 = 24
|
||||
HEADING_SIZES = {"Heading1": SIZE_HEADING1,
|
||||
"Heading2": SIZE_HEADING2,
|
||||
"Heading3": SIZE_HEADING3}
|
||||
|
||||
# Page-Setup (in DXA, 1cm = 566.929 dxa; 1 inch = 1440 dxa)
|
||||
# A4: 21.0 x 29.7 cm
|
||||
PAGE_W = 11906 # A4 Breite
|
||||
PAGE_H = 16838 # A4 Hoehe
|
||||
MARGIN_TOP = 1247 # 2.2 cm
|
||||
MARGIN_BOT = 1247 # 2.2 cm
|
||||
MARGIN_LEFT = 1417 # 2.5 cm
|
||||
MARGIN_RIGHT = 1417 # 2.5 cm
|
||||
HEADER_POS = 720 # 1.27 cm vom oberen Seitenrand
|
||||
FOOTER_POS = 720 # 1.27 cm vom unteren Seitenrand
|
||||
# Tab-Stop am rechten Textrand: PAGE_W - LEFT - RIGHT = 9072 dxa = 16 cm
|
||||
HEADER_RIGHT_TAB = PAGE_W - MARGIN_LEFT - MARGIN_RIGHT
|
||||
|
||||
HEADER_LEFT = "Dr.-Ing. Thomas Langer"
|
||||
HEADER_RIGHT = "Lebenslauf"
|
||||
|
||||
# --- Hilfsfunktionen -------------------------------------------------------
|
||||
|
||||
def log(msg: str) -> None:
|
||||
print(f"[build-reference-docx] {msg}", flush=True)
|
||||
|
||||
XML_DECL = b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n'
|
||||
|
||||
def write_xml(tree: ET.ElementTree, dest: Path) -> None:
|
||||
body = ET.tostring(tree.getroot(), encoding="utf-8")
|
||||
dest.write_bytes(XML_DECL + body)
|
||||
|
||||
def write_xml_bytes(content: bytes, dest: Path) -> None:
|
||||
dest.write_bytes(XML_DECL + content)
|
||||
|
||||
def fetch_pandoc_default(dest: Path) -> None:
|
||||
log("Pandoc-Default-Reference extrahieren ...")
|
||||
result = subprocess.run(
|
||||
["pandoc", "--print-default-data-file", "reference.docx"],
|
||||
capture_output=True, check=False,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
sys.stderr.write(result.stderr.decode("utf-8", errors="replace"))
|
||||
raise SystemExit(f"pandoc liefert Exit-Code {result.returncode}")
|
||||
dest.write_bytes(result.stdout)
|
||||
log(f" -> {dest} ({dest.stat().st_size} Bytes)")
|
||||
|
||||
def unpack_docx(src: Path, dest_dir: Path) -> None:
|
||||
with zipfile.ZipFile(src, "r") as z:
|
||||
z.extractall(dest_dir)
|
||||
|
||||
def repack_docx(src_dir: Path, dest: Path) -> None:
|
||||
files = []
|
||||
for path in src_dir.rglob("*"):
|
||||
if path.is_file():
|
||||
arcname = path.relative_to(src_dir).as_posix()
|
||||
files.append((path, arcname))
|
||||
files.sort(key=lambda t: (0 if t[1] == "[Content_Types].xml" else 1, t[1]))
|
||||
with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as z:
|
||||
for path, arcname in files:
|
||||
z.write(path, arcname)
|
||||
|
||||
def is_code_font(name: str) -> bool:
|
||||
return (name or "").strip().lower() in CODE_FONTS
|
||||
|
||||
# --- B1: Schriften ---------------------------------------------------------
|
||||
|
||||
def set_theme_fonts_to_calibri(theme_xml: Path) -> None:
|
||||
tree = ET.parse(theme_xml)
|
||||
root = tree.getroot()
|
||||
for kind in ("majorFont", "minorFont"):
|
||||
font = root.find(f".//{A}{kind}")
|
||||
if font is None:
|
||||
raise RuntimeError(f"{kind}-Element nicht im Theme")
|
||||
latin = font.find(f"{A}latin")
|
||||
if latin is None:
|
||||
raise RuntimeError(f"{kind}/latin-Element nicht gefunden")
|
||||
old = latin.get("typeface")
|
||||
latin.set("typeface", TARGET_FONT)
|
||||
log(f" Theme {kind}/latin: {old!r} -> {TARGET_FONT!r}")
|
||||
write_xml(tree, theme_xml)
|
||||
|
||||
def replace_direct_fonts_in_styles(styles_xml: Path) -> None:
|
||||
tree = ET.parse(styles_xml)
|
||||
root = tree.getroot()
|
||||
changed = 0
|
||||
skipped = 0
|
||||
for rfonts in root.iter(f"{W}rFonts"):
|
||||
for attr in (f"{W}ascii", f"{W}hAnsi", f"{W}cs", f"{W}eastAsia"):
|
||||
val = rfonts.get(attr)
|
||||
if val is None:
|
||||
continue
|
||||
if is_code_font(val):
|
||||
skipped += 1
|
||||
continue
|
||||
if val != TARGET_FONT:
|
||||
rfonts.set(attr, TARGET_FONT)
|
||||
changed += 1
|
||||
log(f" styles.xml: {changed} direkte Font-Attribute auf {TARGET_FONT!r}"
|
||||
f" gesetzt (Code-Fonts unangetastet: {skipped})")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
# --- B1: Tabellen ----------------------------------------------------------
|
||||
|
||||
def set_table_borders_none(styles_xml: Path) -> None:
|
||||
tree = ET.parse(styles_xml)
|
||||
root = tree.getroot()
|
||||
style = next((s for s in root.findall(f"{W}style")
|
||||
if s.get(f"{W}styleId") == "Table"), None)
|
||||
if style is None:
|
||||
raise RuntimeError("Style 'Table' nicht in styles.xml")
|
||||
tbl_pr = style.find(f"{W}tblPr") or ET.SubElement(style, f"{W}tblPr")
|
||||
existing = tbl_pr.find(f"{W}tblBorders")
|
||||
if existing is not None:
|
||||
tbl_pr.remove(existing)
|
||||
borders = ET.SubElement(tbl_pr, f"{W}tblBorders")
|
||||
for side in ("top", "left", "bottom", "right", "insideH", "insideV"):
|
||||
e = ET.SubElement(borders, f"{W}{side}")
|
||||
e.set(f"{W}val", "none")
|
||||
e.set(f"{W}sz", "0")
|
||||
e.set(f"{W}space", "0")
|
||||
e.set(f"{W}color", "auto")
|
||||
log(" Style 'Table': tblBorders=none auf allen Sides")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
# --- B1.5: Schriftgroessen ------------------------------------------------
|
||||
|
||||
def set_default_body_size(styles_xml: Path) -> None:
|
||||
tree = ET.parse(styles_xml)
|
||||
root = tree.getroot()
|
||||
docDefaults = root.find(f"{W}docDefaults") or ET.SubElement(root, f"{W}docDefaults")
|
||||
rPrDefault = docDefaults.find(f"{W}rPrDefault") or ET.SubElement(docDefaults, f"{W}rPrDefault")
|
||||
rPr = rPrDefault.find(f"{W}rPr") or ET.SubElement(rPrDefault, f"{W}rPr")
|
||||
for tag in (f"{W}sz", f"{W}szCs"):
|
||||
elem = rPr.find(tag) or ET.SubElement(rPr, tag)
|
||||
elem.set(f"{W}val", str(SIZE_BODY))
|
||||
log(f" DocDefault Body-Schriftgroesse: {SIZE_BODY/2} pt")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
def set_heading_sizes(styles_xml: Path) -> None:
|
||||
tree = ET.parse(styles_xml)
|
||||
root = tree.getroot()
|
||||
for style in root.findall(f"{W}style"):
|
||||
sid = style.get(f"{W}styleId")
|
||||
if sid not in HEADING_SIZES:
|
||||
continue
|
||||
target = HEADING_SIZES[sid]
|
||||
rPr = style.find(f"{W}rPr") or ET.SubElement(style, f"{W}rPr")
|
||||
for tag in (f"{W}sz", f"{W}szCs"):
|
||||
elem = rPr.find(tag) or ET.SubElement(rPr, tag)
|
||||
elem.set(f"{W}val", str(target))
|
||||
log(f" Stil {sid!r}: Schriftgroesse {target/2} pt")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
# --- B2: Header und Footer ------------------------------------------------
|
||||
|
||||
def header_default_xml() -> bytes:
|
||||
return (
|
||||
b'<w:hdr xmlns:w="' + NS["w"].encode() + b'">\n'
|
||||
b' <w:p>\n'
|
||||
b' <w:pPr>\n'
|
||||
b' <w:tabs>\n'
|
||||
b' <w:tab w:val="right" w:pos="' + str(HEADER_RIGHT_TAB).encode() + b'"/>\n'
|
||||
b' </w:tabs>\n'
|
||||
b' </w:pPr>\n'
|
||||
b' <w:r><w:t xml:space="preserve">' + HEADER_LEFT.encode() + b'</w:t></w:r>\n'
|
||||
b' <w:r><w:tab/><w:t xml:space="preserve">' + HEADER_RIGHT.encode() + b'</w:t></w:r>\n'
|
||||
b' </w:p>\n'
|
||||
b'</w:hdr>\n'
|
||||
)
|
||||
|
||||
def header_first_blank_xml() -> bytes:
|
||||
return (
|
||||
b'<w:hdr xmlns:w="' + NS["w"].encode() + b'">\n'
|
||||
b' <w:p/>\n'
|
||||
b'</w:hdr>\n'
|
||||
)
|
||||
|
||||
def footer_default_xml() -> bytes:
|
||||
return (
|
||||
b'<w:ftr xmlns:w="' + NS["w"].encode() + b'">\n'
|
||||
b' <w:p>\n'
|
||||
b' <w:pPr>\n'
|
||||
b' <w:tabs>\n'
|
||||
b' <w:tab w:val="right" w:pos="' + str(HEADER_RIGHT_TAB).encode() + b'"/>\n'
|
||||
b' </w:tabs>\n'
|
||||
b' </w:pPr>\n'
|
||||
b' <w:r><w:tab/><w:t xml:space="preserve">Seite </w:t></w:r>\n'
|
||||
b' <w:fldSimple w:instr="PAGE">\n'
|
||||
b' <w:r><w:t>1</w:t></w:r>\n'
|
||||
b' </w:fldSimple>\n'
|
||||
b' <w:r><w:t xml:space="preserve"> / </w:t></w:r>\n'
|
||||
b' <w:fldSimple w:instr="NUMPAGES">\n'
|
||||
b' <w:r><w:t>1</w:t></w:r>\n'
|
||||
b' </w:fldSimple>\n'
|
||||
b' </w:p>\n'
|
||||
b'</w:ftr>\n'
|
||||
)
|
||||
|
||||
REL_HEADER = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header"
|
||||
REL_FOOTER = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer"
|
||||
CT_HEADER = "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"
|
||||
CT_FOOTER = "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"
|
||||
|
||||
def next_free_rel_id(rels_xml: Path) -> int:
|
||||
text = rels_xml.read_text(encoding="utf-8")
|
||||
ids = [int(m.group(1)) for m in re.finditer(r'Id="rId(\d+)"', text)]
|
||||
return (max(ids) + 1) if ids else 1
|
||||
|
||||
def add_relationship(rels_xml: Path, rid: str, rtype: str, target: str) -> None:
|
||||
text = rels_xml.read_text(encoding="utf-8")
|
||||
new_rel = f'<Relationship Type="{rtype}" Id="{rid}" Target="{target}" />'
|
||||
if new_rel in text:
|
||||
return
|
||||
text = text.replace("</Relationships>", new_rel + "</Relationships>")
|
||||
rels_xml.write_text(text, encoding="utf-8")
|
||||
|
||||
def add_content_type_override(ct_xml: Path, part_name: str, ct: str) -> None:
|
||||
text = ct_xml.read_text(encoding="utf-8")
|
||||
new_override = f'<Override PartName="{part_name}" ContentType="{ct}"/>'
|
||||
if part_name in text:
|
||||
return
|
||||
text = text.replace("</Types>", new_override + "</Types>")
|
||||
ct_xml.write_text(text, encoding="utf-8")
|
||||
|
||||
def update_sectpr_with_headers(document_xml: Path,
|
||||
header_default_rid: str,
|
||||
header_first_rid: str,
|
||||
footer_default_rid: str) -> None:
|
||||
"""Ersetzt sectPr durch Page-Setup + Header/Footer-Refs + titlePg.
|
||||
Footer-Ref wird zweimal eingebaut (default und first), beide auf
|
||||
den gleichen Footer — dann hat Seite 1 trotz titlePg den Footer."""
|
||||
text = document_xml.read_text(encoding="utf-8")
|
||||
new_sectpr = (
|
||||
f'<w:sectPr>'
|
||||
f'<w:headerReference w:type="default" r:id="{header_default_rid}"/>'
|
||||
f'<w:headerReference w:type="first" r:id="{header_first_rid}"/>'
|
||||
f'<w:footerReference w:type="default" r:id="{footer_default_rid}"/>'
|
||||
f'<w:footerReference w:type="first" r:id="{footer_default_rid}"/>'
|
||||
f'<w:pgSz w:w="{PAGE_W}" w:h="{PAGE_H}"/>'
|
||||
f'<w:pgMar w:top="{MARGIN_TOP}" w:right="{MARGIN_RIGHT}"'
|
||||
f' w:bottom="{MARGIN_BOT}" w:left="{MARGIN_LEFT}"'
|
||||
f' w:header="{HEADER_POS}" w:footer="{FOOTER_POS}" w:gutter="0"/>'
|
||||
f'<w:titlePg/>'
|
||||
f'</w:sectPr>'
|
||||
)
|
||||
new_text, n = re.subn(
|
||||
r'<w:sectPr\s*/>|<w:sectPr>.*?</w:sectPr>',
|
||||
new_sectpr, text, flags=re.DOTALL,
|
||||
)
|
||||
if n == 0:
|
||||
new_text = text.replace("</w:body>", new_sectpr + "</w:body>")
|
||||
document_xml.write_text(new_text, encoding="utf-8")
|
||||
log(f" document.xml sectPr: pgSz/pgMar (A4, 2.2/2.5cm Raender), Header"
|
||||
f" default+first, Footer default+first auf gleicher rId, titlePg")
|
||||
|
||||
def add_header_footer(unpacked: Path) -> None:
|
||||
word_dir = unpacked / "word"
|
||||
rels_xml = word_dir / "_rels" / "document.xml.rels"
|
||||
ct_xml = unpacked / "[Content_Types].xml"
|
||||
doc_xml = word_dir / "document.xml"
|
||||
|
||||
write_xml_bytes(header_default_xml(), word_dir / "header1.xml")
|
||||
write_xml_bytes(header_first_blank_xml(), word_dir / "header2.xml")
|
||||
write_xml_bytes(footer_default_xml(), word_dir / "footer1.xml")
|
||||
log(" word/header1.xml (default), header2.xml (first blank),"
|
||||
" footer1.xml geschrieben")
|
||||
|
||||
next_id = next_free_rel_id(rels_xml)
|
||||
rid_h_def, rid_h_first, rid_f_def = (f"rId{next_id+i}" for i in range(3))
|
||||
add_relationship(rels_xml, rid_h_def, REL_HEADER, "header1.xml")
|
||||
add_relationship(rels_xml, rid_h_first, REL_HEADER, "header2.xml")
|
||||
add_relationship(rels_xml, rid_f_def, REL_FOOTER, "footer1.xml")
|
||||
log(f" Beziehungen: {rid_h_def}=header1, {rid_h_first}=header2,"
|
||||
f" {rid_f_def}=footer1")
|
||||
|
||||
add_content_type_override(ct_xml, "/word/header1.xml", CT_HEADER)
|
||||
add_content_type_override(ct_xml, "/word/header2.xml", CT_HEADER)
|
||||
add_content_type_override(ct_xml, "/word/footer1.xml", CT_FOOTER)
|
||||
log(" [Content_Types].xml: Override-Eintraege fuer header1/2 und footer1")
|
||||
|
||||
update_sectpr_with_headers(doc_xml, rid_h_def, rid_h_first, rid_f_def)
|
||||
|
||||
# --- Hauptablauf -----------------------------------------------------------
|
||||
|
||||
def main() -> int:
|
||||
log(f"Ziel: {OUTPUT_FILE}")
|
||||
TEMPLATES_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="refdocx-") as tmp:
|
||||
tmp_dir = Path(tmp)
|
||||
default_docx = tmp_dir / "pandoc-default.docx"
|
||||
unpacked = tmp_dir / "unpacked"
|
||||
|
||||
fetch_pandoc_default(default_docx)
|
||||
unpacked.mkdir()
|
||||
unpack_docx(default_docx, unpacked)
|
||||
|
||||
theme_xml = unpacked / "word" / "theme" / "theme1.xml"
|
||||
styles_xml = unpacked / "word" / "styles.xml"
|
||||
|
||||
log("Anpassung: Theme major+minor auf Calibri")
|
||||
set_theme_fonts_to_calibri(theme_xml)
|
||||
log("Anpassung: Direkte Font-Referenzen in styles.xml -> Calibri")
|
||||
replace_direct_fonts_in_styles(styles_xml)
|
||||
log("Anpassung: Tabellen-Default ohne Rahmen")
|
||||
set_table_borders_none(styles_xml)
|
||||
log("Anpassung: Body-Schriftgroesse 11 pt (DocDefault)")
|
||||
set_default_body_size(styles_xml)
|
||||
log("Anpassung: Heading-Schriftgroessen 15/13/12 pt")
|
||||
set_heading_sizes(styles_xml)
|
||||
log("Anpassung: Header und Footer einbauen (B2)")
|
||||
add_header_footer(unpacked)
|
||||
|
||||
log("Repack als reference.docx")
|
||||
repack_docx(unpacked, OUTPUT_FILE)
|
||||
log(f" -> {OUTPUT_FILE} ({OUTPUT_FILE.stat().st_size} Bytes)")
|
||||
|
||||
log("Fertig.")
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user