概述
在本文中,我們将了解如何使用 Java 編輯PDF 檔案的内容。 首先,我們将添加新内容。 然後,我們将專注于删除或替換一些預先存在的内容。
添加iText7依賴
我們将使用 iText7 庫向 PDF 檔案添加内容。 稍後,我們将使用 pdfSweep 插件來删除或替換内容。
請注意,iText 在 AGPL 下獲得許可,這可能會限制商業應用程式的分發:iText 許可模型。
首先,讓我們将這些依賴項添加到我們的 pom.xml 中:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.3</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>cleanup</artifactId>
<version>3.0.1</version>
</dependency>
檔案處理
讓我們了解使用 iText7 處理 PDF 的步驟:
首先,我們打開一個 PdfReader 來讀取源檔案的内容。 如果在讀取檔案時随時發生錯誤,這将引發 IOException。
然後,我們打開一個 PdfWriter 到目标檔案。 如果此檔案不存在或無法建立,則會引發 FileNotFoundException。
之後,我們将打開一個使用 PdfReader 和 PdfWriter 的 PdfDocument。
最後,關閉 PdfDocument 會同時關閉底層 PdfReader 和 PdfWriter。
讓我們編寫一個 main() 方法來運作我們的整個處理。 為了簡單起見,我們将重新抛出任何可能發生的異常:
public static void main(String[] args) throws IOException {
PdfReader reader = new PdfReader("src/main/resources/a.pdf");
PdfWriter writer = new PdfWriter("src/main/resources/a-modified.pdf");
PdfDocument pdfDocument = new PdfDocument(reader, writer);
addContentToDocument(pdfDocument);
pdfDocument.close();
}
在下一節中,我們将逐漸完成 addContentToDocument() 方法,以便用新内容填充我們的 PDF。 源文檔是一個 PDF 檔案,左上角僅包含文本“你好,小王子”。 目标檔案将由程式建立。
向檔案中添加内容
我們現在将向檔案添加各種類型的内容。
- 添加表單
我們将從向檔案中添加一個表單開始。 我們的表單将非常簡單,并包含一個名為 name 的唯一字段。
此外,我們需要告訴 iText 在哪裡放置該字段。 在這種情況下,我們将把它放在以下點:(35,400)。 坐标 (0,0) 指的是文檔的左下角。 最後,我們将字段的尺寸設定為 100×30:
private static void addContentToDocument(PdfDocument pdfDocument) throws IOException {
//添加表單
PdfFormField personal = PdfFormField.createEmptyField(pdfDocument);
personal.setFieldName("information");
PdfTextFormField name = PdfFormField.createText(pdfDocument,
new Rectangle(35, 400, 100, 30),
"name", "");
personal.addKid(name);
PdfAcroForm.getAcroForm(pdfDocument, true)
.addField(personal, pdfDocument.getFirstPage());
}
此外,我們明确指定 iText 将表單添加到文檔的第一頁。
- 添加新頁面
現在讓我們看看如何向文檔添加新頁面。 我們将使用 addNewPage() 方法。
如果我們想指定它,這個方法可以接受添加頁面的索引。 例如,我們可以在文檔的開頭添加一個新頁面:
pdfDocument.addNewPage(1);
完整方法如下:
private static void addContentToDocument(PdfDocument pdfDocument) throws IOException {
//添加表單
PdfFormField personal = PdfFormField.createEmptyField(pdfDocument);
personal.setFieldName("information");
PdfTextFormField name = PdfFormField.createText(pdfDocument,
new Rectangle(35, 400, 100, 30),
"name", "");
personal.addKid(name);
PdfAcroForm.getAcroForm(pdfDocument, true)
.addField(personal, pdfDocument.getFirstPage());
//添加空白頁
pdfDocument.addNewPage(1);、
}
- 添加注釋
我們現在要為文檔添加注釋。 具體來說,注釋看起來像一個方形的漫畫氣泡。
我們将把它添加到現在位于文檔第二頁的表單之上。 是以,我們将其放置在坐标 (40,435) 上。 此外,我們會給它一個簡單的名稱和内容。 這些隻會在将滑鼠懸停在注釋上時顯示:
PdfAnnotation ann = new PdfTextAnnotation(
new Rectangle(40, 435, 0, 0))
.setTitle(new PdfString("name"))
.setContents("Your name");
pdfDocument.getPage(2).addAnnotation(ann);
這是我們第二頁中間現在的樣子:
- 添加圖檔
從現在開始,我們将向頁面添加布局元素。 為了做到這一點,我們将無法再直接操作 PdfDocument。 我們甯願從它建立一個文檔并使用它。 此外,我們最終需要關閉文檔。 關閉文檔會自動關閉基礎 PdfDocument,那外層的關閉document就需要注釋。
Document document = new Document(pdfDocument);
//注釋外面的關閉文檔
addContentToDocument(pdfDocument);
//pdfDocument.close();
現在,要添加圖檔,我們需要從它的位置加載它。 我們将使用 ImageDataFactory 類的 create() 方法來執行此操作。 如果無法解析傳遞的檔案 URL,則會引發 MalformedURLException。 在此示例中,我們将使用放置在資源目錄中的 rejoice圖檔:
ImageData imageData = ImageDataFactory.create("src/main/resources/rejoice.png");
下一步是在檔案中設定圖檔的屬性。 我們将其大小設定為 550×100。 我們将把它放在 PDF 的第一頁,在 (10,50) 坐标處。 讓我們看看添加圖檔的代碼:
Image image = new Image(imageData).scaleAbsolute(550,100)
.setFixedPosition(1, 10, 50);
document.add(image);
// 關閉文檔
document.close();
圖像會自動重新縮放到給定的大小。 如下圖所示:
- 添加段落
iText 庫帶來了一些工具來将文本添加到檔案中。 字型可以在片段本身上進行參數化,也可以直接在段落元素上進行參數化。
例如,讓我們在第一頁的頂部添加以下句子:this is a demo from the princess runs to the end。 我們将這句話開頭的字型大小設定為 16,将段落的全局字型大小設定為 8:
注意:隻能用英文,如果想要用中文,需要手動添加字型包,這裡為了友善不做示範
//添加段落
Text title = new Text("this is a demo").setFontSize(16);
Text author = new Text("the princess runs to the end");
Paragraph p = new Paragraph().setFontSize(8)
.add(title)
.add(" from ")
.add(author);
document.add(p);
- 添加表格
最後但并非最不重要的一點是,我們還可以在檔案中添加一個表。 例如,我們将定義一個複式表,其中包含兩個單元格和兩個表頭。 我們不會指定任何位置。 是以它會自然地添加到文檔頂部,就在我們剛剛添加的段落之後:
Table table = new Table(UnitValue.createPercentArray(2));
table.addHeaderCell("name");
table.addHeaderCell("address");
table.addCell("rejoice");
table.addCell("China Company");
document.add(table);
現在讓我們看看文檔第一頁的開頭:
從檔案中删除内容
現在讓我們看看如何從 PDF 檔案中删除内容。 為簡單起見,我們将編寫另一個 test 方法。
我們的源 PDF 檔案将是 a-modified.pdf 檔案,目标将是一個新的 a-cleaned.pdf 檔案。 我們将直接處理 PdfDocument 對象。 從現在開始,我們将使用 iText 的 pdfSweep 插件。
- 從檔案中擦除文本
要從檔案中擦除給定的文本,我們需要定義一個清理政策。 在此示例中,政策将隻是查找與 the 比對的所有文本。 最後一步是調用 PdfCleaner 的 autoSweepCleanUp() 靜态方法。 此方法将建立一個自定義 PdfCleanUpTool,如果在檔案處理期間發生任何錯誤,它将引發 IOException:
@Test
public void testDelContent() throws IOException {
PdfReader reader = new PdfReader(
"src/main/resources/a-modified.pdf");
PdfWriter writer = new PdfWriter(
"src/main/resources/a-cleaned.pdf");
PdfDocument pdfDocument = new PdfDocument(reader, writer);
CompositeCleanupStrategy strategy = new CompositeCleanupStrategy();
strategy.add(new RegexBasedCleanupStrategy("the"));
PdfCleaner.autoSweepCleanUp(pdfDocument, strategy);
pdfDocument.close();
}
如我們所見,源檔案中出現的 the 詞在結果檔案中被黑色矩形覆寫。 例如,此功能适用于資料脫敏:
- 從檔案中擦除其他内容
不幸的是,很難檢測到檔案中的任何非文本内容。 但是,pdfSweep 提供了擦除檔案一部分内容的可能性。 是以,如果我們知道要擦除的内容的位置,我們就可以利用這種可能性。
例如,我們将擦除位于第二頁 (35,400) 的大小為 100×35 的矩形的内容。 這意味着我們将擺脫表單和注釋的所有内容。 下面是執行所有這些操作的代碼:
//擦除非文本内容
List<PdfCleanUpLocation> cleanUpLocations =
Arrays.asList(
new PdfCleanUpLocation(2, new Rectangle(35, 400, 100, 35)));
PdfCleanUpTool cleaner = new PdfCleanUpTool(pdfDocument,
cleanUpLocations, new CleanUpProperties());
cleaner.cleanUp();
如下圖所示,第二頁中的表單被删除了
替換檔案中的内容
在本節中,我們将做與前面相同的工作,隻是我們将用新文本替換以前的文本,而不是隻删除它。
為了更清楚起見,我們将再次使用新的 test() 方法。我們的源檔案将是 a-modified.pdf 檔案。我們的目标檔案将是一個新的 a-fixed.pdf 檔案。
之前我們看到删除的文本被黑色背景覆寫。但是,此顔色是可配置的。由于我們知道檔案中文本的背景是白色的,我們将強制覆寫為白色,與我們之前擦除的方法的類似。
但是,在調用 autoSweepCleanUp() 之後,我們将查詢政策以擷取已擦除代碼的位置。然後,我們将執行個體化一個包含替換文本 abc的 PdfCanvas。此外,我們将删除上邊距以使其與原始文本更好地對齊。預設對齊确實不太好。讓我們看一下生成的代碼:
@Test
public void testReplaceContent() throws IOException {
PdfReader reader = new PdfReader(
"src/main/resources/a-modified.pdf");
PdfWriter writer = new PdfWriter(
"src/main/resources/a-fixed.pdf");
PdfDocument pdfDocument = new PdfDocument(reader, writer);
CompositeCleanupStrategy strategy = new CompositeCleanupStrategy();
strategy.add(new RegexBasedCleanupStrategy("the")
.setRedactionColor(ColorConstants.WHITE));
PdfCleaner.autoSweepCleanUp(pdfDocument, strategy);
for (IPdfTextLocation location : strategy.getResultantLocations()) {
PdfPage page = pdfDocument.getPage(location.getPageNumber() + 1);
PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamAfter(),
page.getResources(), page.getDocument());
Canvas canvas = new Canvas(pdfCanvas, location.getRectangle());
canvas.add(new Paragraph("abc").setFontSize(6)
.setMarginTop(0f));
}
pdfDocument.close();
}
我們可以看一下效果:
結論
在本教程中,我們了解了如何編輯 PDF 檔案的内容。 我們已經看到,我們可以添加新内容、删除現有内容,甚至可以将原始檔案中的文本替換為新内容。