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;
}