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
- Make sure OpenClaw is installed (local or Docker)
- Run the install command in chat:
/install zcx-pdf-report-generator - After installation, invoke the skill by name or use
/zcx-pdf-report-generator - Provide required inputs per the skill's parameter spec and get structured output
What is Pdf Report Generator?
Convert Markdown reports to professionally formatted PDF documents using pdfkit. Supports Chinese fonts, A4 layout, auto headers/footers, page numbers. Desig... It is an AI Agent Skill for Claude Code / OpenClaw, with 45 downloads so far.
How do I install Pdf Report Generator?
Run "/install zcx-pdf-report-generator" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.
Is Pdf Report Generator free?
Yes, Pdf Report Generator is completely free, licensed under MIT-0. You can download, install and use it at no cost.
Which platforms does Pdf Report Generator support?
Pdf Report Generator is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).
Who created Pdf Report Generator?
It is built and maintained by zhaocaixia888 (@zhaocaixia888); the current version is v1.0.0.