SuperAPI AI Directory

doc-pdf

Office & productivity

View repository

Updated 10-15 21:02

About this skill

PDF Generator (doc-pdf)

Overview

with the single weasyprint enginerenders all input as PDF. Regardless of the input form, 입력 → HTML → weasyprint → PDF it is unified into one path, faithfully handling both of the following scenarios.

  1. Styled HTML reports (예: moai-officer:doc-html-report·moai-officer:doc-html-slide output, or user-made design HTML) → renders its own CSS as is to preserve the screen design. Modern CSS layouts such as two-column card grids, custom colors, and web fonts are not broken.
  2. Markdown · structured JSON · plain text → rendered by applying default document formatting (A4, tables, heading styles).

CJK (Korean·Chinese·Japanese) glyphs are blocked from breaking by embedding the bundled Noto Sans CJK font as @font-face, and if Noto Sans CJK KRis installed on the system, fontconfig automatically falls back.

Why the single weasyprint engine: weasyprint faithfully renders full CSS (layout, color, web fonts, tables). "Turn this HTML report into a PDF exactly as designed" is the most common request, and this path satisfies that requirement precisely. Coordinate-based low-level rendering (e.g. PyMuPDF insert_text) cannot reproduce modern CSS layouts, so it is not used.

Workflow

0. [폰트 확인]  → 시스템 Noto Sans CJK KR 존재 확인, 없으면 폰트 미지정 폴백 (weasyprint fontconfig 자동 폴백)
1. [입력 감지]  → HTML(완성 문서) / Markdown / JSON / Text 자동 감지
2. [HTML 빌드]  → 완성 HTML은 그대로, 그 외는 HTML로 변환 (+ 기본 문서 CSS)
3. [폰트 주입]  → Noto Sans CJK @font-face CSS 결합 (CJK 깨짐 방지)
4. [렌더]       → weasyprint HTML.write_pdf() 로 A4 PDF 생성
5. [자체 검수]  → 산출 PDF 재확인 (페이지 수·CJK 표시·플레이스홀더 잔존)

The core execution is performed directly with the inline weasyprint code below (no separate script). It detects HTML / Markdown / JSON / Text by the input file extension and content, branches accordingly, preserves the completed HTML's own CSS, and applies default formatting + Noto Sans CJK to the rest.

Step 0: Font assurance (conditional path)

CJK fonts are handled in the following priority order — without a separate download script:

  1. System fonts first: if Noto Sans CJK KRis installed on the system, weasyprint fontconfig automatically falls back, so @font-face CJK is displayed safely even without it. This applies to most Cowork sandboxes and Linux/macOS.

  2. Embed if bundled fonts exist: ${CLAUDE_PLUGIN_ROOT}/skills/doc-pdf/assets/fonts/If Noto Sans CJK OTF exists in @font-faceis automatically embedded by

  3. When neither exists: guide the user to install system Noto Sans CJK KR . The commands by operating system are as follows, and automatic bulk downloading is not performed.

    OS Install
    Windows fonts.google.com/noto/specimen/Noto+Sans+KRDownload from , extract the archive → select all font files → right-click → Install
    macOS brew install --cask font-noto-sans-cjk-kr
    Debian/Ubuntu apt install fonts-noto-cjk

Steps 1–4: weasyprint rendering inline code

Run the code below as is:

from weasyprint import HTML, CSS
from pathlib import Path
import os

FONT_DIR = Path(os.environ.get("CLAUDE_PLUGIN_ROOT", str(Path(__file__).parent.parent))) / "assets" / "fonts"

# 번들 Noto Sans CJK를 @font-face로 등록 (weight별)
# 경로 → URL 변환은 반드시 Path.as_uri()로 한다. 문자열 "file://" + 경로 조립은
# Windows에서 file://C:\... 형태의 잘못된 URL이 되어 폰트 로드에 실패한다.
FONT_FACE = "".join(
    f"@font-face{{font-family:'Noto Sans CJK';font-weight:{w};"
    f"src:url('{(FONT_DIR / f'NotoSansCJK-{n}.otf').as_uri()}');}}"
    for w, n in {300: "Light", 400: "Regular", 500: "Medium", 700: "Bold"}.items()
    if (FONT_DIR / f"NotoSansCJK-{n}.otf").exists()
)

# (A) 완성 스타일 HTML → 자체 CSS 보존, CJK 폰트만 보강
HTML(string=styled_html, base_url=".").write_pdf("out.pdf", stylesheets=[CSS(string=FONT_FACE)])

# (B) Markdown/JSON/Text에서 만든 HTML → 기본 문서 CSS + 폰트
HTML(string=plain_html, base_url=".").write_pdf("out.pdf", stylesheets=[CSS(string=FONT_FACE + BASE_CSS)])

BASE_CSS는 @page { size:A4; margin:20mm } + with body/heading/table styles, font-family에 'Noto Sans CJK'specifies that CJK is always rendered with an embedded font.

This skill replaced references to absent scripts (render_pdf.py, download_fonts.py) with Principle A (prompt/inline code path) — run the weasyprint code above directly, and use the system fallback as the primary path for fonts.

Dependencies

pip install weasyprint   # 핵심 렌더링 엔진 (풀 CSS → PDF)
pip install markdown     # Markdown → HTML 변환 (선택, 없으면 최소 폴백)

weasyprint uses the system library cairo / pango / gdk-pixbufMost Cowork sandboxes and Linux/macOS environments include it by default, so it works with pip install weasyprintalone.

When running locally on Windows, these libraries are not provided by default. pip install weasyprinteven if succeeds, import weasyprint at the step cannot load library 'libpango...'it fails with. You must install the GTK runtime first — see the Windows row in §Troubleshooting below. In environments where installation is difficult, instead of PDF moai-officer:doc-html-report guide users to a path of printing the artifact to "PDF" in the browser.

Input Format Specification

Completed HTML (design preserved)

<html>·<body>·<!doctype html> if there is a signal, treat it as a completed documentand render its own <style>and CSS as-is. moai-officer:doc-html-report·moai-officer:doc-html-slide If you pass the artifact as-is, you get a PDF with the same design as the screen.

Structured JSON Spec

{
  "title": "문서 제목",
  "subtitle": "부제목 (선택)",
  "author": "작성자 (선택)",
  "date": "2026-01-01 (선택)",
  "sections": [
    {
      "heading": "섹션 제목",
      "level": 2,
      "body": "본문 텍스트 (마크다운 인라인 지원)",
      "table": { "headers": ["열1", "열2"], "rows": [["a", "b"]] },
      "image": { "path": "./chart.png", "caption": "그림 1" }
    }
  ]
}

Markdown Input Example

# 프로젝트 보고서

## 1. 개요
본 보고서는 ...

## 2. 결과
| 항목 | 수치 |
|------|------|
| 완료율 | 95% |

Usage Examples

  • "Make this HTML report into a PDF with the design as-is" → Completed HTML path (CSS preserved)
  • "Weekly report Markdown into a PDF without broken Korean" → Markdown path (default formatting + CJK)
  • "Generate a branch report PDF with the JSON structure below" → JSON path
  • "Output a Korean·Japanese·Chinese·English mixed manual as PDF" → multilingual embedding

Output Format

  • File format: .pdf (ISO 32000 PDF standard)
  • Page size: A4 (210 × 297mm, default margin 20mm) — completed HTML prioritizes its own @page settings
  • Font: Noto Sans CJK (single family covering Korean·Japanese·Simplified Chinese·Traditional Chinese·Latin, subset embedding)
  • Encoding: Full UTF-8 support

Self-inspection

After generating the PDF, reopen the output .pdfand check for remaining placeholders, page count shortfall, broken CJK encoding, missing designby self-inspection, and if there are problems, automatically fix and regenerate, and report the final PASS/FAIL.

Troubleshooting

Symptom Cause Solution
Korean/Hanja appear as □□□ or blank CJK font unresolved System Noto Sans CJK KR installation (Windows: download from Google Fonts and right-click to install, macOS brew install --cask font-noto-sans-cjk-kr, Debian/Ubuntu apt install fonts-noto-cjk), or place Noto Sans CJK OTF in assets/fonts/and re-render
ModuleNotFoundError: weasyprint weasyprint not installed pip install weasyprint run
cannot load library 'libpango...' (Windows) GTK runtime absent — on Windows, resolved by pip installalone does not work ① After installing MSYS2, UCRT64 셸in pacman -S mingw-w64-ucrt-x86_64-pango (per WeasyPrint's official guidance — not the MINGW64 shell's mingw-w64-x86_64-pango, not that), then $env:WEASYPRINT_DLL_DIRECTORIES="C:\msys64\ucrt64\bin"and set new terminal, then retry. If you don't specify the DLL path, Pango won't be found even after installation. ② Or GTK for Windows Runtime installer. ③ If both are difficult, moai-officer:doc-html-reportto create the HTML, then fall back to the browser's "Print to PDF" (Ctrl+P → Destination: Save as PDF)
cannot load library 'libpango...' (macOS/Linux) Missing system libraries (Debian/Ubuntu) apt install libpango-1.0-0 libpangocairo-1.0-0, (macOS) brew install pango
HTML design breaks in PDF Completed HTML mistaken for a fragment Include <html>/<body> wrapper in the input, or pass it as an --in *.html file
Web fonts (CDN) not applied Offline/CDN blocked Inline the fonts in the HTML or substitute system fonts (offline PDFs should avoid CDN dependencies)
Tables split at page boundaries CSS not specified tr { page-break-inside: avoid; } add

Related skills / handoff

Skill Relationship When to use
moai-officer:doc-html-report before (generate HTML report → convert to PDF with this skill) "Make a report and also a PDF" flow
moai-officer:doc-html-slide before (generate HTML slides → convert to PDF) Distribute the slide deck as a PDF
moai-officer:doc-docx alternative (editable Word output) When the recipient needs an editable file
moai-coworker:ai-slop-reviewer after (review AI patterns in text output) Review the manuscript before generating the text PDF

Technical reference