diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f5fe668..eecd78a 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -416,7 +416,7 @@ "description": "Create PDF documents from markdown with Chinese font support. Supports theme system (default for formal docs, warm-terra for training materials) and dual backend (weasyprint or Chrome). Triggers include convert to PDF, generate PDF, markdown to PDF, or printable documents", "source": "./", "strict": false, - "version": "1.2.0", + "version": "1.3.0", "category": "document-conversion", "keywords": [ "pdf", @@ -425,6 +425,7 @@ "chrome", "themes", "chinese-fonts", + "cjk", "document-generation", "legal", "reports", diff --git a/pdf-creator/SKILL.md b/pdf-creator/SKILL.md index ac3c809..25e9715 100644 --- a/pdf-creator/SKILL.md +++ b/pdf-creator/SKILL.md @@ -57,4 +57,6 @@ uv run --with weasyprint scripts/batch_convert.py *.md --output-dir ./pdfs **weasyprint import error**: Run with `uv run --with weasyprint` or use `--backend chrome` instead. +**CJK text in code blocks garbled (weasyprint)**: The script auto-detects code blocks containing Chinese/Japanese/Korean characters and converts them to styled divs with CJK-capable fonts. If you still see issues, use `--backend chrome` which has native CJK support. Alternatively, convert code blocks to markdown tables before generating the PDF. + **Chrome header/footer appearing**: The script passes `--no-pdf-header-footer`. If it still appears, your Chrome version may not support this flag — update Chrome. diff --git a/pdf-creator/scripts/md_to_pdf.py b/pdf-creator/scripts/md_to_pdf.py index 4fd9ed6..696e2c2 100644 --- a/pdf-creator/scripts/md_to_pdf.py +++ b/pdf-creator/scripts/md_to_pdf.py @@ -125,6 +125,35 @@ def _ensure_list_spacing(text: str) -> str: return "\n".join(result) +_CJK_RANGE = re.compile( + r"[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff" + r"\U00020000-\U0002a6df\U0002a700-\U0002ebef" + r"\u3000-\u303f\uff00-\uffef]" +) + + +def _fix_cjk_code_blocks(html: str) -> str: + """Replace
 blocks containing CJK with styled divs.
+
+    weasyprint renders 
 blocks using monospace fonts that lack CJK glyphs,
+    causing garbled output. This converts CJK-heavy code blocks to styled divs
+    that use the document's CJK font stack instead.
+    """
+
+    def _replace_if_cjk(match: re.Match) -> str:
+        content = match.group(1)
+        if _CJK_RANGE.search(content):
+            return f'
{content}
' + return match.group(0) + + return re.sub( + r"
]*)?>(.+?)
", + _replace_if_cjk, + html, + flags=re.DOTALL, + ) + + def _md_to_html(md_file: str) -> str: """Convert markdown to HTML using pandoc with list spacing preprocessing.""" if not shutil.which("pandoc"): @@ -147,7 +176,9 @@ def _md_to_html(md_file: str) -> str: print(f"Error: pandoc failed: {result.stderr}", file=sys.stderr) sys.exit(1) - return result.stdout + html = result.stdout + html = _fix_cjk_code_blocks(html) + return html def _build_full_html(html_content: str, css: str, title: str) -> str: diff --git a/pdf-creator/themes/default.css b/pdf-creator/themes/default.css index 255cd1a..07a0cb2 100644 --- a/pdf-creator/themes/default.css +++ b/pdf-creator/themes/default.css @@ -86,3 +86,46 @@ hr { border-top: 1px solid #ccc; margin: 1.5em 0; } + +code { + font-family: 'Menlo', 'PingFang SC', 'Heiti SC', 'Noto Sans CJK SC', monospace; + background: #f5f5f5; + padding: 1px 4px; + border-radius: 3px; + font-size: 10pt; +} + +pre { + background: #f5f5f5; + border: 1px solid #ddd; + border-radius: 4px; + padding: 12px 16px; + margin: 1em 0; + overflow-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +pre code { + font-family: 'Menlo', 'PingFang SC', 'Heiti SC', 'Noto Sans CJK SC', monospace; + background: none; + padding: 0; + border-radius: 0; + font-size: 9pt; + line-height: 1.6; +} + +/* CJK code blocks converted to styled divs by preprocessor. + Uses inherit to reuse body's CJK font (weasyprint may not find PingFang SC). */ +.cjk-code-block { + font-family: inherit; + background: #f5f5f5; + border: 1px solid #ddd; + border-radius: 4px; + padding: 12px 16px; + margin: 1em 0; + font-size: 10pt; + line-height: 1.8; + white-space: pre-wrap; + word-break: break-all; +} diff --git a/pdf-creator/themes/warm-terra.css b/pdf-creator/themes/warm-terra.css index 3af0f80..eb7e957 100644 --- a/pdf-creator/themes/warm-terra.css +++ b/pdf-creator/themes/warm-terra.css @@ -110,12 +110,48 @@ header, .date { } code { + font-family: 'Menlo', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', monospace; background: #faf5f0; padding: 1px 4px; border-radius: 3px; font-size: 12px; } +pre { + background: #faf5f0; + border: 1px solid #e2d6c8; + border-radius: 4px; + padding: 12px 16px; + margin: 10px 0; + overflow-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +pre code { + font-family: 'Menlo', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', monospace; + background: none; + padding: 0; + border-radius: 0; + font-size: 11px; + line-height: 1.6; +} + +/* CJK code blocks converted to styled divs by preprocessor. + Uses inherit to reuse body's CJK font (weasyprint may not resolve all font names). */ +.cjk-code-block { + font-family: inherit; + background: #faf5f0; + border: 1px solid #e2d6c8; + border-radius: 4px; + padding: 12px 16px; + margin: 10px 0; + font-size: 12px; + line-height: 1.7; + white-space: pre-wrap; + word-break: break-all; +} + strong { color: #1f1b17; }