實現pdf電子簽名合成效果-並自動識別簽名位置


 

一. 技術選型

由於要識別簽名位置,所以得要能解析pdf的文本布局,要能得到每個布局元素的文本位置坐標。而最終的簽名需要合成到pdf上,所以還需要有編輯pdf的需求。

 

pdf布局分析:pdfminer.six

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

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

 一個專注於PDF內容解析的包。關於它的布局結構分析模式可以參考下圖,詳情參考 https://pdfminersix.readthedocs.io/en/latest/topic/converting_pdf_to_text.html#topic-pdf-to-text-layout

../_images/layout_analysis_output.png

由於簽名位置的元素一般都是與文本相關的,所以我們只用考慮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文件。

 

 

 

                                                  下載文件查看:

 

 

 

至此,沒有任何法律效應的電子簽名功能完成 ٩(◕‿◕。)۶

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM