Community图像github.com

atlasmarkz/handwriting-pdf

将手写样本转换为可复用的 TrueType 字体和稳定配置,然后用该字体排版任意文本并导出可打印的 PDF。完全本地运行,支持 Windows/macOS/Linux。

handwriting-pdf 是什么?

该技能提供了一套完整的本地化工作流程,用于从用户手写样本(照片、填写好的练习表或已有手写笔迹的 PDF)生成 TrueType 字体(.ttf),并使用该字体将任意文本渲染为逼真的手写风格 PDF。它特别强调隐私(所有处理均在本地完成,样本永不离开设备)和诚实性(字体仅包含样本中实际出现的字符,缺失字符会报告并用中性的手写后备字体替代,绝不会编造)。技能支持多种输入方式:通过练习表获得最优质量(自动单元格映射)、从现有 PDF 提取嵌入式字体或从文本层收割字形、从自由照片手动分割,以及直接使用用户已有的字体文件。生成的字体和布局参数可以保存为可复用的“配置文件”,方便在不同项目中快速调用相同风格。此外,提供了一个实验性的合成引擎,能够从已写的字符子集推断未写字符的风格(如倾斜度、笔画粗细),以覆盖更完整的字符集,特别是中文场景。该技能适用于需要生成手写风格文档、信件、笔记或个性化字体的开发者和普通用户。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/atlasmarkz/handwriting-pdf/tree/HEAD

Installed? Explore more 图像 skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

手写 → PDF

从手写样本构建真正的 .ttf 字体,然后用该字体将文本渲染成看起来像作者亲手写下的 PDF。一切都在本地运行;样本绝不会离开你的机器。

一开始就要告诉用户的真相: 这不是一个能从一张照片凭空发明 3000 个汉字的人工智能。一个字体只能包含样本中实际写下的字符。所以:拉丁文本需要大约 60–100 个手写字符;中文文本需要文档中的每一个不重复的字符(几百个是正常的,几千个则不切实际)。缺失的字符会用中性的手写后备字体绘制并报告——绝不会悄无声息地编造。

0. 定位工具

技能目录是包含此 SKILL.md 的文件夹。通过其启动器调用 CLI:

  • Windows:<skill>\bin\hwpdf.cmd <command> ...
  • macOS/Linux:<skill>/bin/hwpdf <command> ...

如果启动器缺失,请先安装(Windows 上运行 <skill>\install.ps1,其他系统上运行 <skill>/install.sh),或者在依赖已就绪时直接运行 python <skill>/scripts/hwpdf.py <command> ...。hwpdf doctor 必须打印 status ok 才能进行后续操作;如果不是,请运行安装程序并报告依赖错误,而不是自行尝试修复。

1. 选择输入流程

情况流程
默认:用户想要一份自己手写的真实文档A. 练习表(最佳质量,自动单元格映射)
用户给你一份已经显示他们手写笔迹的 PDFD. PDF 输入——先尝试嵌入字体,否则从文本层收割字形
用户已经发送了一张手写照片,并且不想再写更多B. 自由照片(由代理标记裁剪的字形)
用户已有自己的 .ttf/.otf 字体C. 仅字体——跳到步骤 4,然后保存配置文件

在生成任何内容之前,先询问文档文本:因为练习表只需要文档中出现的字符,所以短文本意味着短练习表。

流程 A — 练习表(推荐)

  1. 将目标文本放入 UTF-8 文件,例如 hw/doc.txt,然后:
    hwpdf template --text-file hw/doc.txt -d hw
    
    这将生成 hw/template.pdf(和 hw/template.json)。每页 30 个单元格,每 30 个不重复字符一页。告诉用户以下几点:
    • 以 100% / 实际大小 打印(永远不要“适应页面”);
    • 用深色笔(0.5 毫米或更粗)描摹每个浅灰色字形——圆珠笔太浅;
    • 保持四个黑色角方块可见且未被标记;
    • 从上方在均匀光线下拍摄每页,填满取景框,然后发送文件。
  2. 按页码顺序扫描照片:
    hwpdf scan hw/page1.jpg hw/page2.jpg -d hw
    
    透视和小角度旋转会根据角方块进行校正。输出 hw/glyphs.json 和 hw/glyphs/*.png。如果一个单元格返回“缺失”,则表示该字形未被书写或太淡——指出是哪些字符,并提供仅重拍那些单元格的机会。
  3. 构建字体:
    hwpdf font -d hw --family "Alex Hand" -o hw/font.ttf
    
  4. 在渲染前检查覆盖率:
    hwpdf coverage --font hw/font.ttf --text-file hw/doc.txt
    
    非零退出状态或 missing 列表意味着那些字符没有字形。修复方法:仅针对那些字符写一份小练习表并合并进来:
    hwpdf template --chars "<missing chars>" -d hw2
    hwpdf scan hw2/page1.jpg -d hw --append
    hwpdf font -d hw -o hw/font.ttf
    
    否则,接受中性后备字体并明确说明。
  5. 渲染:
    hwpdf render --font hw/font.ttf --text-file hw/doc.txt -o hw/letter.pdf --size 12 --paper ruled
    
  6. 检查结果。 将页面渲染为 PNG 并使用视觉工具检查:
    hwpdf preview --pdf hw/letter.pdf -d hw/preview --dpi 150
    
    判断:笔画是否太细/太粗,行距是否太紧,字符是否碰撞或溢出边缘,是否有明显错误?通过 --size、--leading、--jitter、--weight(重建字体)、--paper none|ruled|grid 修复。

流程 D — 用户提供了一份带有手写笔迹的 PDF

这是最快的途径(当它奏效时),因为 PDF 已经包含了字形。

  1. 尝试嵌入式字体程序(最佳:完整字形集,无需重新描摹):
    hwpdf extract-font --pdf user.pdf -d hw
    
    好的输出 = hw/fonts/ 中的一个 .ttf/.otf 文件,带有真实字符映射(mapped > 20)。如果报告显示“subset/cid”,则跳过此步骤。
  2. 否则,如果 PDF 有文本层(当你可以选择字符时就是有),从渲染页面中收割字形——文本层提供标签,光栅图提供墨迹:
    hwpdf pdf-specimen --pdf user.pdf -d hw            # 添加 --font-name "<family>" 仅保留他们的字体
    hwpdf font -d hw --family "Alex Hand" -o hw/font.ttf
    
  3. 否则,它是扫描件:hwpdf rasterize --pdf user.pdf -d hw/pages → 对页面图像执行流程 B,或者要求提供练习表(流程 A)。
  4. 将结果保存为配置文件(下面的步骤 5),然后渲染。

流程 B — 自由照片

  1. hwpdf segment hw/photo.jpg -d hw → hw/contact.png(编号缩略图)+ hw/crops/。
  2. 打开 hw/contact.png 并读取编号。编写 hw/labels.json 为 {"0":"A","1":"b",...},或者使用 hwpdf label -d hw --pair "0=A 1=B 2=''"("" 表示丢弃一个块:点、污渍、页面边缘,或者分成两笔的字形片段)。
  3. hwpdf font -d hw --labels hw/labels.json -o hw/font.ttf,然后执行上面的步骤 4–6。

连笔/草书和复合笔画(如中文字符)使得此流程容易出错;如果结果看起来不好,请切换到流程 A 并说明原因。

流程 C — 用户已有字体

直接跳到 hwpdf coverage 和 hwpdf render,使用 --font <their file> 参数,然后保存配置文件。

配置文件——稳定且可复用的方式

配置文件冻结了重现外观所需的一切:字体文件(复制到配置文件中,并附带 SHA-256 校验)、其默认值以及一个即用即粘贴的提示词。

hwpdf profile save --name alex --font hw/font.ttf --source "user's handwriting pdf"
hwpdf profile list
hwpdf render --profile alex --text-file letter.txt -o letter.pdf
  • 配置文件存放在 ~/.handwriting-pdf/profiles/<name>/ 目录下(profile.json、font.ttf、PROMPT.md);设置 HWPDF_PROFILE_DIR 可重定位。
  • PROMPT.md 是为用户编写的:将其粘贴到任何机器的任何代理上,它将使用相同的布局默认值调用相同的字体。
  • 在迭代外观?一次只改一个参数——渲染、preview、比较,然后运行 hwpdf profile save --name alex --font hw/font.ttf --size ... --paper ... 将其设为新默认值。font --weight 1 会重建更粗的笔画;之后重新保存配置文件以使更改生效。
  • 从 PDF 构建的配置文件仅覆盖该 PDF 中出现的字符。在承诺完整文档之前,请使用 hwpdf coverage --font <profile font> --text-file <new doc> 进行检查。

合成——用户从未写过的字符(实验性)

文档几乎总是需要用户从未写过的字符;在中文中,这是常态而非例外。两种填充方式,按诚实程度排序:

  1. 中性后备字体(默认,可预测):render --fallback auto 自动选择一个系统手写字体;页面混合了用户的手写体和印刷体或中性手写体,并且 render 会报告每个以这种方式绘制的字符。
  2. 合成推断(hwpdf synth,仍为实验性):构建第二个字体,通过借用用户风格的可测量部分——倾斜角度、笔画粗细、x-高度、字形宽度——并将其覆盖到系统骨架字形上,从而覆盖完整字符集。
hwpdf synth doctor                              # 哪些引擎可用,缺失什么
hwpdf synth build --style hw/font.ttf --charset common3500 -o hw/synth.ttf
hwpdf synth specimen --font hw/synth.ttf --real hw/font.ttf -o hw/sheet.png   # 先检查
hwpdf synth verify --font hw/synth.ttf --charset common3500                   # 覆盖率 / 缺失
hwpdf synth eval --font hw/synth.ttf --real hw/font.ttf -o hw/report.md      # 报告的数字
hwpdf profile save --name alex --font hw/font.ttf --synth-font hw/synth.ttf
hwpdf render --profile alex --text-file doc.txt -o out.pdf                    # 合成填补空缺

引擎:stylefit(分析式——无需下载、无需 GPU、确定性;中文字符保留系统无衬线骨架,仅提取用户的倾斜/粗细)和 stub(测试夹具,不是风格迁移)。扩散引擎 diff-font 需要的权重文件的许可问题尚未解决(参见 PLAN.md §8 S4)——synth doctor 会如实说明,而不是假装。

说明其本质: 他们写下的字符会逐字重现;推断出的字符是“他们的倾斜和粗细叠加在印刷体骨架上”。不要告诉用户推断出的部分“看起来像他们”。发货前请检查 <font>.json 中的 meta.gate(rejected 应为 0)并查看样本。

规则

  1. 仅限本地。 永远不要上传样本、字体或输出;没有 API 调用。
  2. 只有用户自己的手写体。 拒绝模仿第三方的手写体、签名或信笺抬头,并拒绝生成签名/合同/证书/官方文件——简要解释(伪造、欺诈、证据规则)并提供一份普通的打印文档作为替代。
  3. 绝不编造质量。 如果字体有 40 个字形,就说 40。如果后备字体绘制了半页内容,就如实说明。逐字报告缺失的字符。
  4. 在指责工具之前,先要求重拍:模糊、有阴影、角部被裁剪或被网格线覆盖的照片是最常见的失败原因。
  5. 保留工作目录(hw/)——用户以后可以添加字符并重建字体。

命令参考

命令用途
hwpdf doctor依赖项 + 系统字体检查
hwpdf template --chars "abc" / --text-file doc.txt -d DIR练习表 PDF + 元数据
hwpdf scan IMG... [-d DIR] [--rotate 90] [--append]拍摄的表格 → 字形蒙版(append = 合并到现有工作中)
hwpdf extract-font --pdf in.pdf -d DIR从 PDF 中提取嵌入式字体(最佳情况:完整 TTF)
hwpdf pdf-specimen --pdf in.pdf -d DIR [--font-name F]从 PDF 的文本层 + 光栅图中收割带有标签的字形
hwpdf rasterize --pdf in.pdf -d DIR [--dpi 300]扫描的 PDF → 页面 PNG
hwpdf segment IMG... [-d DIR] [--thresh N] [--deskew]自由照片 → 块 + 联系表
hwpdf label -d DIR --order "ABC" / --pair "0=A 1=B"将块映射到字符
hwpdf font -d DIR [--labels f] [--family NAME] [--weight -2..2] [--smooth 0..2] -o out.ttf构建字体
hwpdf coverage --font f --text-file doc.txt哪些字符缺失
hwpdf render --font f --text-file doc.txt -o out.pdf [--size 12] [--leading 1.8] [--paper ruled] [--jitter 1] [--ink "#1a1c24"] [--fallback auto|none|path]PDF(--font system:cjk / system:latin = 内置手写字体,当用户没有样本且仅想要手写外观时)
hwpdf render --profile NAME --text-file doc.txt -o out.pdf使用保存的配置文件的字体和默认值生成 PDF
hwpdf profile save/list/show/remove ...冻结/检查可复用的手写配置文件(写入 PROMPT.md)
hwpdf preview --pdf out.pdf -d DIR [--dpi 150]PDF 页面 → 用于视觉检查的 PNG
hwpdf synth doctor / build / specimen / verify / charsets可选的推断引擎:从已写子集生成完整字符集的字体(参见合成部分)
hwpdf selftest -d DIR [--messy]合成的端到端冒烟测试

限制(在相关时说明)

  • 每个字符一个字形:没有连笔草书,没有出现次之间的自然变化,没有压力/墨水纹理。间距抖动是模拟的,字形形状不是。
  • CJK:字体仅包含写下的字符。每页 30 个单元格;一封 300 字的信需要一份 10 页的练习表。hwpdf synth build --charset common3500 是捷径,但推断的 CJK 是带有用户倾斜度的系统无衬线骨架,而不是他们实际的笔触。
  • PDF 文本层是可搜索/可复制的真实文本(使用生成的字体)。
  • 照片必须显示练习表的全部四个黑色角方块。

详细信息:references/workflow.md · references/troubleshooting.md

相关技能