# Java PDF教學
## 前言
Java PDF這個功能有分成付費版、免費版,兩著的差異除了一個要錢、一個不用錢之外,對於工程師來說就是難易度了,付費版幾乎是已經套好,我們只要塞入值就可以、免費版要拼拼湊湊而且可能搞了半天還沒辦法符合需求方的樣子。
話雖如此,但是本文會採用免費的資源來做教學。
## pdfbox 教學
### 前置作業
搜尋 `pdfbox Maven` 加入依賴
網址:https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox
pdfbox Maven
``` xml=
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.5</version>
</dependency>
```
到專案找到pom.xml加入剛剛複製的依賴
pom.xml
``` xml=
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>testPDF</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- PDF -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.5</version>
</dependency>
</dependencies>
</project>
```
### 實作
首先建立一個Java檔,命名為`CreateSimplePdf`
CreateSimplePdf.java
``` java=
package pdf;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
public class CreateSimplePdf {
public static void main(String[] args) throws IOException {
// 建立 PDF 檔
PDDocument document = new PDDocument();
// 建立新的頁面
PDPage page = new PDPage();
document.addPage(page);
// 建立內容
PDPageContentStream contentStream = new PDPageContentStream(document, page);
// 開始繪製內容
contentStream.beginText();
// 設定字體和大小
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), 12);
// 設定文字位置
contentStream.newLineAtOffset(100, 700);
// 寫入文字
contentStream.showText("Hello, World! This is my first PDF with PDFBox.");
// 結束繪製內容
contentStream.endText();
// 關閉建立內容
contentStream.close();
// 儲存 PDF 文件
document.save("C:/Users/User-name/workspace/testPDF/simple.pdf");
// 關閉文件
document.close();
System.out.println("PDF 檔案已成功建立!");
}
}
```
### 結果

## iText 教學
### 前置作業
搜尋 `iText 7 Maven` 加入依賴
網址:https://mvnrepository.com/artifact/com.itextpdf/itext7-core
iText Maven
``` xml=
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.1.16</version>
<type>pom</type>
</dependency>
```
到專案找到pom.xml加入剛剛複製的依賴
pom.xml
``` xml=
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>testPDF</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- PDF -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.1.16</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
```
### 實作
首先建立一個Java檔,命名為`CreateSimplePdf`
CreateSimplePdf.java
``` java=
package pdf;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import java.io.FileNotFoundException;
public class CreateSimplePdf {
public static void main(String[] args) throws FileNotFoundException {
// 設定 PDF 檔案的輸出路徑
String path = "C:/Users/User-name/workspace/testPDF/simple.pdf";
// 建立 PdfWriter 物件
PdfWriter writer = new PdfWriter(path);
// 建立 PdfDocument 物件
PdfDocument pdf = new PdfDocument(writer);
// 建立 Document 物件
Document document = new Document(pdf);
// 加入文字
document.add(new Paragraph("Hello, World! This is my first PDF with iText."));
// 關閉 Document
document.close();
System.out.println("PDF 檔案已成功建立!");
}
}
```
### 結果

## PDFBox實作表格
CreateSimplePdf.java
``` java=
package pdf;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.font.*;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
public class CreateSimplePdf {
public static void main(String[] args) {
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
float fontSize = 12;
float leading = 1.5f * fontSize;
float margin = 50;
float yStart = page.getMediaBox().getHeight() - margin;
float tableWidth = page.getMediaBox().getWidth() - 2 * margin;
float[] columnWidths = { tableWidth * 0.3f, tableWidth * 0.4f, tableWidth * 0.3f };
String[] headers = { "name", "phone", "acount" };
String[][] data = {
{"andy", "123456789", "$1,000"},
{"unan", "987654321", "$2,500"},
};
float yPosition = yStart;
contentStream.setFont(font, fontSize);
drawRow(contentStream, font, fontSize, margin, yPosition, columnWidths, headers);
yPosition -= leading;
for (String[] row : data) {
drawRow(contentStream, font, fontSize, margin, yPosition, columnWidths, row);
yPosition -= leading;
}
contentStream.close();
document.save("C:/Users/User-name/workspace/testPDF/simple.pdf");
System.out.println("PDF 已產生完成。");
} catch (IOException e) {
e.printStackTrace();
}
}
private static void drawRow(PDPageContentStream contentStream, PDFont font, float fontSize,
float startX, float y, float[] columnWidths, String[] cells) throws IOException {
float textX = startX;
for (int i = 0; i < cells.length; i++) {
contentStream.beginText();
contentStream.setFont(font, fontSize);
contentStream.newLineAtOffset(textX + 2, y);
contentStream.showText(cells[i]);
contentStream.endText();
textX += columnWidths[i];
}
}
}
```
### 結果

## 問題來了,無法支援中文,該怎麼辦?
以上都因為沒有出現中文,看似沒有問題的Code,那假設我現在要產一個有中文的PDF會有問題嗎?
答案是:會,因為這接引用的套件根本不支援中文字,所以在編譯器跑的時候就會告訴你錯誤。
那該如何做才能讓我的PDF可以有中文呢?
### 實作
開始前,大家一定要知道自己電腦的字體包在哪
路徑:C:\Windows\Fonts


強制引入設定中文包讓整個專案可以使用。
`String fontPath = "C:/Windows/Fonts/kaiu.ttf";`
備註:為何選用 `kaiu.ttf` 這個字體,是因為我嘗試了很多種 `mingliub.ttc` 、 `mingliu.ttc` 都無法成功,表示有許多字體其實是不支援的,最後使用標楷體就可以了。
CreateChinesePdf.java
``` java=
package pdf;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.*;
import java.io.File;
import java.io.IOException;
public class CreateChinesePdf {
public static void main(String[] args) {
String outputPath = "C:/Users/User-Name/workspace/testPDF/test.pdf";
String fontPath = "C:/Windows/Fonts/kaiu.ttf";
String[] headers = {"姓名", "電話", "金額"};
String[][] data = {
{"王小明", "123456789", "$1,000"},
{"陳月霞", "987654321", "$2,500"},
};
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
PDFont font = PDType0Font.load(document, new File(fontPath));
float fontSize = 12;
float rowHeight = 1.5f * fontSize;
float margin = 50;
float yStart = page.getMediaBox().getHeight() - margin;
float tableWidth = page.getMediaBox().getWidth() - 2 * margin;
float[] colWidths = {tableWidth * 0.3f, tableWidth * 0.4f, tableWidth * 0.3f};
try (PDPageContentStream cs = new PDPageContentStream(document, page)) {
cs.setFont(font, fontSize);
float y = yStart;
y = drawRow(cs, font, fontSize, margin, y, colWidths, headers, rowHeight);
for (String[] row : data) {
y = drawRow(cs, font, fontSize, margin, y, colWidths, row, rowHeight);
}
}
document.save(outputPath);
System.out.println("建立完成");
} catch (IOException e) {
e.printStackTrace();
}
}
private static float drawRow(PDPageContentStream cs, PDFont font, float fontSize,
float startX, float y, float[] colWidths, String[] cells, float rowHeight) throws IOException {
float x = startX;
for (int i = 0; i < cells.length; i++) {
float w = colWidths[i];
// 畫格線
cs.addRect(x, y - rowHeight, w, rowHeight);
cs.stroke();
// 畫文字
cs.beginText();
cs.newLineAtOffset(x + 2, y - fontSize);
cs.showText(cells[i]);
cs.endText();
x += w;
}
return y - rowHeight;
}
}
```
### 結果
