#!/usr/bin/env python3 """ build_deck.py — 템플릿 스타일 + 제안서 콘텐츠(JSON) → proposal.pptx 생성. deck-designer가 프로젝트별 콘텐츠 JSON만 주입해 재생성 가능한 골격 스크립트. 디자인 시스템(색/폰트)·선 아이콘(SVG는 사전 PNG/EMF 변환 또는 도형)·도식은 deck-designer가 채운다. 사용: python build_deck.py --content content.json [--template template.pptx] --out proposal.pptx content.json 예: { "design": {"primary":"1F4E79","accent":"2E9BD6","text":"222222","font_ko":"맑은 고딕"}, "slides": [ {"layout":"title", "title":"○○시스템 구축 제안서", "subtitle":"제안사 / 2026"}, {"layout":"section", "title":"1. 사업 이해"}, {"layout":"content", "title":"추진 전략", "bullets":["...","..."]}, {"layout":"diagram", "title":"추진 체계도", "note":"도형은 deck-designer가 보강"} ] } 의존: pip install python-pptx · 외부 호출 없음. """ import sys, json, argparse def hex_color(s): from pptx.dml.color import RGBColor return RGBColor.from_string(s) def main(): ap = argparse.ArgumentParser() ap.add_argument("--content", required=True) ap.add_argument("--template") ap.add_argument("--out", default="proposal.pptx") a = ap.parse_args() try: from pptx import Presentation from pptx.util import Inches, Pt from pptx.enum.text import PP_ALIGN except ImportError: print("python-pptx 미설치 → pip install python-pptx", file=sys.stderr); sys.exit(2) with open(a.content, encoding="utf-8") as f: data = json.load(f) design = data.get("design", {}) primary = design.get("primary", "1F4E79") accent = design.get("accent", "2E9BD6") text_c = design.get("text", "222222") font_ko = design.get("font_ko", "맑은 고딕") prs = Presentation(a.template) if a.template else Presentation() blank = prs.slide_layouts[6] if len(prs.slide_layouts) > 6 else prs.slide_layouts[-1] W, H = prs.slide_width, prs.slide_height def add_text(slide, txt, left, top, width, height, size, color, bold=False, align=PP_ALIGN.LEFT): tb = slide.shapes.add_textbox(left, top, width, height) tf = tb.text_frame; tf.word_wrap = True p = tf.paragraphs[0]; p.alignment = align r = p.add_run(); r.text = txt r.font.size = Pt(size); r.font.bold = bold r.font.name = font_ko; r.font.color.rgb = hex_color(color) return tb for s in data.get("slides", []): slide = prs.slides.add_slide(blank) layout = s.get("layout", "content") title = s.get("title", "") if layout == "title": # 상단 컬러 바 bar = slide.shapes.add_shape(1, 0, 0, W, Inches(2.2)) bar.fill.solid(); bar.fill.fore_color.rgb = hex_color(primary); bar.line.fill.background() add_text(slide, title, Inches(0.8), Inches(0.7), W - Inches(1.6), Inches(1.2), 36, "FFFFFF", True) if s.get("subtitle"): add_text(slide, s["subtitle"], Inches(0.8), Inches(2.5), W - Inches(1.6), Inches(0.8), 18, text_c) elif layout == "section": bar = slide.shapes.add_shape(1, 0, Inches(2.6), W, Inches(1.6)) bar.fill.solid(); bar.fill.fore_color.rgb = hex_color(accent); bar.line.fill.background() add_text(slide, title, Inches(0.8), Inches(2.9), W - Inches(1.6), Inches(1.0), 30, "FFFFFF", True) else: # 제목 + 강조 underline add_text(slide, title, Inches(0.7), Inches(0.5), W - Inches(1.4), Inches(0.9), 26, primary, True) ul = slide.shapes.add_shape(1, Inches(0.7), Inches(1.35), Inches(2.2), Pt(3)) ul.fill.solid(); ul.fill.fore_color.rgb = hex_color(accent); ul.line.fill.background() top = Inches(1.8) for b in s.get("bullets", []): add_text(slide, "• " + b, Inches(0.9), top, W - Inches(1.8), Inches(0.6), 16, text_c) top += Inches(0.55) if s.get("note"): add_text(slide, s["note"], Inches(0.9), H - Inches(0.8), W - Inches(1.8), Inches(0.5), 11, "888888") prs.save(a.out) print(f"생성: {a.out} (slides={len(data.get('slides', []))})") if __name__ == "__main__": main()