pdf-sign-kit
English
A framework-agnostic Python toolkit for stamping signatures and text onto PDF files. It is extracted from the core of a production paperless-approval system and works with plain files — no Django, no database, no network required.
Features
- Image stamps — place any PNG (signature, seal) at a click point.
- Automatic table-cell detection — finds the enclosing cell from a single grayscale raster and scales the stamp proportionally; rotated pages are handled transparently.
- Handwriting mode — loose-fit scaling for handwritten signatures.
- Raster text (600 DPI) — mixed Chinese/Latin text, e.g.
编号 BZ-001, rendered with auto-detected CJK and Latin fonts; supports automatic wrapping. - Built-in stamps — "同意" (agree) and a check mark.
- Background removal — turn near-white backgrounds into transparent PNGs.
- Page preview — render any page to a PIL image / PNG bytes.
- Integrity hashing — SHA-256 / SHA-512 / MD5 digest and verification.
- Workflow rule engine — pure functions deciding who may sign now and whether every participant has finished; supports personal, personal countersign and department countersign levels.
- Configurable signing schemes — define any number of levels, name each one, mark a level as personal / countersign / department countersign; schemes round-trip through JSON, with a built-in 8-level default.
- Signature log tables — render the sign/rejection log as a PNG or a
data:URL, with Chinese keyword extraction from rejection reasons. - Text-anchor placement — locate a stamp position by searching visible
text (
"签字:") instead of table borders; supports "after / below / over" the matched text, for borderless contracts and blank templates. - Seam stamps (骑缝章) — slice one seal into N strips placed on the edges of N consecutive pages; the strips reassemble when pages are fanned.
- Diagonal watermarks — rotated "作废" / "草稿" / "保密" captions, single centered mark or tiled grid, with RGBA opacity control.
- Placement templates — save reusable signature positions as JSON and
instantiate them with a
ref -> imagemapping for batch signing of files sharing one layout. - Bitmap composition — horizontal/vertical concatenation of images with alignment, gaps and proportional scaling.
Installation
pip install pdf-sign-kit
Quickstart
import pdf_sign_kit as psk
# Stamp a signature image at (x, y), editing the file in place.
psk.stamp("form.pdf", "signature.png", x=200, y=627)
# Built-in stamps
psk.stamp_agree("form.pdf", x=200, y=627)
psk.stamp_checkmark("form.pdf", x=200, y=627)
# Mixed Chinese/Latin machine text
psk.stamp_text("form.pdf", "编号 BZ-001", x=200, y=627)
# Make a handwriting scan transparent
img = psk.remove_background("scan.png", threshold=235)
img.save("stamp.png")
# Render a preview / compute integrity hash
preview = psk.render_page("form.pdf", page=0, zoom=3)
digest = psk.hash_file("form.pdf")
Define a signing scheme
from pdf_sign_kit import FlowScheme, Initiator, build_metadata
from pdf_sign_kit import GROUP, DEPARTMENT
# Any number of levels, custom names; level 2 is personal countersign and
# level 3 is department countersign (each department needs one signer).
scheme = FlowScheme.create(
3,
names={1: "起草", 2: "会签", 3: "部门会签"},
modes={2: GROUP, 3: DEPARTMENT},
)
metadata = build_metadata(
scheme,
{
1: [{"id": "A", "name": "甲"}],
2: [{"id": "B"}, {"id": "C"}], # any one signs -> done
3: [
{"id": "D", "group": "D1", "group_name": "技术部"},
{"id": "E", "group": "D2", "group_name": "质保部"},
],
},
initiator=Initiator(id="I", name="initiator"),
)
# Ask the rule engine who may sign / whether the document is complete.
psk.workflow.can_sign(metadata, "A")
psk.workflow.all_completed(metadata)
# Schemes serialize to plain JSON for storage and reloading.
restored = FlowScheme.from_dict(scheme.to_dict())
Text anchor, seam stamp, watermark
# Find visible text and stamp next to it (no table borders needed)
anchor = psk.find_text("contract.pdf", "签字:")
psk.stamp_at_anchor("contract.pdf", "signature.png", anchor)
# Seam stamp across all pages (right edges)
psk.stamp_seam("contract.pdf", "seal.png")
# Diagonal watermark on every page; RGBA color controls opacity
psk.stamp_watermark(
"contract.pdf", "作废",
pages=[0, 1],
color=(220, 38, 38, 90),
tile=True,
)
# Compose a name + date strip before stamping
combined = psk.hconcat([name_img, date_img], gap=8)
Save and reuse placement templates
from pdf_sign_kit import PlacementTemplate
# Capture positions from stamp_batch operations and store as JSON
template = PlacementTemplate.capture(operations, name="Form-A")
psk.save_template("form_a.json", template)
# Later: reuse the same positions on a new file of the same layout
template = psk.load_template("form_a.json")
operations = template.instantiate({"signature": "sig.png", "date": "date.png"})
psk.stamp_batch("another_file.pdf", operations)
Coordinate system
x/yare PDF points (1 pt = 1/72 inch) measured from the page's bottom-left corner in its display orientation.pageindices are zero-based.- Page rotation is handled internally.
Notes & limitations
- These are visual ("electronic") signatures — raster images placed on the page — not PKI/certificate-based ("digital") signatures with legal non-repudiation guarantees.
- Raster text is flattened (not selectable), which matches the print-first quality requirement.
- No fonts are bundled: CJK/Latin fonts are auto-detected on the system; you
may always pass an explicit
font_path. On Debian/Ubuntu:apt-get install fonts-noto-cjk.
License
MIT © 兰衣
中文文档
一个与 Web 框架无关的 Python 工具包,用于在 PDF 文件上加盖签名图章与机打 文字。代码提炼自一套生产环境无纸化审批系统的核心内核,只操作本地文件 ——不依赖 Django、数据库或网络。
功能特性
- 图片盖章:在指定坐标放置任意 PNG(签名、印章)。
- 表格单元格自动检测:通过一次灰度渲染识别点击位置所在的表格格子, 并按格子比例自动缩放;自动处理页面旋转。
- 手写模式:为手写签名提供宽松缩放策略。
- 机打文字(600 DPI):支持中英混排(如
编号 BZ-001),自动匹配中/英 字体,支持自动换行。 - 内置图章:"同意" 章与打勾(check mark)。
- 去背景:将近白背景转为透明 PNG。
- 页面预览:把任意页面渲染为 PIL 图像 / PNG 字节。
- 完整性哈希:支持 SHA-256 / SHA-512 / MD5 计算与校验。
- 签署流程规则引擎:以纯函数判断当前谁可以签、是否全部签署完成,支持 个人签署、个人会签与部门会签。
- 签署等级方案可配置:可自定义任意数量的等级、为每个等级命名,标记某级 为个人签署/会签/部门会签;方案支持 JSON 序列化,并内置一套 8 级默认方案。
- 签字日志表格:将签字/驳回日志渲染为 PNG 或
data:URL,并支持从驳回 原因中提取中文关键词。 - 文本锚点定位:通过搜索可见文字(如「签字:」)确定盖章位置,而非依赖 表格线;支持在匹配文字「其后/其下/覆盖」定位,适用于无表格线的合同与空白 模板。
- 骑缝章:将一枚印章切成 N 条,分别盖在连续 N 页的边缘,展开拼合后还原 完整印章。
- 斜向水印:「作废」「草稿」「保密」等旋转文字,支持单个居中章或整页平铺, RGBA 颜色直接控制透明度。
- 签署位置模板:把可复用的签署位置保存为 JSON,通过「引用名 → 图片」映射 实例化,用于同版式文件的批量签署。
- 位图拼接:多图水平/垂直拼接,支持对齐、间距与等比缩放。
安装
pip install pdf-sign-kit
快速上手
import pdf_sign_kit as psk
# 在 (x, y) 处加盖签名图片,原地修改文件
psk.stamp("表单.pdf", "签名.png", x=200, y=627)
# 内置图章
psk.stamp_agree("表单.pdf", x=200, y=627)
psk.stamp_checkmark("表单.pdf", x=200, y=627)
# 中英混排机打文字
psk.stamp_text("表单.pdf", "编号 BZ-001", x=200, y=627)
# 将手写扫描件去背景
img = psk.remove_background("扫描件.png", threshold=235)
img.save("图章.png")
# 渲染预览图 / 计算完整性哈希
preview = psk.render_page("表单.pdf", page=0, zoom=3)
digest = psk.hash_file("表单.pdf")
定义签署等级方案
from pdf_sign_kit import FlowScheme, Initiator, build_metadata
from pdf_sign_kit import GROUP, DEPARTMENT
# 任意等级数量、自定义名称;第2级为个人会签,第3级为部门会签(每个部门
# 任一人签署即完成该部门)。
scheme = FlowScheme.create(
3,
names={1: "起草", 2: "会签", 3: "部门会签"},
modes={2: GROUP, 3: DEPARTMENT},
)
metadata = build_metadata(
scheme,
{
1: [{"id": "A", "name": "甲"}],
2: [{"id": "B"}, {"id": "C"}], # 任一人签即完成
3: [
{"id": "D", "group": "D1", "group_name": "技术部"},
{"id": "E", "group": "D2", "group_name": "质保部"},
],
},
initiator=Initiator(id="I", name="发起人"),
)
# 由规则引擎判断谁可签 / 文件是否全部完成
psk.workflow.can_sign(metadata, "A")
psk.workflow.all_completed(metadata)
# 方案可序列化为普通 JSON 存储后再恢复
restored = FlowScheme.from_dict(scheme.to_dict())
文本锚点、骑缝章、水印
# 搜索可见文字并在其后盖章(无需表格线)
anchor = psk.find_text("合同.pdf", "签字:")
psk.stamp_at_anchor("合同.pdf", "签名.png", anchor)
# 对所有页加盖骑缝章(右边缘)
psk.stamp_seam("合同.pdf", "印章.png")
# 在指定页加盖斜向水印;RGBA 颜色控制透明度
psk.stamp_watermark(
"合同.pdf", "作废",
pages=[0, 1],
color=(220, 38, 38, 90),
tile=True,
)
# 盖章前先拼接姓名 + 日期
combined = psk.hconcat([name_img, date_img], gap=8)
保存与复用签署位置模板
from pdf_sign_kit import PlacementTemplate
# 从 stamp_batch 操作中提取位置并存为 JSON
template = PlacementTemplate.capture(operations, name="表单A")
psk.save_template("表单_a.json", template)
# 之后在同版式的新文件上复用相同位置
template = psk.load_template("表单_a.json")
operations = template.instantiate({"signature": "签名.png", "date": "日期.png"})
psk.stamp_batch("另一个文件.pdf", operations)
坐标系说明
x/y单位为 PDF 点(1 pt = 1/72 英寸),以页面显示方向的 左下角为原点。page页码从 0 开始。- 页面旋转由库内部处理。
注意与限制
- 本包提供的是可视化("电子")签名——即放置到页面上的图片,而非基于 PKI/证书、具备法律防抵赖能力的"数字签名"。
- 机打文字以栅格方式写入(不可选中复制),以满足高打印质量要求。
- 包不携带字体:会自动探测系统中的中/英字体,也可显式传入
font_path; Debian/Ubuntu 可执行apt-get install fonts-noto-cjk。
许可证
MIT © 兰衣
Metadata
Release files for pdf-sign-kit 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pdf_sign_kit-0.5.0.tar.gz | 49.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pdf_sign_kit-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 96.5 kB
Release files / pdf_sign_kit-0.5.0.tar.gz
| Download URL | pdf_sign_kit-0.5.0.tar.gz |
|---|---|
| Size | 49.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
97c04dfbe54e75e17dea4d182a9944bc7668bad9fb30e88db6423361773df8fa
|
|
BLAKE2b-256 checksum How to use checksums |
6c88234a334d5f38626eadc2605e68397483a5a9d03f4956755c41d206bc772b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / pdf_sign_kit-0.5.0-py3-none-any.whl
| Download URL | pdf_sign_kit-0.5.0-py3-none-any.whl |
|---|---|
| Size | 47.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
26131a4c4bf43836adc9c42e996917f21b130d69597748ddeda2065f25d8466e
|
|
BLAKE2b-256 checksum How to use checksums |
4a9ad29cda0b00030369750ca5849dbcbf5508d87d302f9dbc9b4cb4bcce398b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|