74 lines
2.2 KiB
Python
74 lines
2.2 KiB
Python
#!/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()
|