Pdf Report Generator
/install zcx-pdf-report-generator
PDF Report Generator — Markdown转PDF
Convert structured Markdown reports into print-ready A4 PDF documents with Chinese font support, automatic headers/footers, and page numbers. Designed to work hand-in-hand with the daily-market-report skill.
When to Use
| Scenario | Trigger |
|---|---|
| End-of-day market report → PDF | After daily-market-report generates a Markdown summary |
| Trade journal / weekly review export | Convert structured notes to PDF |
| Investment memo generation | Produce clean A4 printouts for offline review |
| Any Markdown → formatted PDF | General-purpose conversion |
Prerequisites
The pdfkit library is already installed at:
C:\Users\Tania\.openclaw\workspace\.tmp-report\
ode_modules\pdfkit
No additional installs needed. The skill uses this existing dependency.
Chinese Font
For Chinese text rendering, pdfkit requires a TrueType font file. Recommended:
- Noto Sans SC (free, open-source): Download from Google Fonts
- Source Han Sans (思源黑体): Another good open-source option
- Microsoft YaHei (微软雅黑): Available on Windows at
C:\Windows\Fonts\msyh.ttc
Place the font file in the skill's assets/ directory or reference it from a known path. Example:
# Option 1: Place in assets/
cp /path/to/NotoSansSC-Regular.ttf skills/pdf-report-generator/assets/
# Option 2: Use Windows system font (no copy needed)
# Just reference C:\Windows\Fonts\msyh.ttc in the script
Workflow: Markdown → PDF
Step 1: Parse Markdown content
The input is a Markdown string. Key structural elements to handle:
| Markdown Element | PDF Rendering |
|---|---|
# H1 |
Large bold header |
## H2 |
Medium bold header |
### H3 |
Small bold header |
| Plain text | Body paragraph |
| ` | table |
**bold** |
Bold text |
- list |
Bullet point |
> quote |
Indented italic |
--- |
Horizontal rule |
`code` |
Monospace |
🟢 / 🔴 |
Color markers |
Step 2: Generate PDF via Node.js script
Create and run a Node.js script that uses pdfkit. Script location: skills/pdf-report-generator/scripts/generate_pdf.js
Core Script Template
const PDFDocument = require('pdfkit');
const fs = require('fs');
// === CONFIG ===
const FONT_PATH = 'C:/Windows/Fonts/msyh.ttc'; // Chinese font
const FONT_BOLD_PATH = 'C:/Windows/Fonts/msyhbd.ttc'; // Bold variant (optional)
const PAGE_WIDTH = 595.28; // A4 width (points)
const PAGE_HEIGHT = 841.89; // A4 height (points)
const MARGIN = 72; // 1 inch margins
const HEADER_Y = 40;
const FOOTER_Y = PAGE_HEIGHT - 30;
const CONTENT_TOP = 72;
const CONTENT_BOTTOM = PAGE_HEIGHT - 72;
// === HELPERS ===
function addHeader(doc, text) {
doc.fontSize(8).font(FONT_PATH)
.text(text, MARGIN, HEADER_Y, { align: 'left' });
doc.moveTo(MARGIN, HEADER_Y + 14)
.lineTo(PAGE_WIDTH - MARGIN, HEADER_Y + 14)
.stroke('#cccccc');
}
function addFooter(doc, pageNum) {
doc.fontSize(8).font(FONT_PATH)
.text(`第 ${pageNum} 页`, MARGIN, FOOTER_Y, { align: 'center' });
}
function renderTable(doc, headers, rows, startY) {
// Column widths: equal distribution
const colCount = headers.length;
const colWidth = (PAGE_WIDTH - 2 * MARGIN) / colCount;
let y = startY;
// Header row
doc.fontSize(9).font(FONT_BOLD_PATH || FONT_PATH);
headers.forEach((h, i) => {
doc.text(h, MARGIN + i * colWidth + 2, y + 2, {
width: colWidth - 4, align: 'center'
});
});
y += 20;
// Draw header line
doc.moveTo(MARGIN, y).lineTo(PAGE_WIDTH - MARGIN, y).stroke();
// Data rows
doc.fontSize(9).font(FONT_PATH);
for (const row of rows) {
row.forEach((cell, i) => {
doc.text(String(cell), MARGIN + i * colWidth + 2, y + 2, {
width: colWidth - 4, align: 'center'
});
});
y += 18;
doc.moveTo(MARGIN, y).lineTo(PAGE_WIDTH - MARGIN, y)
.stroke('#eeeeee');
}
return y; // Return next Y position
}
// === MAIN ===
function generatePDF(markdownContent, outputPath, title) {
const doc = new PDFDocument({
size: 'A4',
margins: { top: MARGIN, bottom: MARGIN, left: MARGIN, right: MARGIN },
info: {
Title: title || 'Market Report',
Author: 'OpenClaw 虾哥',
Producer: 'OpenClaw pdf-report-generator',
}
});
const stream = fs.createWriteStream(outputPath);
doc.pipe(stream);
let pageNum = 1;
addHeader(doc, title || '市场报告');
addFooter(doc, pageNum);
// --- Parse and render markdown ---
const lines = markdownContent.split('\
');
let y = CONTENT_TOP;
for (const line of lines) {
// Check if we need a new page
if (y > CONTENT_BOTTOM - 30) {
doc.addPage();
pageNum++;
addHeader(doc, title || '市场报告');
addFooter(doc, pageNum);
y = CONTENT_TOP;
}
// H1
if (line.startsWith('# ')) {
doc.fontSize(18).font(FONT_BOLD_PATH || FONT_PATH)
.fillColor('#1a1a2e');
y = doc.text(line.slice(2), MARGIN, y + 16, {
continued: false
}).y + 6;
}
// H2
else if (line.startsWith('## ')) {
doc.fontSize(14).font(FONT_BOLD_PATH || FONT_PATH)
.fillColor('#16213e');
y = doc.text(line.slice(3), MARGIN, y + 12, {
continued: false
}).y + 4;
}
// H3
else if (line.startsWith('### ')) {
doc.fontSize(12).font(FONT_BOLD_PATH || FONT_PATH)
.fillColor('#0f3460');
y = doc.text(line.slice(4), MARGIN, y + 10, {
continued: false
}).y + 2;
}
// Horizontal rule
else if (line.startsWith('---')) {
doc.moveTo(MARGIN, y + 4)
.lineTo(PAGE_WIDTH - MARGIN, y + 4)
.stroke('#cccccc');
y += 12;
}
// Empty line
else if (line.trim() === '') {
y += 8;
}
// Regular text / bullet / table row
else {
doc.fontSize(10).font(FONT_PATH).fillColor('#333333');
y = doc.text(line, MARGIN, y + 2, {
width: PAGE_WIDTH - 2 * MARGIN,
lineGap: 2
}).y + 2;
}
doc.fillColor('#000000');
}
doc.end();
return new Promise((resolve, reject) => {
stream.on('finish', () => resolve(outputPath));
stream.on('error', reject);
});
}
// Export for use as module
module.exports = { generatePDF };
// CLI usage
if (require.main === module) {
const args = process.argv.slice(2);
const mdFile = args[0];
const outFile = args[1] || 'report.pdf';
const title = args[2] || '市场报告';
const md = fs.readFileSync(mdFile, 'utf-8');
generatePDF(md, outFile, title).then(() => {
console.log(`PDF generated: ${outFile}`);
});
}
CLI Usage
# From workspace root:
node skills/pdf-report-generator/scripts/generate_pdf.js input.md output.pdf "市场日报"
Step 3: Verify output
- Open generated PDF and check:
- Chinese characters render correctly
- Headers/footers appear on every page
- Page numbers increment properly
- Tables align correctly
- Color markers (🟢🔴) display
- No content overflow at page boundaries
Integration with daily-market-report
After daily-market-report produces a Markdown string, call this skill:
- Save the Markdown to a temp file (e.g.,
.tmp-report/latest.md) - Run the Node.js script with the file
- Delete the temp Markdown file
- Return the PDF file path to the user
Quick Function (Python → Node bridge)
import subprocess
import tempfile
import os
def markdown_to_pdf(markdown_content, output_path, title="市场报告"):
"""Convert Markdown string to PDF file."""
# Write temp markdown
with tempfile.NamedTemporaryFile(
mode='w', suffix='.md', delete=False, encoding='utf-8'
) as f:
f.write(markdown_content)
md_path = f.name
try:
# Call Node.js generator
subprocess.run([
'node',
'skills/pdf-report-generator/scripts/generate_pdf.js',
md_path, output_path, title
], check=True, cwd=os.getenv('OPENCLAW_WORKSPACE', '.'))
return output_path
finally:
os.unlink(md_path)
Resources
assets/
Place Chinese TrueType font files here for portable use:
NotoSansSC-Regular.ttf— Main Chinese fontNotoSansSC-Bold.ttf— Bold variant (optional)NotoSansSC-Light.ttf— Light variant (optional)
If no font file is in assets/, the script falls back to C:\Windows\Fonts\msyh.ttc.
scripts/
generate_pdf.js— Main PDF generation script (see template above)
Notes
- A4 size: 210mm × 297mm (595.28 × 841.89 points)
- Standard margin: 72pt (1 inch) all sides
- Chinese font rendering requires a TTF/TTC with CJK glyphs
- pdfkit doesn't support CSS — all styling is programmatic
- For table-heavy reports, consider reducing font size to 8-9pt
- The script handles page breaks automatically by tracking Y position
- Color markers: 🟢↔green, 🔴↔red, can be mapped to fill colors
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install zcx-pdf-report-generator - 安装完成后,直接呼叫该 Skill 的名称或使用
/zcx-pdf-report-generator触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
Pdf Report Generator 是什么?
Convert Markdown reports to professionally formatted PDF documents using pdfkit. Supports Chinese fonts, A4 layout, auto headers/footers, page numbers. Desig... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 45 次。
如何安装 Pdf Report Generator?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install zcx-pdf-report-generator」即可一键安装,无需额外配置。
Pdf Report Generator 是免费的吗?
是的,Pdf Report Generator 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
Pdf Report Generator 支持哪些平台?
Pdf Report Generator 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Pdf Report Generator?
由 zhaocaixia888(@zhaocaixia888)开发并维护,当前版本 v1.0.0。