← Back to Skills Marketplace
shimonxin

Markdown to PDF (CJK)

by Shimon Xin · GitHub ↗ · v1.0.1 · MIT-0
cross-platform ✓ Security Clean
63
Downloads
0
Stars
0
Active Installs
2
Versions
Install in OpenClaw
/install md2pdf-cjk
Description
Markdown to PDF converter with CJK (Chinese/Japanese/Korean) support. Uses WeasyPrint + Noto CJK fonts for proper rendering. Features: emoji replacement, cus...
README (SKILL.md)

Markdown to PDF (CJK)

Convert Markdown files to well-formatted PDF with full CJK (Chinese/Japanese/Korean) support, code blocks, and tables.

Toolchain

  • Rendering engine: WeasyPrint (pre-installed, /usr/local/bin/weasyprint)
  • Fonts: Noto Sans CJK SC / Noto Serif CJK SC (system-installed)
  • Pipeline: Markdown → HTML (emoji replacement) → WeasyPrint → PDF

Steps

1. Emoji Processing

WeasyPrint does not render emoji characters. Replace them with text labels:

emoji_map = {
    '🦞': '[Lobster]', '🌅': '[Morning]', '🌙': '[Moon]', '🏛': '[Architecture]',
    '🔧': '[Tool]', '🔄': '[Restart]', '📰': '[Report]', '💪': '[Strong]',
    '⚡': '[Lightning]', '⏰': '[Alarm]', '👆': '[Up]', '⬆️': '[Up]',
    '🌟': '[Star]', '👇': '[Down]', '✅': '[Done]', '📊': '[Chart]',
    '🎯': '[Target]', '💡': '[Idea]', '🧰': '[Toolbox]', '🤖': '[AI]',
    '🏗️': '[Build]', '📅': '[Calendar]', '🧘': '[Meditation]', '📖': '[Read]',
    '📝': '[Note]', '🏃': '[Run]', '⭐': '[Fav]', '📬': '[Mail]',
    '🌐': '[Web]', '🐙': '[GitHub]', '💬': '[Chat]', '▪': '·',
    '❌': '[X]', '⚠️': '[!]', '📌': '[PIN]', '🔔': '[Bell]',
    '🤔': '[Think]', '😂': '[Laugh]', '🔒': '[Lock]', '📁': '[Folder]',
    '💰': '[Money]', '👨‍👧‍👦': '[Family]', '😴': '[Sleep]', '👶': '[Baby]',
    '1️⃣': '1.', '2️⃣': '2.', '3️⃣': '3.', '4️⃣': '4.', '5️⃣': '5.',
}

For emoji not in the map, strip variant selectors (\ufe0f) and replace with [?]. Preserve CJK punctuation marks (·…——''""etc.).

2. Markdown → HTML Conversion

Lightweight conversion using Python regex (no extra dependencies):

import re
html = md_content
html = re.sub(r'^# (.+)$', r'\x3Ch1>\1\x3C/h1>', html, flags=re.MULTILINE)
html = re.sub(r'^## (.+)$', r'\x3Ch2>\1\x3C/h2>', html, flags=re.MULTILINE)
html = re.sub(r'^### (.+)$', r'\x3Ch3>\1\x3C/h3>', html, flags=re.MULTILINE)
html = re.sub(r'\*\*(.+?)\*\*', r'\x3Cstrong>\1\x3C/strong>', html)
html = re.sub(r'\*(.+?)\*', r'\x3Cem>\1\x3C/em>', html)
html = re.sub(r'^> (.+)$', r'\x3Cblockquote>\1\x3C/blockquote>', html, flags=re.MULTILINE)
html = re.sub(r'^---$', r'\x3Chr/>', html, flags=re.MULTILINE)
html = re.sub(r'^- (.+)$', r'\x3Cli>\1\x3C/li>', html, flags=re.MULTILINE)
html = re.sub(r'`([^`]+)`', r'\x3Ccode>\1\x3C/code>', html)
html = re.sub(r'```(\w*)\
(.*?)```', r'\x3Cpre>\x3Ccode>\2\x3C/code>\x3C/pre>', html, flags=re.DOTALL)
# Paragraphs
html = re.sub(r'\
\
', r'\x3C/p>\x3Cp>', html)
html = '\x3Cp>' + html + '\x3C/p>'
# Clean empty tags
html = re.sub(r'\x3Cp>\s*\x3C/p>', '', html)
html = re.sub(r'\x3Cp>\s*(\x3Ch[123]>.*?\x3C/h[123]>)\s*\x3C/p>', r'\1', html, flags=re.DOTALL)
html = re.sub(r'\x3Cp>\s*(\x3Chr/>)\s*\x3C/p>', r'\1', html)
html = re.sub(r'\x3Cp>\s*(\x3Cblockquote>.*?\x3C/blockquote>)\s*\x3C/p>', r'\1', html, flags=re.DOTALL)

3. HTML Template

\x3C!DOCTYPE html>
\x3Chtml>
\x3Chead>
\x3Cmeta charset="utf-8">
\x3Cstyle>
@page { size: A4; margin: 2cm 2.5cm 2cm 2.5cm; }
body {
    font-family: "Noto Sans CJK SC", "Noto Serif CJK SC", sans-serif;
    font-size: 11pt; line-height: 1.8; color: #333;
    max-width: 100%; word-wrap: break-word;
}
h1 { font-size: 20pt; color: #d32f2f; border-bottom: 2px solid #d32f2f; padding-bottom: 8px; margin-top: 30px; }
h2 { font-size: 15pt; color: #333; margin-top: 25px; border-left: 4px solid #d32f2f; padding-left: 10px; }
h3 { font-size: 13pt; color: #555; margin-top: 20px; }
blockquote { border-left: 3px solid #ccc; padding-left: 15px; color: #666; margin: 15px 0; font-style: italic; }
code { background: #f5f5f5; padding: 2px 6px; border-radius: 3px; font-size: 10pt; }
pre { background: #f8f8f8; padding: 12px; border-radius: 5px; font-size: 9.5pt; line-height: 1.6; }
pre code { background: none; padding: 0; }
strong { color: #d32f2f; }
hr { border: none; border-top: 1px solid #ddd; margin: 25px 0; }
li { margin: 5px 0; }
table { border-collapse: collapse; width: 100%; margin: 15px 0; }
th, td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; }
th { background: #f5f5f5; font-weight: bold; }
\x3C/style>
\x3C/head>
\x3Cbody>{{HTML_CONTENT}}\x3C/body>
\x3C/html>

4. Generate PDF

weasyprint /tmp/input.html /tmp/output.pdf

One-line Script

All steps are wrapped into a single script:

#!/bin/bash
# Usage: md2pdf.sh input.md [output.pdf]
# Markdown → PDF (weasyprint + CJK + emoji replacement)
INPUT="${1:-/dev/stdin}"
OUTPUT="${2:-/tmp/output.pdf}"
python3 /path/to/md2pdf.py "$INPUT" "$OUTPUT"

Important Notes

  • Do NOT use pandoc + xelatex: Emoji renders as blank, and compilation is slow
  • Do NOT use pandoc + wkhtmltopdf: Not installed by default
  • Always use WeasyPrint: The only solution that supports CJK + emoji replacement
  • Output path: Always use absolute paths under /tmp/
  • Pre-send check: Verify PDF file exists and is > 10KB before sending
Usage Guidance
Install this if you want Markdown-to-PDF conversion with CJK rendering. Consider narrowing its trigger phrases to Markdown-specific requests, and avoid processing sensitive untrusted Markdown if you are not comfortable with local HTML/PDF rendering of that content.
Capability Assessment
Purpose & Capability
The artifact’s stated purpose and instructions consistently describe converting Markdown to PDF with CJK font support using local WeasyPrint processing.
Instruction Scope
The description includes broad triggers such as "generate PDF" and "convert PDF", which could route non-Markdown PDF requests to this skill, but the behavior remains related to document conversion.
Install Mechanism
The package contains only a SKILL.md instruction file and no bundled executable, installer, dependency install step, or automatic setup mechanism.
Credentials
The instructions use local Markdown input, temporary HTML/PDF files under /tmp, Python text processing, and WeasyPrint; they do not request credentials, network APIs, or broad filesystem access.
Persistence & Privilege
No persistence, background workers, privilege escalation, startup hooks, or long-running services are described.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install md2pdf-cjk
  3. After installation, invoke the skill by name or use /md2pdf-cjk
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.1
Full English translation of SKILL.md and all content
v1.0.0
首个公开版本:WeasyPrint+Noto CJK,支持中文排版、emoji替换、自定义CSS样式
Metadata
Slug md2pdf-cjk
Version 1.0.1
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 2
Frequently Asked Questions

What is Markdown to PDF (CJK)?

Markdown to PDF converter with CJK (Chinese/Japanese/Korean) support. Uses WeasyPrint + Noto CJK fonts for proper rendering. Features: emoji replacement, cus... It is an AI Agent Skill for Claude Code / OpenClaw, with 63 downloads so far.

How do I install Markdown to PDF (CJK)?

Run "/install md2pdf-cjk" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Markdown to PDF (CJK) free?

Yes, Markdown to PDF (CJK) is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Markdown to PDF (CJK) support?

Markdown to PDF (CJK) is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Markdown to PDF (CJK)?

It is built and maintained by Shimon Xin (@shimonxin); the current version is v1.0.1.

💬 Comments