Java 實現給pdf文件指定位置蓋章功能

Java 實現給pdf文件指定位置蓋章功能

開發中遇到一個需求, 需要給用戶上傳的的pdf文件, 指定位置上蓋公章的功能, 經過調研和對比, 最終確定實現思路.

這里是使用pdf文件中的關鍵字進行章子的定位, 之所以這樣考慮是因為如果直接寫死坐標的話, 可能會出現因pdf大小, 縮放, 蓋章位置變更的原因, 導致公章位置錯位. 所以選擇了根據關鍵字定位的方式.

下面列出具體的實現方式:

  1. 使用的是Java語言, 使用Maven管理依賴, 下面是操作pdf所依賴的庫的坐標

    <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.12</version>
    </dependency>
    <dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version>
    </dependency>
    
  2. 下面是具體的代碼邏輯

    • CustomRenderListener, 自定義渲染監聽器, 實現查找關鍵字自有邏輯

      import com.itextpdf.awt.geom.Rectangle2D.Float;
      import com.itextpdf.text.pdf.parser.ImageRenderInfo;
      import com.itextpdf.text.pdf.parser.RenderListener;
      import com.itextpdf.text.pdf.parser.TextRenderInfo;
      import lombok.Data;/*** pdf關鍵詞幫助類** @author wdhcr*/
      @Data
      public class CustomRenderListener implements RenderListener {// 坐標private float[] coordinate = null;// 關鍵字private String keyWord;// pdf當前頁private int page;@Overridepublic void beginTextBlock() {}@Overridepublic void endTextBlock() {}@Overridepublic void renderImage(ImageRenderInfo arg0) {}@Overridepublic void renderText(TextRenderInfo textRenderInfo) {String text = textRenderInfo.getText();if (null != text && text.contains(keyWord)) {Float boundingRange = textRenderInfo.getBaseline().getBoundingRectange();coordinate = new float[3];coordinate[0] = boundingRange.x;coordinate[1] = boundingRange.y;coordinate[2] = page;}}
      }
      
    • 獲取關鍵字坐標的工具類

      import com.itextpdf.text.Image;
      import com.itextpdf.text.pdf.PdfContentByte;
      import com.itextpdf.text.pdf.PdfGState;
      import com.itextpdf.text.pdf.PdfReader;
      import com.itextpdf.text.pdf.PdfStamper;
      import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
      import com.jkwl.common.exception.BaseException;
      import lombok.SneakyThrows;
      import lombok.extern.slf4j.Slf4j;import java.io.*;/*** Pdf定位工具類* @author wdhcr*/
      @Slf4j
      public class PdfUtils {/*** 獲取關鍵字所在PDF坐標** @param pdfReader 流* @param keyWords  關鍵詞* @return float[] 坐標*/public static float[] getKeyWords(PdfReader pdfReader, String keyWords) {float[] coordinate = null;int page = 0;try {int pageNum = pdfReader.getNumberOfPages();PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);CustomRenderListener renderListener = new CustomRenderListener();renderListener.setKeyWord(keyWords);for (page = 1; page <= pageNum; page++) {renderListener.setPage(page);pdfReaderContentParser.processContent(page, renderListener);coordinate = renderListener.getCoordinate();if (coordinate != null) {break;}}} catch (IOException e) {e.printStackTrace();}return coordinate;}@SneakyThrowspublic static void stampToPdf(InputStream pdfInputStream, String keyWords, InputStream sealInputStream, OutputStream outputStream) {byte[] sealBytes = sealInputStream.readAllBytes();PdfReader reader = new PdfReader(pdfInputStream);float[] xyz = PdfUtils.getKeyWords(reader, keyWords);if (xyz == null) {throw new BaseException("未找到蓋章位置");}PdfStamper stamper = new PdfStamper(reader, outputStream);// 將印章圖片放在pdf文件的第?頁PdfContentByte over = stamper.getOverContent((int) xyz[2]);// 需要插入的圖片Image contractSealImg = Image.getInstance(sealBytes);// 保存狀態over.saveState();// 圖片處理PdfGState pdfGState = new PdfGState();// 給圖片設置透明度,一般不需要pdfGState.setFillOpacity(0.8F);over.setGState(pdfGState);contractSealImg.setAbsolutePosition(xyz[0] + 50, xyz[1] - 40);// 設置圖片大小contractSealImg.scaleAbsolute(100, 100);// 將圖片添加到pdf文件over.addImage(contractSealImg);over.restoreState();stamper.setFormFlattening(true);// 關閉流stamper.close();reader.close();}}
      
    • 測試demo

          @SneakyThrowspublic static void main(String[] args) {FileInputStream pdfInputStream = new FileInputStream("/Users/Desktop/報告模版.pdf");FileInputStream sealInputStream = new FileInputStream("/Users/Desktop/dbd.png");FileOutputStream fileOutputStream = new FileOutputStream("/Users/Desktop/報告模版蓋章.pdf");// 關鍵字為: 簽發日期PdfUtils.stampToPdf(pdfInputStream, "簽發日期", sealInputStream, fileOutputStream);fileOutputStream.close();pdfInputStream.close();sealInputStream.close();System.out.println("蓋章完成");}
      
    • 公章如圖所示

      seal

    • 報告模版如下:

      image-20241211145537180

    • 蓋完章后

      image-20241211145618814

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

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

相關文章

ASP.NET Core API + MySql

環境 數據庫&#xff1a; mysql8.0 后端&#xff1a; vs2022 ASP.NET Core API .net 8 前端&#xff1a; Hbuilderx bootstrap 5.3.0 jquery v3.7.1 bootstrap-table 1.23.5 創建項目 添加資源包 AutoMapper Microsoft.EntityFrameworkCore.Tools 8.0.0 Pomelo.EntityFramew…

RFDiffusion 計算鍵角函數get_ang解讀

get_ang 函數&#xff08;kinematics.py包中&#xff09;計算三組原子 a,b,c 所形成的平面角&#xff08;planar angle&#xff09;&#xff0c;即 b 為頂點&#xff0c; a,b,c 所確定的角度。 源代碼&#xff1a; def get_ang(a, b, c):"""calculate planar …

Bananna Pi開源社區聯合矽昌通信打造開源的低成本Wifi5路由器

香蕉派 BPI-Wifi5 路由器采用矽昌SF19A2890S2芯片方案設計。它是一款高性能無線路由器&#xff0c;適用于小微企業、家庭和其他網絡環境。Banana Pi開源社區提供整體解決方案。所有代碼開源&#xff0c;用戶可以在上面自由開發自己的應用。 Banana Pi wifi5 路由器github代碼: …

圖像融合算法筆記2024 CDTNet

目錄 ControlCom-Image-Composition CDTNet-High-Resolution-Image-Harmonization 依賴項: trilinear 推理代碼ok: ControlCom-Image-Composition diffusesion https://github.com/bcmi/ControlCom-Image-Composition CDTNet-High-Resolution-Image-Harmonization

item2 for macos

安裝Item2 brew install iterm2 查看終端類型 cat /etc/shells Mac OS X 10.15 已經將默認的shell從Bash換成了zsh&#xff0c;所以不用安裝&#xff0c;10.15以前的可以使用下面的命令進行安裝 brew install zsh 安裝Oh My ZSH # curl sh -c "$(curl -fsSL https://ra…

https證書生成、linux 生成https證書、nginx 配置https證書

1. 檢查 Certbot 是否已安裝 which certbot 2. 安裝 Certbot 2.1啟用 EPEL 倉庫&#xff08;如果尚未啟用&#xff09;&#xff1a; sudo yum install epel-release 2.2 安裝 Certbot 和 Nginx 插件&#xff1a; sudo yum install certbot python3-certbot-nginx 2.3驗證安…

Pytest-Bdd-Playwright 系列教程(14):Docstring 參數

Pytest-Bdd-Playwright 系列教程&#xff08;14&#xff09;&#xff1a;Docstring 參數 前言一、什么是docstring?二、基本語法三、主要特點四、實際例子五、注意事項六、使用建議總結 前言 在自動化測試的過程中&#xff0c;我們經常需要處理復雜的測試數據或需要輸入多行文…

手機租賃系統開發指南一站式服務流程解析

內容概要 手機租賃系統的開發是一個復雜但有趣的過程&#xff0c;像搭建樂高一樣&#xff0c;只要找到合適的模塊&#xff0c;就能打造出一個賓至如歸的租賃平臺。在這部分&#xff0c;我們將對開發流程的整體結構進行簡要概述&#xff0c;并指出每個環節的重要性。 首先&…

OpenAI 正式賦予 ChatGPT 通過視頻實時與用戶互動的能力

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

深入了解C++中const的用法

文章目錄 一、C中的const如何理解&#xff1f;二、C中的const與C語言中的const有何區別&#xff1f;三、const與指針、引用的結合使用 一、C中的const如何理解&#xff1f; 在C中&#xff0c;const是一個關鍵字&#xff0c;用來表示常量性&#xff0c;意在告訴編譯器某些變量或…

EasyExcel設置表頭上面的那種大標題(前端傳遞來的大標題)

1、首先得先引用easyExcel的版本依賴&#xff0c;我那 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version> </dependency> 2、然后得弄直接的實體類&#xff0c;&…

純血鴻蒙崛起,原生Android挑戰?兩大操作系統巔峰對決,智能設備未來誰主沉浮?

鴻蒙HarmonyOS和原生Android系統雖然在一些方面相似&#xff0c;但在架構、設計理念、API、開發工具等方面存在一些差異。鴻蒙系統的目標是跨設備、分布式的操作系統&#xff0c;強調多設備協同和資源共享&#xff0c;而Android則主要集中在智能手機和移動設備領域。 下面將從…

計算機網絡:傳輸層、應用層、網絡安全、視頻/音頻/無線網絡、下一代因特網

目錄 &#xff08;五&#xff09;傳輸層 1&#xff0e;傳輸層尋址與端口 2&#xff0e;無連接服務與面向連接服務 3. 傳輸連接的建立與釋放 4. UDP 的優點 5. UDP 和 TCP 報文段報頭格式 6. TCP 的流量控制 7&#xff0e;TCP 的擁塞控制 8. TCP 傳送連接的管理 &#…

【前端開發】HTML+CSS網頁,可以拿來當作業(免費開源)

HTML代碼 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content_lizhongyu"widthdevice-width, initial-scale1.0"><title>小兔鮮兒-新鮮、惠民、快捷<…

CV(4)--邊緣提取和相機模型

前言 僅記錄學習過程&#xff0c;有問題歡迎討論 邊緣提取&#xff08;涉及語義分割&#xff09;&#xff1a; 圖象的邊緣是指圖象局部區域亮度變化顯著的部分,也有正負之分&#xff0c;暗到亮為正 求邊緣的幅度&#xff1a;sobel&#xff0c;Canny算子 圖像分高頻分量和低…

【信息系統項目管理師】高分論文:論信息系統項目的整合管理(陽光信訪工作平臺)

更多內容請見: 備考信息系統項目管理師-專欄介紹和目錄 文章目錄 正文一、明確目標,制定項目章程二、精心規劃,制定項目管理計劃三、細心嚴謹,指導和管理項目執行四、組織學習,管理項目知識五、多措并舉,對項目進行有效的監控六、規范流程,控制項目整體變更七、嚴謹高效…

智能技術引領未來:自動圖像標注的創新應用與發展

&#x1f351;個人主頁&#xff1a;Jupiter. &#x1f680; 所屬專欄&#xff1a;傳知代碼 歡迎大家點贊收藏評論&#x1f60a; 目錄 概述算法原理核心邏輯效果演示使用方式參考文獻 參考文獻&#xff1a;需要本文的詳細復現過程的項目源碼、數據和預訓練好的模型可從該地址處獲…

C語言-排序

常見的排序算法分為以下四種&#xff0c;插入排序&#xff0c;選擇排序&#xff0c;交換排序&#xff0c;歸并排序。 一、插入排序 (一)直接插入排序 直接插入排序&#xff0c;將一段數組看做被分成已排序序列和未排序序列&#xff0c;排序過程是從未排序序列的元素開始&…

【Java筆記】LinkedList 底層結構

一、LinkedList 的全面說明 LinkedList底層實現了雙向鏈表和雙端隊列特點可以添加任意元素(元素可以重復)&#xff0c;包括null線程不安全&#xff0c;沒有實現同步 二、LinkedList 的底層操作機制 三、LinkedList的增刪改查案例 public class LinkedListCRUD { public stati…

網管平臺(基礎篇):路由器的介紹與管理

路由器簡介 路由器&#xff08;Router&#xff09;是一種計算機網絡設備&#xff0c;它的主要作用是將數據通過打包&#xff0c;并按照一定的路徑選擇算法&#xff0c;將網絡傳送至目的地。路由器能夠連接兩個或更多個網絡&#xff0c;并根據信道的情況自動選擇和設定路由&…