Skip to content

Commit b11ecf5

Browse files
committed
PDF article
1 parent 38af412 commit b11ecf5

File tree

7 files changed

+332
-0
lines changed

7 files changed

+332
-0
lines changed

docs/資訊與科技/article.md

Whitespace-only changes.

docs/資訊與科技/pdf.md

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
---
2+
title: 從手動到自動:數萬份電子簽名處理的最佳實務
3+
authors: 袋鼠
4+
description: 本文示範如何在本機端使用 Python(PyPDF2、reportlab、Pillow)批次為大量 PDF 自動加上電子簽名,包含簽名欄位偵測、座標調整與實務注意事項,適合需保護諮商紀錄隱私的單位。
5+
tags: [PDF,Python,PDF自動簽名,諮商,本機處理,批次處理]
6+
date: 2026-01-07
7+
---
8+
# 從手動到自動:數份電子簽名處理的最佳實務
9+
10+
![](/img/blog/pdf01.png)
11+
12+
## 問題意識與情境
13+
14+
那天,在工作的諮商所遇到了一個實際又棘手的狀況。由於過往部分心理師的諮商紀錄檔案中,未附上正式的電子簽名,因此我們必須協助補齊心理師的簽名檔案,才能符合衛生局的要求。
15+
16+
一開始,我們採取最直觀的方式:逐一打開 PDF 檔案,手動加入心理師的簽名。然而,當我們發現需要處理的紀錄橫跨 2020 年到 2025 年,累積上萬筆檔案 時,這個方法幾乎是不可能完成的任務,光是打開檔案就足以讓人崩潰。原本我們使用的是 **Adobe PDF** 來加入簽名檔,但實際操作後發現速度非常慢,效率極低。於是我開始思考:
17+
18+
> ***是否有辦法一次性替某一位心理師的所有紀錄加上電子簽名?***
19+
>
20+
21+
但問題並沒有這麼單純。不同的紀錄,**簽名欄位的位置並不固定**
22+
23+
有些在第一頁,有些在第二頁,甚至格式略有差異,無法單純用「固定頁數」處理。也因此,我開始研究是否能有一種方式,讓系統**自動判斷簽名欄位的位置,並正確地將電子簽名加上去**。在這個過程中,我開始與 **Claude AI** 討論可能的解法,也逐漸整理出一條可行的處理流程,於是便有了這篇紀錄文。
24+
25+
這套工具最大的好處在於:
26+
27+
- **可在本機端一次處理大量 PDF 檔案**,不需逐一手動開啟
28+
- 系統能自動辨識簽名位置(通常會有簽名欄位),並正確放置電子簽名
29+
- 全程在自己的電腦上完成,符合諮商專業對於隱私與資料保護的要求
30+
31+
對於需要大量補齊電子簽名、又無法將檔案上傳至雲端或第三方服務的情境來說,這是一個非常實用的解法。
32+
33+
## 操作流程
34+
> 重要申明:以下皆為本人自己製作檔案與模擬測試,皆無使用任何諮商紀錄!
35+
>
36+
37+
### 一、安裝 Python
38+
1.前往 Python 官網:https://www.python.org/downloads/
39+
2.點選Or get the standalone installer for Python XXX(最新版本),即開始下載Python
40+
3.下載完後,開始執行安裝檔。在安裝第一個畫面的最下方,**必須勾選**
41+
42+
43+
☑ Add python.exe to PATH
44+
45+
4.驗證安裝是否成功:Window系統開啟「命令提示字元」或「終端機」(可直接在電腦搜尋),執行:`python --version`
46+
47+
應該顯示類似:`Python xxx`(版本號碼)或是他是空白的,都代表安裝成功。
48+
49+
### 二、安裝 Python 套件
50+
51+
1.在命令提示字元或終端機輸入:
52+
53+
python -m pip install --upgrade pip
54+
python -m pip install PyPDF2 reportlab pillow
55+
56+
2.驗證安裝,並確認清單包含:PyPDF2、reportlab、pillow
57+
58+
python -m pip list
59+
60+
61+
![](/img/blog/pdf02.png)
62+
63+
### 三、準備工作環境
64+
65+
1. 建立資料夾結構:(可以改成自己習慣或編排的模式)
66+
67+
```python
68+
📁 實作程式/
69+
📄 pdf_signature.py ← 程式檔案
70+
🖼️ 簽名01.png ← 簽名圖片(PNG格式,建議背景透明)
71+
📁 原始PDF資料夾/ ← 放入要處理的PDF
72+
📄 記錄001.pdf
73+
📄 記錄002.pdf
74+
📄 記錄003.pdf
75+
...
76+
📁 已簽名PDF
77+
```
78+
79+
2. 打開程式編輯器(推薦使用:[VS Code](https://code.visualstudio.com/)、[notepad++](https://notepad-plus-plus.org/downloads/)),並將以下程式碼貼上(詳細要修改程式碼內容可以參見底下附錄一)
80+
81+
A. 程式結構
82+
83+
```
84+
程式結構:
85+
├── find_signature_page() → 找到「請簽名:」在哪一頁
86+
├── add_signature_to_pdf() → 在PDF上加簽名
87+
├── batch_process_pdfs() → 批次處理多個PDF
88+
└── 主程式 (if __name__ == "__main__") → 程式入口,設定參數
89+
```
90+
91+
B. 完整程式碼
92+
93+
```python
94+
# -*- coding: utf-8 -*-
95+
# PDF 自動簽名程式
96+
# 請先安裝需要的套件: pip install PyPDF2 reportlab pillow
97+
98+
import os
99+
from PyPDF2 import PdfReader, PdfWriter
100+
from reportlab.pdfgen import canvas
101+
from reportlab.lib.pagesizes import letter
102+
from PIL import Image
103+
import io
104+
105+
def find_signature_page(pdf_path, keyword="請簽名:"):
106+
"""尋找包含簽名關鍵字的頁面"""
107+
try:
108+
reader = PdfReader(pdf_path)
109+
for page_num, page in enumerate(reader.pages):
110+
text = page.extract_text()
111+
if keyword in text:
112+
return page_num
113+
return None
114+
except Exception as e:
115+
print(f"讀取 {pdf_path} 時發生錯誤: {e}")
116+
return None
117+
118+
def add_signature_to_pdf(input_pdf, output_pdf, signature_image, x=100, y=100, width=150, height=50):
119+
"""在PDF指定位置加入簽名圖片"""
120+
try:
121+
reader = PdfReader(input_pdf)
122+
writer = PdfWriter()
123+
124+
signature_page_num = find_signature_page(input_pdf)
125+
126+
if signature_page_num is None:
127+
print(f"警告: {input_pdf} 找不到「請簽名:」字樣,跳過此檔案")
128+
return False
129+
130+
packet = io.BytesIO()
131+
can = canvas.Canvas(packet, pagesize=letter)
132+
can.drawImage(signature_image, x, y, width=width, height=height, mask='auto', preserveAspectRatio=True)
133+
can.save()
134+
135+
packet.seek(0)
136+
signature_pdf = PdfReader(packet)
137+
138+
for page_num, page in enumerate(reader.pages):
139+
if page_num == signature_page_num:
140+
page.merge_page(signature_pdf.pages[0])
141+
writer.add_page(page)
142+
143+
with open(output_pdf, 'wb') as output_file:
144+
writer.write(output_file)
145+
146+
print(f"完成: {input_pdf} -> 簽名加在第 {signature_page_num + 1}")
147+
return True
148+
149+
except Exception as e:
150+
print(f"處理 {input_pdf} 時發生錯誤: {e}")
151+
return False
152+
153+
def batch_process_pdfs(input_folder, output_folder, signature_image):
154+
"""批次處理資料夾內所有PDF"""
155+
156+
if not os.path.exists(output_folder):
157+
os.makedirs(output_folder)
158+
159+
pdf_files = [f for f in os.listdir(input_folder) if f.endswith('.pdf')]
160+
161+
if not pdf_files:
162+
print("錯誤: 找不到任何PDF檔案")
163+
return
164+
165+
print(f"找到 {len(pdf_files)} 個PDF檔案")
166+
print("開始處理...")
167+
print("")
168+
169+
success_count = 0
170+
fail_count = 0
171+
172+
for pdf_file in pdf_files:
173+
input_path = os.path.join(input_folder, pdf_file)
174+
output_path = os.path.join(output_folder, f"已簽名_{pdf_file}")
175+
176+
if add_signature_to_pdf(input_path, output_path, signature_image):
177+
success_count += 1
178+
else:
179+
fail_count += 1
180+
181+
print("")
182+
print("處理完成!")
183+
print(f"成功: {success_count} 個檔案")
184+
print(f"失敗: {fail_count} 個檔案")
185+
186+
if __name__ == "__main__":
187+
# ===== 設定參數(可依需求修改)=====
188+
INPUT_FOLDER = "原始PDF資料夾" # 原始PDF所在資料夾
189+
OUTPUT_FOLDER = "已簽名PDF" # 輸出資料夾
190+
SIGNATURE_IMAGE = "簽名.png" # 簽名圖片檔名
191+
192+
# 簽名位置與大小(可調整)
193+
SIGNATURE_X = 350 # X座標(左右位置,數字越大越右)
194+
SIGNATURE_Y = 150 # Y座標(上下位置,數字越大越上)
195+
SIGNATURE_WIDTH = 120 # 簽名寬度
196+
SIGNATURE_HEIGHT = 40 # 簽名高度
197+
198+
print("PDF 自動簽名程式")
199+
print("=" * 50)
200+
201+
# 檢查簽名圖片
202+
if not os.path.exists(SIGNATURE_IMAGE):
203+
print(f"錯誤: 找不到簽名圖片 {SIGNATURE_IMAGE}")
204+
print("請確保簽名圖片與程式在同一個資料夾")
205+
input("按 Enter 鍵結束...")
206+
exit()
207+
208+
# 檢查輸入資料夾
209+
if not os.path.exists(INPUT_FOLDER):
210+
print(f"錯誤: 找不到資料夾 {INPUT_FOLDER}")
211+
print("請建立資料夾並放入要處理的PDF檔案")
212+
input("按 Enter 鍵結束...")
213+
exit()
214+
215+
# 執行批次處理
216+
batch_process_pdfs(INPUT_FOLDER, OUTPUT_FOLDER, SIGNATURE_IMAGE)
217+
218+
print("")
219+
input("按 Enter 鍵結束...")
220+
```
221+
222+
223+
### 四、執行程式
224+
225+
1.開啟命令提示字元或終端機,並切換到工作資料夾(請依實際建立的位置調整路徑),以下範例為存在桌面中有個「實作程式」的資料夾
226+
:::info
227+
▶️知識+:什麼是cd?
228+
229+
**cd****Change Directory** 的縮寫,中文意思是「**切換目錄**」或「**更改資料夾**」。
230+
舉例:當你打開命令提示字元時,通常會看到:`C:\Users\袋鼠>`
231+
232+
這表示您現在「站在」`C:\Users\袋鼠` 這個資料夾裡。
233+
234+
如果不想要那麼麻煩去找他在哪,可以點選資料夾上排,按右鍵「複製位置」即可找到資料夾在那了。
235+
![](/img/blog/pdf03.png)
236+
:::
237+
2.執行程式:`python pdf_signature.py`
238+
![](/img/blog/pdf04.png)
239+
3.完成的檔案呈現
240+
![](/img/blog/pdf05.jpg)
241+
242+
243+
### 附錄一:舉一反三修改程式-簽名位置與簽名關鍵字設定指南
244+
245+
#### (一)如何修改千名關鍵字
246+
247+
1.在程式的第 10 行:
248+
249+
```python
250+
def find_signature_page(pdf_path, keyword="請簽名:"):
251+
```
252+
253+
(1)程式會在PDF中搜尋這個關鍵字
254+
(2)找到關鍵字的那一頁,就是要加簽名的頁面
255+
(3)**無論關鍵字在第1頁、第2頁或任何頁,程式都會自動找到**
256+
257+
2.修改範例:
258+
(1)範例 1:改成「簽章:」
259+
`def find_signature_page(pdf_path, keyword="簽章:"):`
260+
(2)範例 2:改成英文
261+
`def find_signature_page(pdf_path, keyword="Signature:"):`
262+
(3)如果有多種可能的關鍵字-修改程式的第 16 行:
263+
264+
```python
265+
# 原本:
266+
if keyword in text:
267+
268+
# 改成(可接受多種關鍵字):
269+
if keyword in text or "簽章:" in text or "請蓋章:" in text:
270+
```
271+
272+
273+
274+
#### (二)如何調整簽名位置與大小
275+
276+
1.在程式的第 101-104 行:
277+
278+
```python
279+
SIGNATURE_X = 350 # X座標(左右位置)
280+
SIGNATURE_Y = 150 # Y座標(上下位置)
281+
SIGNATURE_WIDTH = 120 # 簽名寬度
282+
SIGNATURE_HEIGHT = 40 # 簽名高度
283+
```
284+
285+
2.PDF 座標系統說明-座標原點在「左下角」
286+
287+
```
288+
PDF頁面示意圖:
289+
290+
Y軸越大越上 ↑
291+
|
292+
(0, 800) | (600, 800) ← 頁面上方
293+
|
294+
|
295+
(0, 400) | (600, 400) ← 頁面中間
296+
|
297+
|
298+
(0, 0) |________→ X軸越大越右
299+
左下角原點 (600, 0)
300+
```
301+
302+
| 參數 | 說明 | 效果 |
303+
| --- | --- | --- |
304+
| **X 增加** | 數字變大 | 簽名往右移 |
305+
| **X 減少** | 數字變小 | 簽名往左移 |
306+
| **Y 增加** | 數字變大 | 簽名往上移 |
307+
| **Y 減少** | 數字變小 | 簽名往下移 |
308+
| **WIDTH 增加** | 寬度變大 | 簽名變寬 |
309+
| **HEIGHT 增加** | 高度變大 | 簽名變高 |
310+
311+
(1)步驟 1:用預設值測試-先用預設值處理 **1個PDF**,看看簽名在哪裡
312+
(2)步驟 2:判斷要往哪個方向調整
313+
314+
| 簽名位置問題 | 調整方法 | 範例 |
315+
| --- | --- | --- |
316+
| 太左邊 | **增加 X** | 350 → 400 |
317+
| 太右邊 | **減少 X** | 350 → 300 |
318+
| 太下面 | **增加 Y** | 150 → 200 |
319+
| 太上面 | **減少 Y** | 150 → 100 |
320+
| 太小 | **增加 WIDTH 和 HEIGHT** | 120 → 150 |
321+
| 太大 | **減少 WIDTH 和 HEIGHT** | 120 → 80 |
322+
323+
(3)步驟 3:每次調整 50 左右-不要一次調太多,建議每次調整 **30-50** 的幅度
324+
325+
## 總結
326+
327+
回頭看這個問題,其實它並不只是「怎麼把簽名加上去」那麼單純,而是反映了許多助人工作現場正在面對的現實:**行政符合規範的壓力,往往會在不知不覺中吞噬大量專業人力**。當制度要求被一條一條補齊時,如果只能依靠人工處理,最終消耗的,往往是工作者本就有限的時間與心力。
328+
329+
這次嘗試用程式解決問題,是希望把那些**可以被自動化的工作交給工具處理**,讓人能夠回到真正需要人去承接的地方。
330+
331+
如果你也正面臨大量文件處理、卻又受限於隱私與合規無法使用雲端服務,或許這個做法能成為一個參考起點。技術不一定要很炫,只要能**實際減輕現場負擔**,它就已經完成了它最重要的任務。
332+

static/img/blog/pdf01.png

406 KB
Loading

static/img/blog/pdf02.png

3.95 KB
Loading

static/img/blog/pdf03.png

18.6 KB
Loading

static/img/blog/pdf04.png

10.2 KB
Loading

static/img/blog/pdf05.jpg

20.6 KB
Loading

0 commit comments

Comments
 (0)