Java PDF導出工具:自定義表格與圖片插入
下面我將實現一個Java PDF導出工具,支持插入自定義表格和圖片的功能。這個解決方案使用iText 7庫,提供了一個直觀的用戶界面,可以預覽生成的PDF內容。
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;public class PDFExporter extends JFrame {private JTable table;private DefaultTableModel tableModel;private JTextArea previewArea;private List<String> imagePaths = new ArrayList<>();private PdfFont font;private PdfFont titleFont;public PDFExporter() {super("PDF導出工具 - 支持自定義表格與圖片插入");setSize(900, 700);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLocationRelativeTo(null);initFonts();initUI();}private void initFonts() {try {// 創建字體(實際應用中應使用支持中文的字體文件)font = PdfFontFactory.createFont();titleFont = PdfFontFactory.createFont(PdfFontFactory.HELVETICA_BOLD);} catch (Exception e) {e.printStackTrace();font = PdfFontFactory.createFont(PdfFontFactory.COURIER);titleFont = PdfFontFactory.createFont(PdfFontFactory.COURIER_BOLD);}}private void initUI() {// 創建主面板JPanel mainPanel = new JPanel(new BorderLayout(10, 10));mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));// 創建頂部面板JPanel topPanel = new JPanel(new BorderLayout(10, 10));// 表格模型String[] columns = {"書名", "作者", "價格 (¥)", "出版年份", "評分"};tableModel = new DefaultTableModel(columns, 0);table = new JTable(tableModel);table.setRowHeight(30);table.setFont(new Font("微軟雅黑", Font.PLAIN, 14));// 添加示例數據addSampleData();JScrollPane tableScroll = new JScrollPane(table);tableScroll.setBorder(BorderFactory.createTitledBorder("自定義表格數據"));topPanel.add(tableScroll, BorderLayout.CENTER);// 表格操作按鈕JPanel tableButtonPanel = new JPanel(new GridLayout(5, 1, 5, 5));JButton addRowBtn = new JButton("添加行");JButton deleteRowBtn = new JButton("刪除行");JButton addImageBtn = new JButton("添加圖片");JButton previewBtn = new JButton("預覽PDF");JButton exportBtn = new JButton("導出PDF");addRowBtn.addActionListener(e -> tableModel.addRow(new Object[]{"", "", "", "", ""}));deleteRowBtn.addActionListener(e -> {int row = table.getSelectedRow();if (row != -1) {tableModel.removeRow(row);}});addImageBtn.addActionListener(e -> addImage());previewBtn.addActionListener(e -> previewPDF());exportBtn.addActionListener(e -> exportPDF());tableButtonPanel.add(addRowBtn);tableButtonPanel.add(deleteRowBtn);tableButtonPanel.add(addImageBtn);tableButtonPanel.add(previewBtn);tableButtonPanel.add(exportBtn);topPanel.add(tableButtonPanel, BorderLayout.EAST);// 預覽區域previewArea = new JTextArea();previewArea.setFont(new Font("等線", Font.PLAIN, 14));previewArea.setEditable(false);previewArea.setBackground(new Color(240, 240, 240));previewArea.setBorder(BorderFactory.createTitledBorder("PDF預覽內容"));JScrollPane previewScroll = new JScrollPane(previewArea);previewScroll.setPreferredSize(new Dimension(0, 200));// 添加組件到主面板mainPanel.add(topPanel, BorderLayout.CENTER);mainPanel.add(previewScroll, BorderLayout.SOUTH);add(mainPanel);// 狀態欄JLabel statusBar = new JLabel("就緒 | 添加表格數據并插入圖片,然后導出PDF");statusBar.setBorder(BorderFactory.createEtchedBorder());add(statusBar, BorderLayout.SOUTH);updatePreview();}private void addSampleData() {Object[][] data = {{"Java核心技術", "Cay S. Horstmann", "128.50", "2022", "4.8"},{"Effective Java", "Joshua Bloch", "99.80", "2018", "4.9"},{"深入理解Java虛擬機", "周志明", "119.00", "2019", "4.7"},{"Spring實戰", "Craig Walls", "89.90", "2020", "4.6"},{"Python編程:從入門到實踐", "Eric Matthes", "75.00", "2021", "4.7"}};for (Object[] row : data) {tableModel.addRow(row);}}private void addImage() {JFileChooser fileChooser = new JFileChooser();fileChooser.setDialogTitle("選擇要插入的圖片");fileChooser.setMultiSelectionEnabled(true);int result = fileChooser.showOpenDialog(this);if (result == JFileChooser.APPROVE_OPTION) {for (File file : fileChooser.getSelectedFiles()) {imagePaths.add(file.getAbsolutePath());}updatePreview();JOptionPane.showMessageDialog(this, "已添加 " + fileChooser.getSelectedFiles().length + " 張圖片", "添加圖片", JOptionPane.INFORMATION_MESSAGE);}}private void updatePreview() {StringBuilder sb = new StringBuilder();sb.append("PDF 內容預覽:\n");sb.append("----------------------------------------\n");sb.append("標題: 圖書清單報告\n\n");sb.append("表格數據 (").append(tableModel.getRowCount()).append(" 行):\n");for (int col = 0; col < tableModel.getColumnCount(); col++) {sb.append(String.format("%-20s", tableModel.getColumnName(col)));}sb.append("\n");for (int row = 0; row < tableModel.getRowCount(); row++) {for (int col = 0; col < tableModel.getColumnCount(); col++) {Object value = tableModel.getValueAt(row, col);sb.append(String.format("%-20s", value != null ? value.toString() : ""));}sb.append("\n");}sb.append("\n圖片列表 (").append(imagePaths.size()).append(" 張):\n");for (String path : imagePaths) {sb.append("? ").append(new File(path).getName()).append("\n");}previewArea.setText(sb.toString());}private void previewPDF() {try {File tempFile = File.createTempFile("pdf_preview", ".pdf");createPDF(tempFile.getAbsolutePath());if (Desktop.isDesktopSupported()) {Desktop.getDesktop().open(tempFile);} else {JOptionPane.showMessageDialog(this, "PDF預覽已生成: " + tempFile.getAbsolutePath(), "預覽生成成功", JOptionPane.INFORMATION_MESSAGE);}} catch (Exception ex) {ex.printStackTrace();JOptionPane.showMessageDialog(this, "生成預覽時出錯: " + ex.getMessage(), "錯誤", JOptionPane.ERROR_MESSAGE);}}private void exportPDF() {JFileChooser fileChooser = new JFileChooser();fileChooser.setDialogTitle("保存PDF文件");fileChooser.setSelectedFile(new File("圖書清單報告.pdf"));int result = fileChooser.showSaveDialog(this);if (result == JFileChooser.APPROVE_OPTION) {File file = fileChooser.getSelectedFile();String filePath = file.getAbsolutePath();if (!filePath.toLowerCase().endsWith(".pdf")) {filePath += ".pdf";}try {createPDF(filePath);JOptionPane.showMessageDialog(this, "PDF導出成功: " + filePath, "導出成功", JOptionPane.INFORMATION_MESSAGE);if (Desktop.isDesktopSupported()) {Desktop.getDesktop().open(new File(filePath));}} catch (Exception ex) {ex.printStackTrace();JOptionPane.showMessageDialog(this, "導出PDF時出錯: " + ex.getMessage(), "錯誤", JOptionPane.ERROR_MESSAGE);}}}private void createPDF(String filePath) throws Exception {try (PdfWriter writer = new PdfWriter(filePath);PdfDocument pdf = new PdfDocument(writer);Document document = new Document(pdf)) {// 設置文檔屬性document.setMargins(50, 50, 50, 50);// 添加標題Paragraph title = new Paragraph("圖書清單報告").setFont(titleFont).setFontSize(24).setTextAlignment(TextAlignment.CENTER).setFontColor(ColorConstants.DARK_GRAY).setMarginBottom(20);document.add(title);// 添加副標題Paragraph subtitle = new Paragraph("自定義表格與圖片展示").setFont(font).setFontSize(16).setTextAlignment(TextAlignment.CENTER).setFontColor(ColorConstants.GRAY).setMarginBottom(30);document.add(subtitle);// 添加表格addTableToDocument(document);// 添加圖片addImagesToDocument(document);// 添加頁腳Paragraph footer = new Paragraph("生成時間: " + new java.util.Date()).setFont(font).setFontSize(10).setTextAlignment(TextAlignment.CENTER).setFontColor(ColorConstants.LIGHT_GRAY).setMarginTop(30);document.add(footer);}}private void addTableToDocument(Document document) {// 創建表格float[] columnWidths = {3, 2, 1, 1, 1};Table pdfTable = new Table(UnitValue.createPercentArray(columnWidths));pdfTable.setWidth(UnitValue.createPercentValue(100));pdfTable.setMarginBottom(30);// 添加表頭for (int col = 0; col < tableModel.getColumnCount(); col++) {Cell headerCell = new Cell().add(new Paragraph(tableModel.getColumnName(col)).setFont(titleFont).setFontSize(12).setBackgroundColor(new com.itextpdf.kernel.color.Color(230, 230, 230)).setTextAlignment(TextAlignment.CENTER);pdfTable.addHeaderCell(headerCell);}// 添加表格數據for (int row = 0; row < tableModel.getRowCount(); row++) {for (int col = 0; col < tableModel.getColumnCount(); col++) {Object value = tableModel.getValueAt(row, col);String text = value != null ? value.toString() : "";Cell dataCell = new Cell().add(new Paragraph(text)).setFont(font).setFontSize(11);// 設置特殊列的樣式if (col == 2) { // 價格列dataCell.setTextAlignment(TextAlignment.RIGHT);} else if (col == 4) { // 評分列try {double rating = Double.parseDouble(text);if (rating >= 4.5) {dataCell.setFontColor(ColorConstants.GREEN);} else if (rating >= 4.0) {dataCell.setFontColor(ColorConstants.BLUE);} else {dataCell.setFontColor(ColorConstants.ORANGE);}} catch (NumberFormatException e) {// 忽略格式錯誤}dataCell.setTextAlignment(TextAlignment.CENTER);} else {dataCell.setTextAlignment(TextAlignment.LEFT);}pdfTable.addCell(dataCell);}}document.add(pdfTable);}private void addImagesToDocument(Document document) throws Exception {if (imagePaths.isEmpty()) return;// 添加圖片標題Paragraph imageTitle = new Paragraph("圖書封面").setFont(titleFont).setFontSize(16).setMarginBottom(15);document.add(imageTitle);// 添加圖片for (String path : imagePaths) {if (!Files.exists(Paths.get(path))) continue;try {ImageData imageData = ImageDataFactory.create(path);Image pdfImage = new Image(imageData);// 調整圖片大小(最大寬度400px,保持寬高比)float width = pdfImage.getImageWidth();float height = pdfImage.getImageHeight();float maxWidth = 400;if (width > maxWidth) {float ratio = maxWidth / width;pdfImage.scale(ratio, ratio);}// 居中顯示pdfImage.setHorizontalAlignment(com.itextpdf.layout.property.HorizontalAlignment.CENTER);pdfImage.setMarginBottom(20);document.add(pdfImage);} catch (Exception e) {System.err.println("無法加載圖片: " + path);e.printStackTrace();}}}public static void main(String[] args) {SwingUtilities.invokeLater(() -> {try {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch (Exception e) {e.printStackTrace();}PDFExporter exporter = new PDFExporter();exporter.setVisible(true);});}
}
使用說明
要運行此程序,您需要以下依賴項:
- iText 7 Core庫 (用于PDF生成)
- Java Swing (用于GUI)
Maven依賴配置
<dependencies><!-- iText 7 Core --><dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>7.2.5</version><type>pom</type></dependency><!-- 其他必要的依賴項 -->
</dependencies>
程序功能
-
表格自定義:
- 添加/刪除表格行
- 編輯表格內容
- 支持多列數據
-
圖片插入:
- 添加多張圖片
- 自動調整圖片大小
- 保持圖片寬高比
-
PDF操作:
- 預覽生成的PDF
- 導出PDF文件
- 自動打開生成的PDF
-
用戶界面:
- 表格數據編輯區
- PDF內容預覽區
- 操作按鈕面板
使用步驟
- 在表格中編輯或添加圖書數據
- 點擊"添加圖片"按鈕插入圖書封面
- 使用"預覽PDF"查看效果
- 滿意后點擊"導出PDF"保存文件
程序會自動為表格添加樣式,并根據評分值顯示不同顏色,使生成的PDF更具可讀性。
注意:實際使用中,您可能需要添加中文字體支持以正確顯示中文內容。