Itext進行PDF的編輯開發

這周寫了一周的需求,是制作一個PDF生成功能,其中用到了Itext來制作PDF的視覺效果。其中一些功能不是很懂,僅作記錄,若要學習請仔細甄別正確與否。

開始之前,我還是想說,這傻福需求怎么想出來的,讓人手擼PDF,哥們一兩頁PDF寫了快1k行代碼,代碼量大并且感覺極難維護。這次遇見的難點主要有:

1:對于分頁的處理。

這個問題真的困擾了很久,現在也無法良好解決。比如在遇見我寫一個動態表格的時候,發生了分頁,但我一旦分頁我要先添加一些別的表頭信息再繼續我的分頁實現。這個時候我首先想到了用事件監聽之類的,在發生分頁時自動插入某些函數。

注冊事件監聽器:
        pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE,new PageNumberEventHandler(font, boldFont));

具體實現(GPT實現)

 private static class PageNumberEventHandler implements IEventHandler {private final PdfFont font;private final PdfFont boldFont;public PageNumberEventHandler(PdfFont font, PdfFont boldFont) {this.font = font;this.boldFont = boldFont;}@Overridepublic void handleEvent(Event event) {PdfDocumentEvent docEvent = (PdfDocumentEvent) event;PdfDocument pdfDoc = docEvent.getDocument();PdfPage page = docEvent.getPage();int pageNumber = pdfDoc.getPageNumber(page);int totalPages = pdfDoc.getNumberOfPages();// 更新靜態變量InvoiceGenerator.currentPage = pageNumber;InvoiceGenerator.totalPages = totalPages;Rectangle pageSize = page.getPageSize();PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamBefore(),page.getResources(), pdfDoc);// 定義繪制區域(關鍵修正)Rectangle rootArea = new Rectangle(36, 36,pageSize.getWidth() - 72,pageSize.getHeight() - 72);// 創建Canvas對象Canvas canvas = new Canvas(pdfCanvas, rootArea);// 如果是續頁(第2頁及以后),添加續篇表頭if (pageNumber > 1) {try {addContinuationHeader(canvas, font, boldFont, pageNumber);} catch (IOException e) {throw new RuntimeException(e);}}// 添加頁碼(右上角)Paragraph pageInfo = new Paragraph().add(String.format(PAGE_X_OF_Y_TEXT, pageNumber, totalPages)).setFont(font).setFontSize(8).setFixedPosition(pageSize.getRight() - 36,pageSize.getTop() - 20,100).setTextAlignment(TextAlignment.RIGHT);canvas.add(pageInfo);// 添加修訂信息(左下角)Paragraph revInfo = new Paragraph(REV_INFO).setFont(font).setFontSize(7).setFixedPosition(36, 20, 100);canvas.add(revInfo);canvas.close();pdfCanvas.release();}

我后面發現,handler實現出來要寫在一個canvas里面,而我開始是把所有內容繪制在一個document里面的,這就導致我把canvas放在document里面的時候document里面的內容無法正確識別出我加入的canvas,然后形成了內容的疊加。遂放棄了用監聽器。

手動計算分頁

比如計算一頁最多可以放多少數據,然后放了這么多條我就新建一頁

              document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));// 強制分頁

然后繼續在這一頁里面寫。這樣的缺點就是我要計算出準確的能放多少數據,如果數據的變化太多這個方法就不行了。其實后面就遇見了,因為后面插入的每條數據的寬度不一樣。然后我之前想的是。把寬度計算出來,結果我第一頁的寬度計算和后面的不一樣,縷了半小時思路還是有問題。

實際場景是:

插入items里面的每一行數據,按道理來說每一行setbond是(10),但是里面的詳情字段可能會超長,然后導致換行,我這里就把這個item當作了兩行,這樣確實可以做到準確分頁,但是會出現的問題是,如果分頁剛好發生在換行這個item,那么我這個item就應該到下面去,我設定的是第一頁只存12行,存過了就分頁。但這樣如果我第4個item的時候前面已經有10行了,那么我第4行就要超過了,所以第4行就應該放到下一個去。然后當時就是設置了一個總行數totalNum和一個真實到了哪一個item的數量currentNum。第一頁的邏輯就是。總行數totalNum就是每次calculateLineBreaks(commercialInvoiceDto.getItems().get(i).getDescription()
? ? ? ? ? ? ? ? ? ? , font
? ? ? ? ? ? ? ? ? ? , 8
? ? ? ? ? ? ? ? ? ? , 340)得到的行數,這個函數就是計算我這個詳情實際占多少行。

if(i+calculateLineBreaks(commercialInvoiceDto.getItems().get(i).getDescription(), font, 8, 340)<12)

那么在第二頁的邏輯的時候,我就傳一個currentNum去代表這一頁開始遍歷的item的index。這一頁可以存40行數據,那么我每遍歷一個currentNum進去,我的totalNum就加一次calculateLineBreaks,然后如果下一次+calculateLineBreaks會超過40我就提前分頁。這樣我感覺從邏輯上是能行通的。結果后面告訴我不想要這種換行的效果,要采用字體縮放來解決。

字體縮放

結果這才是最痛苦的,本來打算周五可以摸摸魚看看八股,在GPT和百度的掙扎下,最開始老板告訴我有一個自適應縮放的,找了半天沒找到。我就打算采用百度上通過計算我這個字段,計算出他會占多少行,然后按照比例縮小字體大小。結果他的計算方式是大致計算,不能準確的識別出里面的空格,就導致縮放的有可能會不夠小。然后我采用一個處理溢出操作的方法,結果和注釋所說一樣,我的自適應縮放只能縮放到7f大小就不能更小了。

        Paragraph para = new Paragraph(Des).setFont(font).setFontSize(fontSize).setWidth(maxWidth);para.setProperty(Property.OVERFLOW_X, OverflowPropertyValue.FIT);//只能自適應縮放到字體大小大于7f的,看見有什么MIN_FONT_SIZE字段,但我用的7.2.5沒有,我看了好久源碼也沒找到。
2:布局問題
邊框重合

在生成過程中,我發現有的線框會變得很粗,這是因為兩個外邊框的重合會引起變粗的效果。因此可以通過setBorder來操控,比如說和上面的方框重合了,就把上面的setBorderBottom設置為(NO_Border)或者把下面的setBorderTop。

同時注意,外邊框和內部文字的邊框,如果只想呈現一個框框里面只有文字沒有分割線的效果就只在new Table的時候設置邊框,如果文字中間需要分割就在Cell里面設置。

對齊問題

一行有多少內容可以存放是由開始設置的分割布局來決定的,因此如果有兩行內容可以放在一個table里面,但是注意存放的數量。

3:常見概念

(這是在下周一寫的了,哥們明明功能都寫完了,結果組長告訴我周五說我現在用的包不能過甲方審核,heartbreak了。然后后面嘗試用openPdf做,我感覺太麻煩了,剛好老板說不用做了,但是都寫這么多了,再說點我這次 遇見的常用的一些內容吧)

一、表格 (Table) 操作
  1. 表格初始化
    • PdfPTable table = new PdfPTable(3);:創建一個包含 3 列的表格。
    • table.setWidthPercentage(100);:設置表格寬度占頁面寬度的 100%。
    • table.setTotalWidth(new float[]{30, 20, 50});:自定義列寬比例,這里三列的寬度比例分別為 30、20、50。
  2. 表格樣式屬性
    • table.setSpacingBefore(10f);:設置表格上方的間距為 10 個單位。
    • table.setSpacingAfter(10f);:設置表格下方的間距為 10 個單位。
    • table.setLockedWidth(true);:鎖定列寬,防止列寬在后續操作中自動調整。
    • table.getDefaultCell().setBorder(0);:設置表格默認單元格無邊框。
二、單元格 (Cell) 操作
  1. 基礎單元格
    • PdfPCell cell = new PdfPCell(new Paragraph("內容"));:創建一個包含文本內容的單元格。
    • cell.setBackgroundColor(BaseColor.ORANGE);:設置單元格的背景顏色為橙色。
    • cell.setBorderColor(BaseColor.BLUE);:設置單元格的邊框顏色為藍色。
  2. 高級屬性
    • cell.setColspan(2);:使單元格橫向合并 2 列。
    • cell.setRowspan(2);:使單元格縱向合并 2 行。
    • cell.setHorizontalAlignment(Element.ALIGN_CENTER);:設置單元格內容水平居中對齊。
    • cell.setVerticalAlignment(Element.ALIGN_MIDDLE);:設置單元格內容垂直居中對齊。
三、文本與段落
  1. 段落樣式
    • Paragraph p = new Paragraph("文本", FontFactory.getFont("SIMHEI", 12));:創建一個包含文本的段落,并設置中文字體為 “黑體”,字號為 12。
    • p.setAlignment(Element.ALIGN_CENTER);:設置段落內容居中對齊。
    • p.setSpacingBefore(5f);:設置段落前的間距為 5 個單位。
四、圖形與圖像
  1. 插入圖片
    • Image img = Image.getInstance("logo.png");:從指定路徑(這里是 “logo.png”)獲取圖片。
    • PdfPCell imgCell = new PdfPCell(img, true);:創建一個包含圖片的單元格,true表示圖片將被縮放以適應單元格大小。
五、文檔元數據
  1. document.addTitle("標題");:設置文檔的標題。
  2. document.addKeywords("關鍵詞");:添加文檔的關鍵詞。
  3. document.addCreator("創建者");:設置文檔的創建者信息。

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

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

相關文章

android編譯使用共享緩存

注意 服務器端與客戶端系統的版本號需為Ubuntu20.04ccache版本不能低于4.4執行用戶需要為sudo權限服務器端nfs目錄權限必須為nobody:nogroup 一、服務端配置&#xff1a; 在服務器192.168.60.142上配置 NFS 共享 1.安裝 NFS 服務器&#xff1a; 1 sudo apt-get install nfs…

工作中sql總結

sql總結 場景1分組后失敗的成功數據帶入場景2完全性質的一對一匹配場景3虛擬戶的特殊匹配場景4多對多匹配場景5一對一匹配場景6 一對多匹配 場景1分組后失敗的成功數據帶入 現有一批交易表的數據&#xff0c;根據戶名&#xff0c;日期&#xff0c;金額分組&#xff0c;存在TRA…

QML FontDialog:使用FontDialog實現字體選擇功能

目錄 引言相關閱讀FontDialog基本介紹字體屬性 實例演示項目結構代碼實現Main.qmlmain.cpp 代碼解析運行效果 總結 引言 在桌面應用程序開發中&#xff0c;字體選擇是一個常見的需求。Qt Quick提供了FontDialog組件來實現這一功能。本文將介紹如何在Qt Quick應用程序中使用Fon…

MCP(3):在CherryStudio中使用MCPServer

上一文章講述了如何新建一個MCP Server&#xff0c;并在MCP Inspector完成測試。本文講述如何在CherryStudio中進行測試。 Cherry Studio 是一款由 CherryHQ 開發的多模型支持的 AI 桌面助手&#xff0c;兼容 Windows、Linux 和 macOS 系統&#xff0c;旨在為用戶提供更便捷、…

面試題-鏈表(2)

1.合并兩個有序鏈表&#xff1a; 21. 合并兩個有序鏈表 - 力扣&#xff08;LeetCode&#xff09; public ListNode mergeTwoLists(ListNode headA, ListNode headB){ListNode newheadnew ListNode(-1);ListNode curnewhead;while(headA!null&&headB!null){if(headA.va…

微軟Entra新安全功能引發大規模賬戶鎖定事件

誤報觸發大規模鎖定 多家機構的Windows管理員報告稱&#xff0c;微軟Entra ID新推出的"MACE"&#xff08;泄露憑證檢測應用&#xff09;功能在部署過程中產生大量誤報&#xff0c;導致用戶賬戶被大規模鎖定。這些警報和鎖定始于昨夜&#xff0c;部分管理員認為屬于誤…

【MATLAB第117期】#源碼分享 | 基于MATLAB的SSM狀態空間模型多元時間序列預測方法(多輸入單輸出)

【MATLAB第117期】#源碼分享 | 基于MATLAB的SSM狀態空間模型多元時間序列預測方法&#xff08;多輸入單輸出&#xff09; 引言 本文使用狀態空間模型實現失業率遞歸預測&#xff0c;狀態空間模型&#xff08;State Space Model, SSM&#xff09;是一種用于描述動態系統行為的…

谷歌瀏覽器搜索后的頁面總是覆蓋當前頁面

最近將搜索引擎換為谷歌后&#xff0c;發現&#xff0c;每次搜索完的結果頁面總是覆蓋當前頁面&#xff0c;非常不方便&#xff0c;在瀏覽器設置中又找不到類似設置的選項&#xff0c;然后終于在一個博主“如何設置使谷歌瀏覽器打開鏈接自動跳轉到新標簽頁而不是覆蓋當前頁面?…

記錄學習的第三十天

今天終于又開始寫博客了。 還是滑動窗口問題&#xff0c;這段時間不出意外都是這了 上面的思路是我自己做的&#xff0c;但是不知道為什么不行&#xff0c;有沒有大佬能指點一下我。 接下來這道題是進階的。不過我之前的基礎都做的很艱難&#xff0c;道阻且長啊。

QTextDocument 入門

一、QTextDocument QTextDocument 是 Qt 中用于處理富文本文檔的核心類&#xff0c;支持文本格式、圖片、表格等復雜內容。 1. QTextDocument 入門 1.1 基本概念 QTextDocument 是 Qt 中用于處理富文本內容的核心類&#xff0c;它提供了&#xff1a; 結構化文本存儲&#x…

WebRTC服務器Coturn服務器相關測試工具

1、概述 在安裝開源的webrtc服務器coturn服務器后&#xff0c;會附帶安裝coturn的相關工具&#xff0c;主要有以下幾種工具 2、turnadmin工具 說明&#xff1a;服務器命令行工具&#xff0c;提供添加用戶、添加管理員、生成TURN密鑰等功能&#xff0c;turnadmin -h查看詳細用…

如何創建Vue3工程

1.首先下載環境 &#xff08;默認下好了VS code&#xff09; Node.js: Node.js 中文網 — 下載 Node.js 選擇要下載的版本 檢查環境&#xff1a; 在命令行中輸入 node ,檢查版本號 2.創建工程 1.找到自己要創建工程的文件目錄&#xff0c;右鍵打開打開終端 在終端輸入創…

基于大模型的肛裂手術全流程預測與治療方案研究報告

目錄 一、引言 1.1 研究背景與意義 1.2 研究目標與創新點 1.3 研究方法與技術路線 二、肛裂概述與大模型技術原理 2.1 肛裂的醫學定義與分類 2.2 肛裂的發病機制與臨床癥狀 2.3 大模型技術簡介 三、大模型在肛裂術前預測的應用 3.1 術前風險因素分析與數據收集 3.2 …

【趣味小游戲】--掃雷游戲

目錄 一.test.c部分 二.game.h部分 三.game.c部分 前言:前面學習了數組和函數等c語言相關知識&#xff0c;這篇文章我們將通過這些知識分為三個文件來完成掃雷游戲&#xff1b; 1.test.c //文件中寫游戲的測試邏輯 2.game.c //文件中寫游戲中函數的實現等 3.game.h. //文件中寫…

【微服務】SpringBoot制作Docker鏡像接入SkyWalking詳解

目錄 一、前言 二、SkyWalking介紹 2.1 SkyWalking是什么 2.2 SkyWalking核心功能 2.3 SkyWalking整體架構 2.4 SkyWalking主要工作流程 三、前置準備 3.1 搭建SkyWalking服務 3.1.1 下載安裝包 3.1.2 上傳服務器目錄 2.1.3 數據庫持久化配置說明 3.1.4 啟動skywalk…

從零開始構建微博爬蟲與數據分析系統

從零開始構建微博爬蟲與數據分析系統 引言 社交媒體平臺蘊含著海量的信息和數據&#xff0c;通過對這些數據的收集和分析&#xff0c;我們可以挖掘出有價值的見解。本文將詳細介紹如何構建一個完整的微博爬蟲和數據分析系統&#xff0c;從數據爬取、清洗、到多維度分析與可視…

深入探索RAG:用LlamaIndex為大語言模型擴展知識,實現智能檢索增強生成

大型語言模型&#xff08;LLM&#xff09;&#xff0c;如ChatGPT和Llama&#xff0c;在回答問題方面表現出色&#xff0c;但它們的知識僅限于訓練時所獲取的信息。它們無法訪問私有數據&#xff0c;也無法在訓練截止日期之后學習新知識。那么&#xff0c;核心問題就是……我們如…

【延遲雙刪】簡單解析

使用場景&#xff1a;【高并發】情況下的做【更新操作】 什么是延遲雙刪 首次刪除&#xff1a;當需要更新某個數據項時&#xff0c;首先刪除緩存中的該項。 更新數據庫&#xff1a;接著&#xff0c;更新數據庫中的該項。 短暫延遲&#xff1a;然后等待一段很短的時間&#xff…

解決Windows安全中心顯示空白頁面

1、電腦重裝系統后&#xff0c;發現原本一些軟件打不開了&#xff0c;電腦莫名認為有病毒&#xff0c;自動刪除插件。附圖。 2、第一反應是電腦防火墻的原因&#xff0c;默認威脅防護識別到了病毒軟件&#xff0c;自動刪除。在開始屏幕搜Windows安全中心&#xff0c;打開之后發…

【回眸】error: failed to compile `xxxxxx`重裝rust環境

在ubuntu上安裝軟件報錯 error: failed to compile cxx2flow v0.6.2 Caused by: package cargo-platform v0.1.9 cannot be built because it requires rustc 1.78 or newer, while the currently active rustc version is 1.75.0 Try re-running cargo install with --lo…