#!/usr/bin/env python3 """WING-OPS 사용자 매뉴얼 챕터별 PDF 생성. `frontend/src/common/data/chapters.json`을 읽어 `frontend/public/manual/pdfs/ch01.pdf ~ ch08.pdf`를 생성한다. 사용법: pip install -r requirements.txt python generate.py """ from __future__ import annotations import json from pathlib import Path from jinja2 import Environment, FileSystemLoader, select_autoescape from weasyprint import HTML SCRIPT_DIR = Path(__file__).resolve().parent REPO_ROOT = SCRIPT_DIR.parent.parent DATA_FILE = REPO_ROOT / 'frontend' / 'src' / 'common' / 'data' / 'chapters.json' PUBLIC_DIR = REPO_ROOT / 'frontend' / 'public' OUT_DIR = PUBLIC_DIR / 'manual' / 'pdfs' def load_chapters() -> list[dict]: with DATA_FILE.open(encoding='utf-8') as fp: return json.load(fp) def render_pdf(chapter: dict, env: Environment) -> None: template = env.get_template('template.html') html_str = template.render(chapter=chapter) # base_url: 템플릿 내부의 상대경로(manual/imageN.png, style.css)가 # frontend/public 및 scripts/generate_manual_pdfs 양쪽을 참조하므로 # public 을 base 로 두고 style.css 는 절대경로로 포함한다. style_path = SCRIPT_DIR / 'style.css' html_with_style = html_str.replace( 'href="style.css"', f'href="file://{style_path}"', ) out_path = OUT_DIR / f'{chapter["id"]}.pdf' HTML(string=html_with_style, base_url=str(PUBLIC_DIR)).write_pdf(str(out_path)) print(f' {out_path.relative_to(REPO_ROOT)} ({out_path.stat().st_size // 1024} KB)') def main() -> None: if not DATA_FILE.exists(): raise SystemExit(f'chapters.json not found: {DATA_FILE}') OUT_DIR.mkdir(parents=True, exist_ok=True) chapters = load_chapters() print(f'Loaded {len(chapters)} chapters from {DATA_FILE.relative_to(REPO_ROOT)}') env = Environment( loader=FileSystemLoader(str(SCRIPT_DIR)), autoescape=select_autoescape(['html']), ) for chapter in chapters: print(f'Rendering CH {chapter["number"]} · {chapter["title"]} ({len(chapter["screens"])} screens)') render_pdf(chapter, env) print(f'\nDone. Output: {OUT_DIR.relative_to(REPO_ROOT)}/') if __name__ == '__main__': main()