← 返回 Skills 市场
zhaocaixia888

Pdf Report Generator

作者 zhaocaixia888 · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ 安全检测通过
45
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install zcx-pdf-report-generator
功能描述
Convert Markdown reports to professionally formatted PDF documents using pdfkit. Supports Chinese fonts, A4 layout, auto headers/footers, page numbers. Desig...
使用说明 (SKILL.md)

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:

  1. Save the Markdown to a temp file (e.g., .tmp-report/latest.md)
  2. Run the Node.js script with the file
  3. Delete the temp Markdown file
  4. 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 font
  • NotoSansSC-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
安全使用建议
Before installing, confirm you trust the local pdfkit package that Node will load and choose output paths intentionally, since the script writes to the path you provide. The single VirusTotal detection should be treated as telemetry rather than decisive evidence here.
能力标签
crypto
能力评估
Purpose & Capability
The artifacts consistently describe converting Markdown reports to A4 PDFs using pdfkit; the executable script only reads a user-supplied Markdown file and writes a user-supplied PDF output.
Instruction Scope
Runtime instructions are limited to invoking a Node.js generator and optionally bridging from Python for conversion; deletion is limited to a temporary Markdown file created by the example workflow.
Install Mechanism
The skill expects Node and an existing pdfkit installation, with optional PDFKIT_PATH metadata, but the script uses normal Node require('pdfkit') resolution rather than dynamically installing packages.
Credentials
Local filesystem access is proportionate to the stated PDF-generation purpose: read input Markdown, check local font files, and create the requested PDF.
Persistence & Privilege
No startup hooks, background workers, credential use, privilege escalation, session access, or durable persistence mechanisms were found.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install zcx-pdf-report-generator
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /zcx-pdf-report-generator 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial release on ClawHub
元数据
Slug zcx-pdf-report-generator
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

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。

💬 留言讨论