← Back to Skills Marketplace
zhaocaixia888

Pdf Report Generator

by zhaocaixia888 · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ Security Clean
45
Downloads
0
Stars
0
Active Installs
1
Versions
Install in OpenClaw
/install zcx-pdf-report-generator
Description
Convert Markdown reports to professionally formatted PDF documents using pdfkit. Supports Chinese fonts, A4 layout, auto headers/footers, page numbers. Desig...
README (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
Usage Guidance
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.
Capability Tags
crypto
Capability Assessment
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.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install zcx-pdf-report-generator
  3. After installation, invoke the skill by name or use /zcx-pdf-report-generator
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.0
Initial release on ClawHub
Metadata
Slug zcx-pdf-report-generator
Version 1.0.0
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 1
Frequently Asked Questions

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.

💬 Comments