CtrlK
BlogDocsLog inGet started
Tessl Logo

pdf-skill

PDF 读/写/转/OCR 一体化。触发场景:总结 PDF、读文本或表格、填 AcroForm 表单、渲染页面为图、合并/拆分/水印/旋转/加密、创建新 PDF(发票/报告)、PDF ↔ docx/md/txt 互转。典型说法:“总结这份 PDF”、“填一下这个 PDF 表单”、“把几个 PDF 合一起”、“PDF 加水印”、“PDF 转 Word”、“扫描件 OCR”、“看看 PDF 第 3 页长什么样”。用户提到 .pdf 文件、要产出 PDF、或要对 PDF 做任何改动都加载本技能。

76

Quality

95%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

PDF 技能

读用 PdfInspect写 / 改 / 创建一律用 JsSandbox 跑 Node 脚本调用 pdf-lib / pdfkit / pdf-parse 等预装库;格式互转用 DocConvert;扫描件走 CloudImageUnderstand

工具清单

工具做什么只读
PdfInspect读:summary / text / tables / form-fields / form-structure / images / annotations / render
JsSandbox所有写操作:创建新 PDF、合并、水印、旋转、填表、加密…… 用 pdf-lib / pdfkit 代码实现
DocConvert格式互转:pdf ↔ docx / html / md / txt / xlsx
CloudImageUnderstand扫描 PDF 的 OCR 入口(云端,会扣积分)

加载(两步,缺一不可)

  1. LoadSkill pdf-skill —— 仅把本技能文档拉进上下文。
  2. ToolSearch(query: "select:PdfInspect,JsSandbox,DocConvert") —— 激活工具 schema。

Read 对 .pdf 只走轻量摘要;任何分析/总结/填/改/转/OCR PDF 都走 PdfInspect + JsSandbox


1. 读:PdfInspect 是唯一入口

不知道 PDF 长啥样先 summary

PdfInspect { action: "summary", filePath: "…" }

返回 pageCount / fileSize / characterCount / hasForm / encryption / textType,按 textType

textType下一步
extractablePdfInspect(text) 直接取全文
scanned / cid-encodedPdfInspect(render, pageRange) → 再调 CloudImageUnderstand 对每张 PNG OCR
isEncrypted: true走下面 JsSandbox pdf-lib 解密,或 PdfInspect(password)

大 PDF 必传 pageRange(如 "1-5"),否则触发截断。

AcroForm 表单:PdfInspect(form-fields)checkedValue / radioOptions 再填。


2. 写:JsSandbox + pdf-lib / pdfkit

首选 pdf-lib(编辑已有 PDF / 合并 / 水印 / 旋转 / 填表 / 解密); 从零生成复杂布局pdfkit(矢量 + 文字 + 图)。

2.1 Demo:创建一份中文发票 PDF(pdfkit

import PDFDocument from 'pdfkit'
import fs from 'node:fs'

const doc = new PDFDocument({ size: 'A4', margin: 48 })
doc.pipe(fs.createWriteStream('invoice.pdf'))

doc.fontSize(22).text('INVOICE', { align: 'right' })
doc.moveDown()
doc.fontSize(10).text('Acme Corp', { align: 'right' })
doc.text('Invoice #2026-042   Date: 2026-04-20', { align: 'right' })
doc.moveDown()

// 简易表格
const rows = [
  ['Widget', 1, 50.00],
  ['Gadget', 2, 30.00],
]
doc.fontSize(12).text('Description     Qty     Unit     Total')
doc.moveTo(48, doc.y).lineTo(547, doc.y).stroke()
let total = 0
for (const [name, qty, unit] of rows) {
  const line = qty * unit
  total += line
  doc.text(`${name.padEnd(14)} ${qty}       $${unit.toFixed(2)}   $${line.toFixed(2)}`)
}
doc.moveDown().fontSize(14).text(`Total: $${total.toFixed(2)}`, { align: 'right' })

doc.end()
await new Promise(r => doc.on('end', r))
console.log('invoice.pdf written')

CJK 提示:pdfkit 默认字体不含中文字形。若要出中文,先用 doc.registerFont('cn', '/path/to/NotoSansCJK.ttf')doc.font('cn')。系统 fallback 字体不保证覆盖。

2.2 Demo:给已有 PDF 加 CONFIDENTIAL 水印(pdf-lib

import { PDFDocument, rgb, degrees, StandardFonts } from 'pdf-lib'
import fs from 'node:fs/promises'

const src = await fs.readFile(process.argv[2] ?? 'input.pdf')
const pdf = await PDFDocument.load(src)
const font = await pdf.embedFont(StandardFonts.HelveticaBold)

for (const page of pdf.getPages()) {
  const { width, height } = page.getSize()
  page.drawText('CONFIDENTIAL', {
    x: width / 2 - 140,
    y: height / 2,
    size: 64,
    font,
    color: rgb(0.9, 0.1, 0.1),
    opacity: 0.25,
    rotate: degrees(-30),
  })
}

const out = await pdf.save()
await fs.writeFile('watermarked.pdf', out)
console.log(`watermarked ${pdf.getPageCount()} pages`)

2.3 Demo:合并 PDF(pdf-lib

import { PDFDocument } from 'pdf-lib'
import fs from 'node:fs/promises'

const merged = await PDFDocument.create()
for (const p of ['a.pdf', 'b.pdf', 'c.pdf']) {
  const src = await PDFDocument.load(await fs.readFile(p))
  const pages = await merged.copyPages(src, src.getPageIndices())
  pages.forEach(pg => merged.addPage(pg))
}
await fs.writeFile('merged.pdf', await merged.save())
console.log(`merged → ${merged.getPageCount()} pages`)

2.4 Demo:填 AcroForm 表单(先 PdfInspect(form-fields)checkedValue

import { PDFDocument } from 'pdf-lib'
import fs from 'node:fs/promises'

const pdf = await PDFDocument.load(await fs.readFile('form.pdf'))
const form = pdf.getForm()
form.getTextField('full_name').setText('张三')
form.getCheckBox('agree').check()          // 若 PdfInspect 给出 checkedValue='Y',用 setValue('Y')
form.getRadioGroup('gender').select('M')
// form.flatten() // 想锁表单就 flatten
await fs.writeFile('filled.pdf', await pdf.save())
console.log('form filled')

2.5 Demo:解密 / 旋转 / 抽页

// 解密
import { PDFDocument } from 'pdf-lib'
const pdf = await PDFDocument.load(buf, { password: 'secret', ignoreEncryption: false })
await fs.writeFile('unlocked.pdf', await pdf.save())

// 旋转第 1 页 90°
pdf.getPage(0).setRotation(degrees(90))

// 抽出第 3、5 页到新 PDF
const out = await PDFDocument.create()
const [p3, p5] = await out.copyPages(pdf, [2, 4])
out.addPage(p3); out.addPage(p5)

3. OCR(扫描件)

PdfInspect(summary)              // textType == 'scanned'
PdfInspect(render, pageRange)    // 得到 [<asset>/render-p1.png, ...]
CloudImageUnderstand(image=<上面每张 png>, question='精确识别并提取中文文字')

4. 格式互转

DocConvert(from="pdf", to="docx", sourcePath="…")   # PDF → Word 编辑
DocConvert(from="docx", to="pdf", sourcePath="…")   # Word → PDF 分发

DocConvertJsSandbox + pdf-lib 快且排版忠实;互转优先它


5. 常见错误兜底

症状原因处理
pdfkit 中文乱码 / 方块默认字体不含 CJK 字形registerFont('cn', '/path/to/NotoSansCJK.ttf')
pdf-lib 加载报 EncryptedPDFError文件加密PDFDocument.load(buf, { password: '…' })
水印覆盖不均PDF 页面大小不同循环 page.getSize() 按页算 x/y
合并后字体变样原 PDF 嵌字体不完整pdf-libuseObjectStreams: false 重写
TypeError: Cannot read properties of undefined (reading 'save')pdfkit 没有 doc.save() / doc.restore()(那是 Canvas 2D API)颜色/字号状态直接用 doc.fillColor() / doc.fontSize() 切换即可,不需要保存-恢复栈。最终文档落盘用 doc.pipe(fs.createWriteStream(...)); doc.end()

修脚本:JsSandbox(action="edit-and-run", scriptPath=<上次的>, edits=[{find,replace}]) 只传改动点。

Repository
itsablabla/openloaf-web
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.