基于Python打造一個PDF手寫模擬器
前言
作為學(xué)生,想必大家都有過被海量手寫實(shí)驗(yàn)報告、課程作業(yè)支配的痛苦。要花費(fèi)大量時間一筆一劃地抄寫到紙質(zhì)文檔中再進(jìn)行掃描成pdf提交,不僅耗時耗力,手寫的字跡還可能參差不齊,影響作業(yè)美觀度。
為了偷懶,博主開發(fā)了一款基于python的PDF手寫模擬器,它能夠模擬真實(shí)手寫筆跡,將電腦上的文字批量填充到 PDF 指定區(qū)域,支持中文/英文分開配置、手寫擾動效果自定義、配置模版復(fù)用等功能,生成的效果高度貼近真實(shí)手寫,幫你徹底告別手動抄寫的煩惱。首先來個界面以及效果預(yù)覽:

流程思路總覽
這款 PDF 手寫模擬器的整體運(yùn)作流程可以分為「用戶操作流程」和「技術(shù)實(shí)現(xiàn)流程」兩層,清晰易懂:
1. 用戶操作流程(簡單易上手)
打開目標(biāo) PDF:選擇需要填寫的實(shí)驗(yàn)報告、作業(yè)等 PDF 文件;


框選填寫區(qū)域:在 PDF 預(yù)覽界面拖動鼠標(biāo),框選出需要插入文字的區(qū)域(紅色矩形標(biāo)記);

配置手寫參數(shù):分別在中文、英文/數(shù)字選項卡中調(diào)整字體、大小、顏色、擾動效果等參數(shù);

輸入并預(yù)覽文字:在右側(cè)文本框輸入需要填寫的內(nèi)容,開啟「實(shí)時預(yù)覽」查看手寫效果;


不滿意可實(shí)時調(diào)整參數(shù)

確認(rèn)并保存:效果滿意后確認(rèn)應(yīng)用筆跡,支持撤銷、擦除錯誤內(nèi)容,也可保存當(dāng)前配置為模版,最后導(dǎo)出填寫完成的 PDF。

2. 技術(shù)實(shí)現(xiàn)流程(分層協(xié)作)
- UI 交互層:基于 tkinter 搭建可視化界面,提供按鈕、選項卡、文本框等交互組件,接收用戶操作;
- 參數(shù)配置層:管理中文/英文手寫參數(shù),支持配置保存(JSON)與加載,實(shí)現(xiàn)模版復(fù)用;
- PDF 操作層:基于 PyMuPDF 實(shí)現(xiàn) PDF 的讀取、頁面渲染、文字插入、擦除、保存等核心操作;
- 手寫渲染層:核心邏輯層,實(shí)現(xiàn)文字排版、語言區(qū)分、手寫擾動效果生成,最終將模擬手寫文字插入 PDF。
┌─────────────────────┐
│ UI交互層(tkinter) │ # 可視化交互,接收操作
└─────────────┬───────┘
▼
┌─────────────────────┐
│ 參數(shù)配置層(JSON) │ # 參數(shù)管理,模版復(fù)用
└─────────────┬───────┘
▼
┌─────────────────────┐
│ PDF操作層(PyMuPDF) │ # PDF核心操作(讀寫/保存等)
└─────────────┬───────┘
▼
┌─────────────────────┐
│ 手寫渲染層(核心) │ # 手寫效果生成,文字插入
└─────────────────────┘
涉及的具體技術(shù)
這款工具基于 Python 生態(tài)的常用庫開發(fā),技術(shù)棧輕量化且實(shí)用性強(qiáng),核心涉及以下技術(shù):
- tkinter:Python 內(nèi)置 GUI 庫,無需額外安裝,負(fù)責(zé)搭建整個應(yīng)用的可視化界面,實(shí)現(xiàn)按鈕點(diǎn)擊、參數(shù)調(diào)整、文本輸入、PDF 預(yù)覽等交互功能;
- PyMuPDF(fitz):核心 PDF 處理庫,提供高效的 PDF 讀取、寫入、頁面渲染、文字插入、紅act標(biāo)注(擦除功能)等接口,是實(shí)現(xiàn) PDF 編輯的核心依賴;
- Pillow(PIL):圖像處理庫,將 PyMuPDF 渲染出的 PDF 頁面像素數(shù)據(jù),轉(zhuǎn)換成 tkinter 畫布可顯示的圖像格式,實(shí)現(xiàn) PDF 頁面的可視化預(yù)覽;
- JSON:輕量級數(shù)據(jù)格式,用于保存用戶配置的手寫參數(shù)模版(字體、大小、擾動值等),方便后續(xù)直接復(fù)用,無需重復(fù)調(diào)整;
- Python 隨機(jī)數(shù)與數(shù)學(xué)計算:實(shí)現(xiàn)手寫效果的「不規(guī)則擾動」,模擬真實(shí)手寫的位置偏移、大小波動、行傾斜等特性;
- TTF 字體支持:讀取自定義 TrueType 字體文件,支持切換不同手寫風(fēng)格字體,適配不同用戶的手寫習(xí)慣。
最終效果演示

代碼原理簡單講解(手寫字體生成 + 擾動效果)
我們重點(diǎn)講解核心功能 —— 手寫字體生成與擾動效果的實(shí)現(xiàn),忽略 UI 搭建等輔助代碼,聚焦核心邏輯:
手寫字體生成(文字插入 PDF 核心)
這部分的核心是將文字按規(guī)則排版后,插入到 PDF 指定區(qū)域,關(guān)鍵步驟如下:
1.文字與區(qū)域預(yù)處理
首先獲取文本框中的輸入文字,按換行符 \n 分割成多行,同時將用戶框選的預(yù)覽區(qū)域坐標(biāo)(帶縮放比例)轉(zhuǎn)換為 PDF 實(shí)際坐標(biāo)(除以縮放系數(shù) self.zoom),得到真實(shí)的填寫范圍 (x1, y1, x2, y2)。
# 讀取輸入文字并分割行
text = self.text_editor.get("1.0", tk.END).strip("\n")
lines = text.split('\n')
# 轉(zhuǎn)換為 PDF 實(shí)際坐標(biāo)(去除預(yù)覽縮放影響)
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.語言區(qū)分與參數(shù)匹配
通過 is_chinese 函數(shù)判斷單個字符是中文還是英文/數(shù)字,分別匹配對應(yīng)的配置參數(shù)(中文/英文獨(dú)立的字體、大小、字距等),確保不同語言的手寫效果適配合理。
# 判斷是否為中文(含中文標(biāo)點(diǎn))
def is_chinese(self, char):
if '\u4e00' <= char <= '\u9fff': return True
if char in "。,、??。?;“”‘'()《》【】": return True
return False
# 遍歷字符時匹配對應(yīng)語言參數(shù)
lang = 'zh' if self.is_chinese(char) else 'en'
p = self.params[lang] # 獲取對應(yīng)語言的配置參數(shù)
3.PDF 文字插入核心 API
使用 PyMuPDF 的 page.insert_text 方法實(shí)現(xiàn)文字插入,這是手寫字體生成的關(guān)鍵,核心參數(shù)說明如下:
fitz.Point(final_x, final_y):文字的實(shí)際插入坐標(biāo)(經(jīng)排版和擾動調(diào)整后);char:要插入的單個字符(逐字符插入實(shí)現(xiàn)精細(xì)排版);fontsize:字符的實(shí)際大?。◣Т笮《秳樱?/li>fontfile:TTF 手寫字體文件路徑,決定字體風(fēng)格;color:文字顏色(默認(rèn)純黑,支持用戶自定義);morph:變換矩陣,實(shí)現(xiàn)字符旋轉(zhuǎn)效果(疊加行傾斜與字符旋轉(zhuǎn)抖動)。
4.行與字符排版
按行遍歷文字,逐字符計算插入坐標(biāo),處理空格(單獨(dú)預(yù)留間距),當(dāng)字符橫坐標(biāo)超出框選區(qū)域右側(cè)時自動換行,同時根據(jù)「行距參數(shù)」調(diào)整下一行的縱坐標(biāo),確保文字排版規(guī)整且不超出框選范圍。
擾動效果實(shí)現(xiàn)(模擬真實(shí)手寫不規(guī)則性)
這是工具的靈魂所在,通過「行級擾動」和「字符級擾動」兩層效果,徹底擺脫打印體的規(guī)整感,貼近真實(shí)手寫,對應(yīng)代碼中的配置參數(shù):
行級擾動(整行不規(guī)則性):針對每一行文字,添加整體的偏移和傾斜,模擬手寫時「行不直、略有偏移」的特點(diǎn),對應(yīng)三個參數(shù):
# 行級擾動參數(shù)計算 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)
- 行左右平移(
line_jitter_x):隨機(jī)生成-line_jitter_x ~ line_jitter_x范圍內(nèi)的偏移量line_dx,使每行文字左右輕微晃動; - 行上下平移(
line_jitter_y):隨機(jī)生成-line_jitter_y ~ line_jitter_y范圍內(nèi)的偏移量line_dy,使行與行之間的間距略有差異; - 行整行傾斜(
line_tilt):隨機(jī)生成傾斜角度line_angle_deg,轉(zhuǎn)換為弧度后,通過tilt_y_offset = (curr_x - line_start_x) * math.tan(line_angle_rad)計算每個字符的Y軸偏移,實(shí)現(xiàn)整行輕微傾斜。
字符級擾動(單個字符不規(guī)則性):針對每個字符,添加位置、大小、旋轉(zhuǎn)的細(xì)微差異,模擬手寫時「每個字大小不一、略有晃動」的特點(diǎn),對應(yīng)三個參數(shù):
# 字符級擾動參數(shù)計算 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())
- 字位置抖動(
jitter_pos):隨機(jī)生成(-jitter_pos ~ jitter_pos)的X、Y偏移量,使字符脫離嚴(yán)格的水平對齊; - 字大小抖動(
jitter_size):在基礎(chǔ)字體大小上,隨機(jī)增減(-jitter_size ~ jitter_size)的數(shù)值,生成char_jitter_fs,使字符大小略有差異; - 字旋轉(zhuǎn)抖動(
jitter_rot):隨機(jī)生成(-jitter_rot ~ jitter_rot)的旋轉(zhuǎn)角度,疊加行傾斜角度后,通過morph參數(shù)實(shí)現(xiàn)字符輕微旋轉(zhuǎn)。
隨機(jī)數(shù)控制(預(yù)覽穩(wěn)定 + 實(shí)際隨機(jī)):為了保證實(shí)時預(yù)覽時效果穩(wěn)定可調(diào)整,設(shè)置隨機(jī)數(shù)種子 random.seed(42) 固定擾動效果;實(shí)際應(yīng)用筆跡時,不設(shè)置種子 random.seed(),生成隨機(jī)的擾動效果,讓每次生成的手寫風(fēng)格略有差異,更貼近真實(shí)場景。
if is_preview: random.seed(42) # 預(yù)覽模式:固定隨機(jī)數(shù),效果穩(wěn)定 else: random.seed() # 實(shí)際生成:隨機(jī)種子,效果更真實(shí)
總結(jié)
這款 PDF 手寫模擬器完美解決了手寫作業(yè)、實(shí)驗(yàn)報告的痛點(diǎn),兼具「實(shí)用性」和「靈活性」:
- 實(shí)用性拉滿:無需手動抄寫,一鍵生成手寫風(fēng)格 PDF,節(jié)省大量時間和精力,生成效果高度貼近真實(shí)手寫;
- 自定義性強(qiáng):中文/英文獨(dú)立配置,支持字體、顏色、大小、字距行距調(diào)整,多層擾動參數(shù)可精細(xì)調(diào)控手寫風(fēng)格;
- 操作便捷:可視化界面友好,支持實(shí)時預(yù)覽、撤銷、擦除、模版復(fù)用,零基礎(chǔ)用戶也能快速上手;
- 技術(shù)輕量化:基于 Python 常用庫開發(fā),無需復(fù)雜環(huán)境配置,代碼可靈活修改擴(kuò)展。
當(dāng)然,這款工具還有優(yōu)化空間,比如支持連筆效果、筆跡粗細(xì)變化、批量處理多個 PDF 等。如果大家有類似需求,可以基于這份代碼進(jìn)行二次開發(fā),適配自己的使用場景。
以上就是基于Python打造一個PDF手寫模擬器的詳細(xì)內(nèi)容,更多關(guān)于Python PDF手寫模擬器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python數(shù)據(jù)寫入Excel文件中的實(shí)現(xiàn)步驟
Python作為時下流行的語言,數(shù)據(jù)寫入Excel是必要的操作,下面這篇文章主要給大家介紹了關(guān)于python數(shù)據(jù)寫入Excel文件中的簡單實(shí)現(xiàn)方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
Python常用模塊logging——日志輸出功能(示例代碼)
logging模塊是Python的內(nèi)置模塊,主要用于輸出運(yùn)行日志,可以靈活配置輸出日志的各項信息。這篇文章主要介紹了Python常用模塊logging——日志輸出的實(shí)例代碼,需要的朋友可以參考下2019-11-11
詳解Python中的分支和循環(huán)結(jié)構(gòu)
這篇文章主要介紹了Python中的分支和循環(huán)結(jié)構(gòu),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02
python人工智能tensorflow構(gòu)建卷積神經(jīng)網(wǎng)絡(luò)CNN
學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)已經(jīng)有一段時間,從普通的BP神經(jīng)網(wǎng)絡(luò)到LSTM長短期記憶網(wǎng)絡(luò)都有一定的了解,但是從未系統(tǒng)的把整個神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)記錄下來,我相信這些小記錄可以幫助我更加深刻的理解神經(jīng)網(wǎng)絡(luò)2022-05-05
如何利用Python處理excel表格中的數(shù)據(jù)
Excel做為職場人最常用的辦公軟件,具有方便、快速、批量處理數(shù)據(jù)的特點(diǎn),下面這篇文章主要給大家介紹了關(guān)于如何利用Python處理excel表格中數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2022-03-03
在Python中實(shí)現(xiàn)字典反轉(zhuǎn)案例
這篇文章主要介紹了在Python中實(shí)現(xiàn)字典反轉(zhuǎn)案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Python 實(shí)現(xiàn)刪除某路徑下文件及文件夾的實(shí)例講解
下面小編就為大家分享一篇Python 實(shí)現(xiàn)刪除某路徑下文件及文件夾的實(shí)例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04
在Pytorch中計算卷積方法的區(qū)別詳解(conv2d的區(qū)別)
今天小編就為大家分享一篇在Pytorch中計算卷積方法的區(qū)別詳解(conv2d的區(qū)別),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01

