Document Export
Convert documents (Markdown, HWP, DOCX, RTF) to PDF, PNG, HTML slides.
Usage mandate (HARD STOP)
All Markdown | HWP | DOCX → PDF / PNG / HTML / DOCX conversion must go through this skill. Do not assemble pandoc / prince / md-to-pdf / soffice commands ad-hoc — direct assembly repeats mistakes (duplicated titles, watermark leakage on official documents, missing images on HWP txt fallback, etc.).
| # | Don't | Do |
|---|---|---|
| 1 | Directly assemble pandoc ... && prince ... in Bash |
Invoke /doc-export <file> → follow the Instructions procedure below |
| 2 | Reconstruct conversion options from memory each time | Follow "Conversion cautions (recurrence prevention)" + Instructions every time |
| 3 | For an HWP / DOCX / PDF document analysis request, silently fall back to txt extraction |
Rich-format analysis defaults to PDF or HTML with images/tables preserved. txt is opt-in only (user must explicitly say "txt only") |
| 4 | Use prince / md-to-pdf for official / external-submission documents | Watermark risk (prince inserts "non-commercial" mark). Route official documents through LibreOffice (§Medium policy below) |
Topics
| Topic | Description | Guide |
|---|---|---|
| docx | Word conversion + md → docx → pdf chain (pandoc + LibreOffice) | docx.md |
| legacy | HWP / DOC / RTF → PDF / HTML via LibreOffice (below in this file) | — |
| marp | Marp slide conversion (Mermaid, checklists, overflow) | marp.md |
| pandoc | Markdown → PDF / PNG (pandoc + LibreOffice or prince) | below in this file |
Quick Start
/doc-export path/to/document.md
Instructions
1. Classify the target medium (MANDATORY — before tool selection)
Before picking a converter, classify the deliverable into one of the two mediums below. The medium decides which tool is legal, not which tool is available.
| Medium | Definition | Watermark-clean required? | Default converter |
|---|---|---|---|
| Official / external | Submitted to a customer, consortium, government, external partner, or any recipient outside your workspace. Also: reports embedded into contract deliverables, quotes, RFP responses | Yes (HARD STOP) | LibreOffice (§tool table row 1) |
| Internal / draft | Working draft only, staying inside the workspace. Review copies, session artifacts, .tmp/ scratch, throwaway previews |
Not required | Any row of the tool table; pick by availability |
If the user has not stated the medium explicitly, default to "Official / external" — false positives (watermark-clean tool used on a scratch draft) waste nothing; false negatives (watermarked prince output emailed to a customer) are unrecoverable.
2. Tool priority (fallback order)
Use the first available tool that satisfies the medium classification from §1. Skip any tool marked "internal only" if the medium is Official / external.
| Rank | Tool | Check command | Watermark? | License | Allowed medium |
|---|---|---|---|---|---|
| 1 | LibreOffice (soffice) | command -v soffice || command -v libreoffice |
None | MPL 2.0 (fully free) | Official + Internal |
| 2 | pandoc + wkhtmltopdf | command -v pandoc && command -v wkhtmltopdf |
None | LGPL / GPL | Official + Internal |
| 3 | pandoc + xelatex | command -v pandoc && command -v xelatex |
None | LPPL / free | Official + Internal |
| 4 | pandoc + prince | command -v pandoc && command -v prince |
Yes ("This document was created with the unregistered version of Prince") | Non-commercial free / commercial paid | Internal only |
| 5 | md-to-pdf (npx puppeteer) | npx --yes md-to-pdf --version |
None (uses headless Chromium) | MIT | Official + Internal (but Chromium install downloads ~150MB) |
Rank rationale:
- LibreOffice is #1 because it is watermark-clean, MPL-licensed, and handles the widest input format list (Markdown via pandoc pre-step, DOCX, HWP, RTF, ODT). It is the only converter that can render HWP without loss.
- prince is dropped to internal-only because the free build stamps every page. Paid Prince removes the stamp but is per-machine licensed — do not silently rely on user's paid seat.
- md-to-pdf is a valid watermark-clean alternative on Windows / npm-heavy machines but pulls Chromium on first run, so LibreOffice remains #1 on macOS / Linux.
3. LibreOffice install-check + install-ask procedure (MANDATORY)
Before every LibreOffice-backed conversion:
if command -v soffice >/dev/null 2>&1 || command -v libreoffice >/dev/null 2>&1; then
echo "LibreOffice available"
else
echo "LibreOffice NOT installed"
fi
If not installed, do NOT silently fall through to prince / md-to-pdf when the medium is Official / external. Instead:
- Run
AskUserQuestionwith these options (single-select):Install LibreOffice (~400MB, Recommended for official documents)— description mentionsbrew install --cask libreoffice(macOS) orscoop install libreoffice(Windows) orapt install libreoffice(Linux). Runtime ~2–10 min depending on networkFall back to next watermark-clean rank (wkhtmltopdf / xelatex / md-to-pdf)— if any is available. State which one and its trade-offDowngrade medium to Internal-only and use prince— only offer when the user is willing to accept the watermark
- Wait for the answer. Do NOT proceed with prince output on an Official-medium document without explicit user approval.
- If the user selects install: run the appropriate install command in the appropriate way for the platform, then verify with the check command above before continuing.
Don't / Do
| # | Don't | Do |
|---|---|---|
| 1 | Detect "soffice not found" and silently switch to prince for an Official document | Run the install-ask above. Prince output on Official medium requires explicit user override |
| 2 | Assume LibreOffice from a prior session is still installed | Run command -v soffice at the start of every conversion. State the check result in the response |
| 3 | Install LibreOffice without asking (400MB download is user-visible impact) | AskUserQuestion first. Install only after approval |
| 4 | Report "conversion done" when the medium is Official but the output was produced by prince (with watermark) | Watermark verification: `pdftotext output.pdf - |
4. Execution
Method A — LibreOffice (default, watermark-clean)
md → pdf chain (LibreOffice can't read .md directly, so pandoc pre-converts to docx):
pandoc document.md -o document.docx --toc -V lang=ko-KR
soffice --headless --convert-to pdf --outdir "$OUTDIR" document.docx
# → document.pdf (watermark-free, faithful to Word-style layout)
Direct format conversions (LibreOffice reads these natively):
soffice --headless --convert-to pdf --outdir "$OUTDIR" input.docx
soffice --headless --convert-to pdf --outdir "$OUTDIR" input.hwp
soffice --headless --convert-to pdf --outdir "$OUTDIR" input.rtf
soffice --headless --convert-to html --outdir "$OUTDIR" input.hwp # HTML with images extracted
Method B — pandoc + prince (Internal only; do NOT use for Official)
# Only when medium classification = Internal AND the user has not asked for a watermark-clean output
pandoc document.md -f gfm -t html5 -s -c style.css -o document.html
prince document.html -o document.pdf
PNG rendering (PDF → PNG page images)
pdftoppm -png -r 150 document.pdf document
5. HWP / legacy document conversion (integrated procedure)
HWP (Hangul Word Processor) is a Korean office format frequently used in official Korean government / enterprise submissions.
Toolchain by input format
| Input | Recommended converter | Fallback | Notes |
|---|---|---|---|
.hwp (HWP 5.x binary) |
LibreOffice --convert-to pdf or --convert-to html |
uvx --from pyhwp --with six hwp5txt (text-only, images lost) |
LibreOffice preserves tables and images. pyhwp txt is a last-resort text-only fallback, never the default. Exception: some HWP 5.1.0.x sub-versions are not parsed by LibreOffice's HWP import filter at all (distinct from the filename-encoding issue below) — for these, pyhwp is the only working path, not a last resort |
.hwpx (HWP 2010+ XML) |
LibreOffice --convert-to pdf |
(rare) unzip + XML parse | HWPX is a zip container — LibreOffice reads it natively |
.doc (Word 97-2003) |
LibreOffice --convert-to docx then re-open |
— | Legacy DOC must be upgraded before editing |
.rtf, .odt |
LibreOffice --convert-to pdf |
— | Native support |
Analysis-request default (HARD STOP)
When the user asks to analyze a rich-format document (HWP / DOCX / PDF / legacy) without specifying the output medium:
| # | Don't | Do |
|---|---|---|
| 1 | Silently choose --convert-to txt and drop tables / images |
Default to --convert-to pdf (or --convert-to html), preserving layout / tables / images |
| 2 | Fall back to hwp5txt because soffice failed once |
If LibreOffice load fails, retry with a sanitized filename copy in /tmp first. Only after LibreOffice truly cannot open the file → offer pyhwp hwp5txt as an explicit fallback with a note that images will be lost |
| 3 | Present a txt / html / pdf option set without stating the default |
State explicitly: "Default = PDF (images preserved). Pick another only if you need txt-only" |
| 4 | Interpret an ambiguous option label ("LibreOffice install") as "install only, then extract txt" | Read the option description. If it says "preserves images / faithful to original", the user intent is a visual-preserving format (PDF or HTML), not txt |
| 5 | Retry the sanitized-filename workaround repeatedly when soffice already fails on a clean path (no Korean characters / spaces in the filename) |
A clean-path failure is a filter incompatibility signal, not an encoding issue — some HWP 5.1.0.x sub-versions are unsupported by LibreOffice's HWP import filter regardless of filename. Move directly to pyhwp hwp5txt instead of repeating the sanitize step |
Sanitized filename workaround
LibreOffice sometimes fails on paths with Korean characters + spaces. If soffice --convert-to pdf "<original>" returns "source file could not be loaded":
cp "$ORIGINAL" /tmp/input.hwp
soffice --headless --convert-to pdf --outdir /tmp /tmp/input.hwp
# then rename output back to the original stem if needed
Conversion cautions (recurrence prevention)
Title — no duplication
- If the document already contains
# H1, do NOT append--metadata title="..."to pandoc.-semits a separate title block that duplicates the H1 → two-line duplicated title. Use H1 as the sole title. - If a separate title block is required, remove the
# H1from the source and keep only--metadata title(one or the other, never both).
Change-highlight documents (<mark> for review)
| # | Don't | Do |
|---|---|---|
| 1 | Apply <mark> inside sections that already summarize changes (change log / summary of changes) |
That section is redundant to highlight. <mark> is for body content (tables / paragraphs) distinguishing changed vs unchanged |
| 2 | Inject "review-copy / highlight legend" banners on your own | Do not inject banners without user request. If asked to "remove it", remove immediately then regenerate |
| 3 | Add <mark> without CSS |
mark { background: #fff3a3 } + Korean font + table border CSS via -c style.css — without CSS the highlight does not render |
Do not delete review artifacts
Review PDFs / MDs awaiting user approval are kept until the user explicitly confirms review is complete (see file-operations.md .tmp section). No auto-cleanup.
Tool inventory
| Tool | Purpose | macOS install | Windows install |
|---|---|---|---|
| LibreOffice (soffice) | Any → PDF / HTML / DOCX (watermark-clean, top priority) | brew install --cask libreoffice |
scoop install libreoffice or the official site |
| pandoc | Markdown → HTML / DOCX | brew install pandoc |
scoop install pandoc |
| wkhtmltopdf | HTML → PDF (watermark-clean fallback) | brew install wkhtmltopdf |
scoop install wkhtmltopdf |
| xelatex (via TeX Live) | Markdown → PDF (heavy install) | brew install --cask mactex-no-gui |
scoop install latex |
| prince | HTML → PDF (watermark on free build — internal only) | brew install prince |
official site |
| md-to-pdf | Markdown → PDF (watermark-clean, pulls Chromium) | npm i -g md-to-pdf |
npm i -g md-to-pdf or npx |
| poppler (pdftoppm) | PDF → PNG | brew install poppler |
scoop install poppler |
| pyhwp (fallback only) | HWP → text (images lost) | uvx --from pyhwp --with six hwp5txt |
same via uvx |
Output files
document.pdf— PDFdocument.html— HTML (with image assets when converted from HWP / DOCX)document-1.png,document-2.png, ... — per-page PNG
Options
PNG resolution
pdftoppm -png -r 300 document.pdf document # 300 DPI (high resolution)
pdftoppm -png -r 72 document.pdf document # 72 DPI (low resolution)
Merge PNGs into one
# Requires ImageMagick
convert document-*.png -append document-all.png
