一. 技术选型

由于要识别签名位置,所以得要能解析pdf的文本布局,要能得到每个布局元素的文本位置坐标。而最终的签名需要合成到pdf上,所以还需要有编辑pdf的需求。

pdf布局分析:pdfminer.six

github:https://github.com/pdfminer/pdfminer.six

官网:https://pdfminersix.readthedocs.io/en/latest

关于go的pdf解析库,大多都只是提取纯文本,解析不了布局。而能满足要求的 unidoc/unipdf 库,需要收费且费用昂贵。于是把目光投向了生态丰富的python,果不其然,找到了pdfminer.six , 一个专注于PDF内容解析的包。关于它的布局结构分析模式可以参考下图,详情参考 https://pdfminersix.readthedocs.io/en/latest/topic/converting_pdf_to_text.html#topic-pdf-to-text-layout

由于签名位置的元素一般都是与文本相关的,所以我们只用考虑LTPage的LTTextBox分支。

pdf编辑pdfcpu

github:https://github.com/pdfcpu/pdfcpu

官网:https://pdfcpu.io/

一个强大的PDF 处理库,功能很全面,我们只需要用到 Stamp 功能

二. 识别签名位置

既然要识别签名位置,那么首先得让程序有一个判断依据,来确定某个位置是否需要签名。而文档签名位置的左方都会有 签名提示文本 ,它的格式通常为”XXX签字:“,所以可以用 签名提示文本 的格式作为判断依据。

由于签名提示文本普遍都是单行,所以在 pdfminer.six 解析的布局结构中,对所有的LTTextLine中的文本进行格式正则匹配,就能得到文档中所有的 签名提示文本 四个角的坐标点。而签名位置只需要知道左上角坐标即可(对应 签名提示文本 右上角坐标)。解析demo如下:

点击查看代码

from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTTextBoxHorizontal, LTTextLineHorizontal
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
import re match_text = ".+签字|名[::]$" # 签名提示文本格式 def pdfSearchSignLocation(pdfpath, passwd=""):
praser = PDFParser(open(pdfpath, 'rb'))
doc = PDFDocument(praser, passwd) # 检测文档是否支持提取
if not doc.is_extractable:
print("non-supported")
return # 创建资源管理器
rsrcmgr = PDFResourceManager() # 创建页面聚合器
laparams = {} # 布局分析参数,具体参考https://pdfminersix.readthedocs.io/en/latest/reference/composable.html#laparams
device = PDFPageAggregator(rsrcmgr, laparams=LAParams(**laparams)) # 生成页面解释对象
interpreter = PDFPageInterpreter(rsrcmgr, device) cnt = 0
# 获取page内容列表
for page in PDFPage.create_pages(doc):
interpreter.process_page(page)
# 获取该页的LTPage对象
lt_page = device.get_result() # 循环布局结构
for lt_tbox in lt_page:
if not isinstance(lt_tbox, LTTextBoxHorizontal):
continue for line in lt_tbox._objs:
if not isinstance(line, LTTextLineHorizontal):
continue # 获取行文本
line_text = line.get_text().strip() # 匹配签名提示文本
result = re.search(match_text, line_text)
if result:
cnt += 1
print("签名{} 第{}页 左下点、右上点坐标:({line.x0},{line.y0})、({line.x1},{line.y1})".format(cnt, lt_page.pageid, line=line)) if __name__ == "__main__":
pdfSearchSignLocation("tt10.pdf")

三. pdf签名图片合成

使用 pdfcpu 的 Stamp add 命令(详情参考https://pdfcpu.io/core/stamp):

pdfcpu stamp add -p 页数 -m image "签名图片路径" "详细配置" pdf文件输入路径 pdf文件输出路径

需要设置的详细配置有四个:

1. position(坐标原点位置)

应与 pdfminer.six 统一,为 “bl“(左下角)

2. rot(旋转角度)

本是不需要设置的,文档说明中默认也为0,但实际测试默认会逆时针旋转45度(pdfcpu可能认为你进行的是类似加水印的操作),所以主动设置为0即可

3. offset(坐标偏移)

即签名图片的定点坐标(当position位于左下角时,图片定点位于自身左下角),对应 签名提示文本 右下角

4. scalef(缩放比例)

一般来说,线下签字时,签字的文字大小与文档中不会相差太大,但线上签名时,我们通过用户书写的画布获取到的签名图片,与文档文字大小相差甚大,所以需要进行缩放处理。

      • 缩放比例可以通过 文档文字大小 / 签名图片高度 得出
      • 文档文字大小 可以通过 签名提示文本 布局的两个对角点坐标 的Y轴差值得出
      • 签名图片高度 顾名思义,值得一提的是,最好将签名图片四周的空白区域剪裁掉

最终命令如下:

pdfcpu stamp add -p 页数 -m image "签名图片路径" "position:bl, rot:0, offset:偏移x 偏移y, scalef:缩放比例 abs" pdf文件输入路径 pdf文件输出路径

四. Demo演示

demo地址:http://175.24.203.88:9001/

首先需要上传一个pdf文本文件(或直接使用准备好的demo文件),上传完成后自动进入签名界面,左方是当前预览的pdf,右方是识别出来的需要签名信息的列表。点击签名信息可在跳转至对应签名处,点击签名按钮可以进行签名操作。签名提交后,左方预览会加载出合成签名后的pdf,可以点击下载按钮下载当前的预览的pdf文件。

                                                                           

至此,没有任何法律效应的电子签名功能完成 ٩(◕‿◕。)۶

go实现pdf电子签名-自动识别签名位置的更多相关文章

  1. 如何让Adobe reader 记住上次pdf文档打开位置?

    菜单栏: Edit --> Preferences --> Documents --> 勾选 “Restore last view settings where reopening ...

  2. 验证pdf文件的电子章签名

    pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  3. 如何设置PDF签名文档,PDF签名文档怎么编辑

    在工作中我们都会遇到有文件需要签名的时候,如果是在身边就直接拿笔来签名了,那么如果没有在身边又是电子文件需要签名的时候应该怎么办呢,这个时候就应该设置一个电子的签名文档,其他的文件电子文件签名很简单, ...

  4. 怎么保护PDF文档和扫描文件里的机密信息

    从事商务工作的人,必然要处理带有机密信息的文档,需要分享这些文档的时候,如何谨慎小心地对待那些机密信息,说到底还是取决于自己.分享文档的目的不同,对文档的保护类型和级别也不一样.例如,只有授权的读者才 ...

  5. PDF数据提取------3.解析Demo

    1.PDF中文本字符串格式中关键值信息抓取(已完成) 简介:这种解析比较传统最简单主要熟练使用Regular Expression做语义识别和验证.例如抓取下面红色圈内关键信息 string mett ...

  6. PDF数据防扩散系统方案

    在企业信息化过程中.大量的企业重要图纸和资料都是以电子文件的方式存在.为了避免内部关键数据的外泄,採取了多种方式:设计部门的门禁管制.防火墙.禁止计算机的USB接口等等. 可是泄密问题还是时有发生,原 ...

  7. H5拖拽 构造拖拽及缩放 pdf展示

    前言: 协助项目需要实现一个签名的功能. 功能说明:1.有文本签名和头像签名.2.头像签名需要实现可拖拽功能.3.需要展示的是pdf的文件并需要获取签名位于pdf文件的相对位置. 功能一:实现拖拽 思 ...

  8. itext实现pdf自动定位合同签订

    需求 需要实现如下效果(最终效果) 思考 需求方的要求就是实现签订合同,实现方法不限,但过程中又提出需要在签章的过程中把签订日期的文字也打上去,这就有点坑了~ 一开始的想法是想办法定位需要签名的位置, ...

  9. H5拖拽 构造拖拽及缩放 pdf文件转换为html预览

    前言: 协助项目需要实现一个签名的功能. 功能说明:1.有文本签名和头像签名.2.头像签名需要实现可拖拽功能.3.需要展示的是pdf的文件并需要获取签名位于pdf文件的相对位置. 功能一:实现拖拽 思 ...

随机推荐

  1. 我的获奖记录及 Important Dates in OI

    逊逊的获奖记录/ruo(真的没拿过啥奖,并且大部分都集中在初三阶段,即 2020-2021 赛季): NOIP2018 pj,1=,无游记 CSP-S2019,1=,无游记 APIO2020,Ag,游 ...

  2. NOIP2020 自爆记

    Day -4 - 2459184 本学期第 14 周终于到来了,NOIP 只剩 5 周了. djq 进国集了,先以膜为敬. 晚上上 hb,hb 让我们记了几点要求: 认真读题,要一字一句读题,包括输入 ...

  3. Codeforces 700D - Huffman Coding on Segment(莫队+根分)

    Codeforces 题目传送门 & 洛谷题目传送门 好家伙,刚拿到此题时我连啥是 huffman 编码都不知道 一种对 \(k\) 个字符进行的 huffman 编码的方案可以看作一个由 \ ...

  4. Codeforces 536D - Tavas in Kansas(dp)

    Codeforces 题目传送门 & 洛谷题目传送门 其实这题本该 2019 年 12 月就 AC 的(详情请见 ycx 发此题题解的时间),然鹅鸽到了现在-- 首先以 \(s,t\) 分别为 ...

  5. Peaks Gym 100365H

    Peaks ( Gym 100365H ) 这题nk做法还挺正常的..后面那个循环就很恶心了 考虑 dp[i][j] 表示长度为i的排列,恰好有k个峰的方案数量. 然后转移就是把 i 插入 i-1 的 ...

  6. 【samtools】运行报错: error while loading shared libraries:libcrypto.so.1.0.0或libncurses.so.5或libtinfow.so.5

    samtools用conda安装后,总是出现共享库缺失的报错.即便你刚安装samtools时可以用,但后面在同一环境中安装其他相关软件,有可能产生了冲突,导致库替换,因而报错. 避免这种情况,可能最好 ...

  7. C++异常处理(try、catch、throw)

    本文为转载 博主原文连接 我们通常希望自己编写的程序能够在异常的情况下也能作出相应的处理,而不至于程序莫名其妙地中断或者中止运行了.在设计程序时应充分考虑各种异常情况,并加以处理. 在C++中,一个函 ...

  8. Oracle—网络配置文件

    Oracle网络配置文件详解     三个配置文件 listener.ora.sqlnet.ora.tnsnames.ora ,都是放在$ORACLE_HOME/network/admin目录下. 1 ...

  9. 面试 Java 后端开发的感受

    上周,密集面试了若干位Java后端候选人,工作经验在3到5年间.我的标准其实不复杂(适用90%小小小公司,BAT等自动忽略): 第一能干活,第二Java基础要好,第三最好熟悉些分布式框架.我相信其它公 ...

  10. Linux基础命令---slabtop

    slabtop slabtop实时显示详细的内核板条缓存信息.它显示按所列排序条件之一排序的顶级缓存的列表.它还会显示一个统计信息头,其中填充了板坯层信息. 此命令的适用范围:RedHat.RHEL. ...