python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python PDF手写模拟器

基于Python打造一个PDF手写模拟器

作者:ChenAI_TGF

这篇文章主要为大家详细介绍了如何基于Python打造一个PDF手写模拟器,轻松搞定手写作业,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

前言

作为学生,想必大家都有过被海量手写实验报告、课程作业支配的痛苦。要花费大量时间一笔一划地抄写到纸质文档中再进行扫描成pdf提交,不仅耗时耗力,手写的字迹还可能参差不齐,影响作业美观度。

为了偷懒,博主开发了一款基于python的PDF手写模拟器,它能够模拟真实手写笔迹,将电脑上的文字批量填充到 PDF 指定区域,支持中文/英文分开配置、手写扰动效果自定义、配置模版复用等功能,生成的效果高度贴近真实手写,帮你彻底告别手动抄写的烦恼。首先来个界面以及效果预览:

流程思路总览

这款 PDF 手写模拟器的整体运作流程可以分为「用户操作流程」和「技术实现流程」两层,清晰易懂:

1. 用户操作流程(简单易上手)

打开目标 PDF:选择需要填写的实验报告、作业等 PDF 文件;

框选填写区域:在 PDF 预览界面拖动鼠标,框选出需要插入文字的区域(红色矩形标记);

配置手写参数:分别在中文、英文/数字选项卡中调整字体、大小、颜色、扰动效果等参数;

输入并预览文字:在右侧文本框输入需要填写的内容,开启「实时预览」查看手写效果;

不满意可实时调整参数

确认并保存:效果满意后确认应用笔迹,支持撤销、擦除错误内容,也可保存当前配置为模版,最后导出填写完成的 PDF。

2. 技术实现流程(分层协作)

┌─────────────────────┐
│  UI交互层(tkinter) │  # 可视化交互,接收操作
└─────────────┬───────┘
              ▼
┌─────────────────────┐
│  参数配置层(JSON)  │  # 参数管理,模版复用
└─────────────┬───────┘
              ▼
┌─────────────────────┐
│ PDF操作层(PyMuPDF) │  # PDF核心操作(读写/保存等)
└─────────────┬───────┘
              ▼
┌─────────────────────┐
│  手写渲染层(核心)  │  # 手写效果生成,文字插入
└─────────────────────┘

涉及的具体技术

这款工具基于 Python 生态的常用库开发,技术栈轻量化且实用性强,核心涉及以下技术:

最终效果演示

代码原理简单讲解(手写字体生成 + 扰动效果)

我们重点讲解核心功能 —— 手写字体生成与扰动效果的实现,忽略 UI 搭建等辅助代码,聚焦核心逻辑:

手写字体生成(文字插入 PDF 核心)

这部分的核心是将文字按规则排版后,插入到 PDF 指定区域,关键步骤如下:

1.文字与区域预处理

首先获取文本框中的输入文字,按换行符 \n 分割成多行,同时将用户框选的预览区域坐标(带缩放比例)转换为 PDF 实际坐标(除以缩放系数 self.zoom),得到真实的填写范围 (x1, y1, x2, y2)

# 读取输入文字并分割行
text = self.text_editor.get("1.0", tk.END).strip("\n")
lines = text.split('\n')
# 转换为 PDF 实际坐标(去除预览缩放影响)
x1, y1 = min(self.start_x, self.end_x)/self.zoom, min(self.start_y, self.end_y)/self.zoom
x2, y2 = max(self.start_x, self.end_x)/self.zoom, max(self.start_y, self.end_y)/self.zoom

2.语言区分与参数匹配

通过 is_chinese 函数判断单个字符是中文还是英文/数字,分别匹配对应的配置参数(中文/英文独立的字体、大小、字距等),确保不同语言的手写效果适配合理。

# 判断是否为中文(含中文标点)
def is_chinese(self, char):
    if '\u4e00' <= char <= '\u9fff': return True
    if char in "。,、?!:;“”‘'()《》【】": return True
    return False

# 遍历字符时匹配对应语言参数
lang = 'zh' if self.is_chinese(char) else 'en'
p = self.params[lang]  # 获取对应语言的配置参数

3.PDF 文字插入核心 API

使用 PyMuPDF 的 page.insert_text 方法实现文字插入,这是手写字体生成的关键,核心参数说明如下:

4.行与字符排版

按行遍历文字,逐字符计算插入坐标,处理空格(单独预留间距),当字符横坐标超出框选区域右侧时自动换行,同时根据「行距参数」调整下一行的纵坐标,确保文字排版规整且不超出框选范围。

扰动效果实现(模拟真实手写不规则性)

这是工具的灵魂所在,通过「行级扰动」和「字符级扰动」两层效果,彻底摆脱打印体的规整感,贴近真实手写,对应代码中的配置参数:

行级扰动(整行不规则性):针对每一行文字,添加整体的偏移和倾斜,模拟手写时「行不直、略有偏移」的特点,对应三个参数:

# 行级扰动参数计算
line_dx = random.uniform(-p_line['line_jitter_x'].get(), p_line['line_jitter_x'].get())
line_dy = random.uniform(-p_line['line_jitter_y'].get(), p_line['line_jitter_y'].get())
line_angle_deg = random.uniform(-p_line['line_tilt'].get(), p_line['line_tilt'].get())
line_angle_rad = math.radians(line_angle_deg)

字符级扰动(单个字符不规则性):针对每个字符,添加位置、大小、旋转的细微差异,模拟手写时「每个字大小不一、略有晃动」的特点,对应三个参数:

# 字符级扰动参数计算
char_jitter_x = random.uniform(-p['jitter_pos'].get(), p['jitter_pos'].get())
char_jitter_y = random.uniform(-p['jitter_pos'].get(), p['jitter_pos'].get())
char_jitter_rot = random.uniform(-p['jitter_rot'].get(), p['jitter_rot'].get())
char_jitter_fs = f_size + random.uniform(-p['jitter_size'].get(), p['jitter_size'].get())

随机数控制(预览稳定 + 实际随机):为了保证实时预览时效果稳定可调整,设置随机数种子 random.seed(42) 固定扰动效果;实际应用笔迹时,不设置种子 random.seed(),生成随机的扰动效果,让每次生成的手写风格略有差异,更贴近真实场景。

if is_preview: random.seed(42)  # 预览模式:固定随机数,效果稳定
else: random.seed()  # 实际生成:随机种子,效果更真实

总结

这款 PDF 手写模拟器完美解决了手写作业、实验报告的痛点,兼具「实用性」和「灵活性」:

当然,这款工具还有优化空间,比如支持连笔效果、笔迹粗细变化、批量处理多个 PDF 等。如果大家有类似需求,可以基于这份代码进行二次开发,适配自己的使用场景。

以上就是基于Python打造一个PDF手写模拟器的详细内容,更多关于Python PDF手写模拟器的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文