PHP實現PDF自動簽名

技術要點:在PDF中找到一個固定錨點,在需要放置圖片的地方找到測試出錨點對應的XY位

// 使用了poppler方法,其他PDF庫在獲取坐標方面有各種問題,他的安裝是在Linux底層,比在PHP項目中用Composer安裝的庫看上去更穩定,功能更強
// pdftohtml方法需要先將PDF緩存成一個XML文件來進行坐標及其他具體數據的獲取,所以要新建一個$TempPath做為緩存位置可以方便后期統一清理
// $filePath = 'file/SL/06/SL1.01.06.V01_測試'; // PDF文件實際位置
$filePath = 'file/' . input('post.fcate') . '/' . input('post.fcode') . '/' . input('post.fname'); // 自動獲取文件+路徑
$fname = str_replace('.pdf', '', input('post.fname')); // 文件名去掉PDF后綴
$TempPath = 'cache/' . $fname; // PDF文件緩存位置
$fNo = explode('_', $fname);
$fNo = $fNo[0]; // 只取文件名前面的編號// 設置PDF文件路徑
$pdfFilePath = $filePath;
// 執行pdftohtml命令,轉換為HTML并輸出坐標
// -c:保持原始布局
// -hidden:隱藏元素
// -xml:生成 XML 格式的輸出,適合后續解析
// -noimages:不包含圖片
// -stdout:將輸出發送到標準輸出而不是文件
// -xml方法會生成PDF中的圖片,其他不生成圖片的方法會與-xml方法沖突導致無法生成xml文件,所以使用緩存方法統一對xml文件進行處理
$command = "pdftohtml -xml -c -hidden $pdfFilePath $TempPath";
// 在緩存位置自動生成XML文件
exec($command);// 解析生成的XML文件獲取坐標信息
$xml = simplexml_load_file($TempPath . '.xml');
// 輸出坐標信息
//var_dump($xml->page->text);
// 自動計算用值
$left = '4.2';
$top = '4.06';
$signTime = '11';//                             print_r($xml->page->text);
// 獲取所有簽名附近的唯一標識的坐標,通過計算得出簽名和簽名日期真正的坐標
foreach ($xml->page->text as $v) {// 文件編號if (strstr($v, 'Procedure No.')) {$No_L = (float)($v['left'] / $left) + 19.6;$No_T = (float)($v['top'] / $top) - 0.46;// echo 'Procedure No. $No_L = ' . $No_L . ' | $No_T = ' . $No_T . '<br />';} elseif (strstr($v, 'File No.')) {$No_L = (float)($v['left'] / $left) + 11;$No_T = (float)($v['top'] / $top) - 0.46;// echo 'File No. $No_L = ' . $No_L . ' | $No_T = ' . $No_T . '<br />';}// 編輯者簽名if ($v == 'EDITED BY') {$Edit_L = (float)($v['left'] / $left);$Edit_T = (float)($v['top'] / $top);// echo '$Edit_L = ' . $Edit_L . ' | $Edit_T = ' . $Edit_T . '<br />';}// 審批簽名if ($v == 'REVIEWED BY') {$Revi_L = (float)($v['left'] / $left);$Revi_T = (float)($v['top'] / $top);// echo '$Revi_L = ' . $Revi_L . ' | $Revi_T = ' . $Revi_T . '<br />';}// 批準簽名if ($v == 'APPROVED BY') {$Appr_L = (float)($v['left'] / $left);$Appr_T = (float)($v['top'] / $top);// echo '$Appr_L = ' . $Appr_L . ' | $Appr_T = ' . $Appr_T . '<br />';}
}// 創建 TCPDF 和 FPDI 的實例
// 在剛才獲取的坐標中插入對應的簽名及日期
$pdf = new TcpdfFpdi();// 加載現有的 PDF 文件
$file = $pdfFilePath;
$pageCount = $pdf->setSourceFile($file); // 獲取 PDF 文件的頁數// 遍歷每一頁
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {// 導入頁面$templateId = $pdf->importPage($pageNo);// 添加新頁面$pdf->addPage();// 使用導入的頁面$pdf->useTemplate($templateId);// 只修改第一頁if ($pageNo == 1) {// 設置插入圖片的位置和大小$pic1 = 'signature/【pic1】.png';$pic2 = 'signature/【pic2】.png';$pic3 = 'signature/【pic3】.png';$pdf->Image($pic1, $Edit_L, $Edit_T, 16, 9); // Image(簽名地址, X坐標, Y坐標, 寬, 高) 位置插入圖片,寬高為 50$pdf->SetFont('', '', 9); // SetFont(字體, 粗/斜 , 字號)$pdf->Text($Edit_L, $Edit_T + $signTime, date('Y-m-s', input('post.addtime_int'))); // Text(X坐標, Y坐標, 內容)$pdf->Image($pic2, $Revi_L, $Revi_T, 16, 9);$pdf->SetFont('', '', 9);$pdf->Text($Revi_L, $Revi_T + $signTime, date('Y-m-s', input('post.revtime_int')));$pdf->Image($pic3, $Appr_L, $Appr_T, 16, 9);$pdf->SetFont('', '', 9);$pdf->Text($Appr_L, $Appr_T + $signTime, date('Y-m-s'));}$pdf->SetFont('', '', 9);$pdf->Text($No_L, $No_T, $fNo);// $pdf->SetMargins(10, 10, 10); // 設置頁面邊距$pdf->SetDrawColor(255, 255, 255); // 設置邊框顏色為白色// $pdf->SetAutoPageBreak(true, 10); // 自動分頁的底部邊距
}
// 輸出修改后的 PDF 文件 Output實際使用的是fopen()方法,所以要用絕對路徑,不要用相對路徑會報錯
$pdf->Output($_SERVER['DOCUMENT_ROOT'] . '/' . $pdfFilePath, 'F'); // 'I' 為直接輸出到瀏覽器,'F' 為保存文件

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/79993.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/79993.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/79993.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

中達瑞和便攜式高光譜相機:珠寶鑒定領域的“光譜之眼”

在珠寶行業中&#xff0c;真偽鑒定始終是核心需求。隨著合成技術與優化處理手段的日益精進&#xff0c;傳統鑒定方法逐漸面臨挑戰。中達瑞和推出的便攜式高光譜相機&#xff0c;憑借其獨特的“圖譜合一”技術&#xff0c;為珠寶真假鑒定提供了科學、高效且無損的解決方案&#…

2025年滲透測試面試題總結-某戰隊紅隊實習面經(附回答)(題目+回答)

網絡安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 某戰隊紅隊實習面經 個人經歷與技術能力 2. HVV/攻防演練成績 3. 上一個工作主要內容 4. 有意思的邏…

【PostgreSQL數據分析實戰:從數據清洗到可視化全流程】5.1 描述性統計分析(均值/方差/分位數計算)

&#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 文章大綱 5.1 描述性統計分析&#xff1a;均值、方差與分位數計算實戰5.1.1 數據準備與分析目標數據集介紹分析目標 5.1.2 均值計算&#xff1a;從整體到分組分析總體均值計算加權均值…

npm下載插件無法更新package.json和package-lock.json文件的解決辦法

經過多番查證&#xff0c;使用npm config ls查看相關配置等方式&#xff0c;最后發現全局的.npmrc文件的配置多寫了globaltrue&#xff0c;去掉就好了 如果參數很多&#xff0c;不知道是哪個參數引起的&#xff0c;先只保留registryhttp://xxx/&#xff0c;試試下載&#xff0…

基于Anaconda的Pycharm環境配置

一、前提條件&#xff1a; 1、默認已安裝完Anaconda&#xff0c;且創建虛擬環境&#xff0c;參見https://blog.csdn.net/XIAOWEI_JIN/article/details/147657029?spm1001.2014.3001.5501 2、已安裝pycharm&#xff0c;下載鏈接見Pycharm官網&#xff0c;以下以PyCharm 2024.…

Word域操作記錄(從1開始的畢業論文格式排版)

傻逼Word。 寫在最前面 如果你的文章不包括&#xff1a;自動目錄、交叉引用、自動題注。請關閉此頁面。繼續閱讀本文是在浪費您用于跟格式如泥潭里纏斗的時間。 本文內容概述 從指導手冊到畢設初稿 基于多級列表的自動目錄生成方法 正片開始 關于文字 拿到畢設手冊&#…

Linux中的web服務

什么是www www是world wide web的縮寫&#xff0c;及萬維網&#xff0c;也就是全球信息廣播的意思 通常說的上網就是使用www來查詢用戶所需要的信息。 www可以結合文字、圖形、影像以及聲音等多媒體&#xff0c;超鏈接的方式將信息以Internet傳遞到世界各 處去。 當你連接w…

linux -c程序開發

目的是在linux中創建可執行的c語言程序的步驟 和gcc,make和git的簡單運用 建立可執行程序的步驟: -1:預處理: --:頭文件展開;--去掉注釋;--宏替換;--條件編譯 -2:編譯 --:將預處理之后的c語言替換為匯編語言帶阿米 --:語法分析,語義分析,代碼生成 --:檢查語法正確性并且優…

Netty 是一個基于 Java NIO 的高性能網絡通信框架

Netty 是一個基于 Java NIO 的高性能網絡通信框架&#xff0c;廣泛應用于構建分布式系統、RPC 框架、即時通信系統等場景。它的核心設計目標是 異步、非阻塞、高可擴展性&#xff0c;其底層原理涉及 事件驅動模型、線程模型、內存管理 等關鍵技術。以下是 Netty 的核心原理和架…

UI 庫 Ant Design 中的 Table 表格和分頁器:快速實現數據展示和分頁功能

&#x1f90d; 前端開發工程師、技術日更博主、已過CET6 &#x1f368; 阿珊和她的貓_CSDN博客專家、23年度博客之星前端領域TOP1 &#x1f560; 牛客高級專題作者、打造專欄《前端面試必備》 、《2024面試高頻手撕題》、《前端求職突破計劃》 &#x1f35a; 藍橋云課簽約作者、…

Java實現堆排序算法

1. 堆排序原理圖解 堆排序是一種基于二叉堆&#xff08;通常使用最大堆&#xff09;的排序算法。其核心思想是利用堆的性質&#xff08;父節點的值大于或等于子節點的值&#xff09;來高效地進行排序。堆排序分為兩個主要階段&#xff1a;建堆和排序。 堆排序步驟&#xff1a; …

【Hive入門】Hive安全管理與權限控制:審計日志全解析,構建完善的操作追蹤體系

目錄 引言 1 Hive審計日志概述 1.1 審計日志的核心價值 1.2 Hive審計日志類型 2 HiveServer2操作日志配置 2.1 基礎配置方案 2.2 日志格式解析 2.3 日志輪轉配置 3 Metastore審計配置 3.1 Metastore審計啟用 3.2 審計事件類型 4 高級審計方案 4.1 與Apache Ranger…

力扣-hot100 (缺失的第一個正數)

41. 缺失的第一個正數 困難 給你一個未排序的整數數組 nums &#xff0c;請你找出其中沒有出現的最小的正整數。 請你實現時間復雜度為 O(n) 并且只使用常數級別額外空間的解決方案。 示例 1&#xff1a; 輸入&#xff1a;nums [1,2,0] 輸出&#xff1a;3 解釋&#xff…

13前端項目----購物車修改

購物車修改 uuid臨時游客身份購物車部分功能全選修改商品數量修改商品勾選狀態刪除產品 uuid臨時游客身份 請求數據倉庫發起請求 ->問題&#xff1a;獲取不到購物車數據&#xff1f; 所以需要一個身份&#xff0c;告訴服務器是誰存的數據&#xff1f;是要獲取誰的數據&…

Mac電腦,idea突然文件都展示成了文本格式,導致ts,tsx文件都不能正常加載或提示異常,解決方案詳細說明如下

有一天使用clean my mac軟件清理電腦 突然發現idea出現了文件都以文本格式展示&#xff0c;如圖所示 然后就卸載&#xff0c;計劃重新安裝&#xff0c;安裝了好幾個版本&#xff0c;并且setting->file types怎么設置都展示不對&#xff0c;考慮是否idea沒卸載干凈&#xff…

Nginx搭建test服務器

創建test域名 進入阿里云添加解析 創建域名:test.xxxxx.com 服務器復制項目代碼 新建目錄,Git拉取項目代碼,安裝上插件包 修改配置文件,啟動測試服務 修改配置文件“服務器接口” 開啟服務pm2 start app.js --name "test" 表格含義: 列名含義說明id進程在…

MyBatis-Plus 非 Spring 環境使用時 `GenericTypeResolver` 缺失問題總結

MyBatis-Plus 非 Spring 環境使用時 GenericTypeResolver 缺失問題總結 問題描述 在非 Spring 環境中使用 MyBatis-Plus 3.4.3.1 及以上版本時&#xff0c;啟動程序會拋出以下錯誤&#xff1a; Exception in thread "main" java.lang.NoClassDefFoundError: org/s…

綜合案例:使用vuex對購物車的商品數量和價格等公共數據進行狀態管理

文章目錄 0.實現需求1.新建購物車模塊cart2.使用json-server模擬向后端請求數據3.在vuex請求獲取并存入數據,并映射到組件中,在組件中渲染【重點】3.1.安裝axios3.2.準備actions和mutations,獲取和存入數據到vuex中3.3.動態渲染:先用mapState映射list到組件頁面 4.點擊修改數量…

《數據結構初階》【順序表 + 單鏈表 + 雙向鏈表】

《數據結構初階》【順序表 單鏈表 順序表】 前言&#xff1a;先聊些其他的東西&#xff01;&#xff01;&#xff01;什么是線性表&#xff1f;什么是順序表&#xff1f;順序表的種類有哪些&#xff1f; 什么是鏈表&#xff1f;鏈表的種類有哪些&#xff1f; ---------------…

Android Retrofit框架分析(三):自動切換回主線程;bulid的過程;create方法+ServiceMethod源碼了解

目錄 Okhttp有什么不好&#xff1f;bulid的過程create方法ServiceMethodcall enqueue的過程為什么要學習源碼呢&#xff1f; 一、Okhttp有什么不好&#xff1f; Okhttp本身來說&#xff0c;是一個挺好的網絡框架&#xff0c;但&#xff0c;對于開發者而言&#xff0c;使用起…