【无标题】导出pdf

发布于:2025-07-09 ⋅ 阅读:(20) ⋅ 点赞:(0)

Java PDF导出工具 - iText 7实现

下面是一个使用iText 7库实现的PDF导出工具,支持页眉文字和图片、表格插入和图片插入功能。

import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.property.HorizontalAlignment;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

public class PdfExportTool extends JFrame {

    private JTextField headerTextField;
    private JTextField logoPathField;
    private JTextArea contentArea;
    private JTable dataTable;
    private JTextField imagePathField;
    private JLabel imagePreview;

    public PdfExportTool() {
        setTitle("PDF导出工具 - iText 7实现");
        setSize(850, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout(10, 10));

        // 主面板
        JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
        mainPanel.setBorder(new EmptyBorder(15, 15, 15, 15));
        mainPanel.setBackground(new Color(245, 248, 250));

        // 创建顶部控制面板
        JPanel topPanel = new JPanel(new GridLayout(0, 1, 10, 10));
        topPanel.setBackground(new Color(245, 248, 250));
        
        // 页眉设置
        JPanel headerPanel = createHeaderPanel();
        topPanel.add(headerPanel);
        
        // 内容设置
        JPanel contentPanel = createContentPanel();
        topPanel.add(contentPanel);
        
        mainPanel.add(topPanel, BorderLayout.NORTH);

        // 创建中心面板
        JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        
        // 表格标签页
        tabbedPane.addTab("表格数据", createTablePanel());
        
        // 图片标签页
        tabbedPane.addTab("图片设置", createImagePanel());
        
        mainPanel.add(tabbedPane, BorderLayout.CENTER);

        // 底部按钮
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 15));
        buttonPanel.setBackground(new Color(245, 248, 250));
        
        JButton exportBtn = new JButton("导出PDF");
        exportBtn.setFont(new Font("微软雅黑", Font.BOLD, 16));
        exportBtn.setBackground(new Color(65, 131, 215));
        exportBtn.setForeground(Color.WHITE);
        exportBtn.setFocusPainted(false);
        exportBtn.setPreferredSize(new Dimension(150, 45));
        
        buttonPanel.add(exportBtn);
        
        // 添加事件
        exportBtn.addActionListener(e -> exportPdf());
        
        mainPanel.add(buttonPanel, BorderLayout.SOUTH);
        
        add(mainPanel);
    }

    private JPanel createHeaderPanel() {
        JPanel panel = new JPanel(new GridLayout(2, 1, 5, 5));
        panel.setBorder(BorderFactory.createTitledBorder("页眉设置"));
        panel.setBackground(Color.WHITE);
        
        // 第一行:文字
        JPanel textPanel = new JPanel(new BorderLayout(10, 10));
        textPanel.setBackground(Color.WHITE);
        textPanel.add(new JLabel("页眉文字:"), BorderLayout.WEST);
        
        headerTextField = new JTextField("年度销售报告");
        headerTextField.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        textPanel.add(headerTextField, BorderLayout.CENTER);
        
        // 第二行:Logo
        JPanel logoPanel = new JPanel(new BorderLayout(10, 10));
        logoPanel.setBackground(Color.WHITE);
        logoPanel.add(new JLabel("Logo图片:"), BorderLayout.WEST);
        
        JPanel logoFieldPanel = new JPanel(new BorderLayout(5, 5));
        logoPathField = new JTextField();
        logoPathField.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        logoFieldPanel.add(logoPathField, BorderLayout.CENTER);
        
        JButton browseLogoBtn = new JButton("浏览...");
        browseLogoBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        browseLogoBtn.addActionListener(e -> selectImage(logoPathField));
        logoFieldPanel.add(browseLogoBtn, BorderLayout.EAST);
        
        logoPanel.add(logoFieldPanel, BorderLayout.CENTER);
        
        panel.add(textPanel);
        panel.add(logoPanel);
        
        return panel;
    }

    private JPanel createContentPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder("内容设置"));
        panel.setBackground(Color.WHITE);
        
        contentArea = new JTextArea();
        contentArea.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        contentArea.setLineWrap(true);
        contentArea.setWrapStyleWord(true);
        contentArea.setText("本报告总结了公司2023年度的销售业绩和关键指标。\n\n" +
                "主要亮点包括:\n" +
                "• 全年销售额同比增长25%\n" +
                "• 新产品线贡献了总收入的35%\n" +
                "• 客户满意度达到历史最高水平\n\n" +
                "报告详细分析了各产品类别的表现、区域销售数据和未来增长机会。");
        
        JScrollPane scrollPane = new JScrollPane(contentArea);
        
        panel.add(scrollPane, BorderLayout.CENTER);
        
        return panel;
    }

    private JPanel createTablePanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(new EmptyBorder(10, 10, 10, 10));
        panel.setBackground(Color.WHITE);
        
        // 创建表格模型
        String[] columns = {"产品类别", "Q1", "Q2", "Q3", "Q4", "总计"};
        Object[][] data = {
                {"电子产品", 1850000, 2100000, 2450000, 2750000, 9150000},
                {"家用电器", 1200000, 1350000, 1500000, 1800000, 5850000},
                {"服装", 850000, 920000, 780000, 950000, 3500000},
                {"食品", 620000, 580000, 650000, 720000, 2570000},
                {"家具", 480000, 520000, 600000, 750000, 2350000}
        };
        
        dataTable = new JTable(data, columns);
        dataTable.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        dataTable.setRowHeight(30);
        dataTable.getTableHeader().setFont(new Font("微软雅黑", Font.BOLD, 14));
        
        JScrollPane scrollPane = new JScrollPane(dataTable);
        
        panel.add(scrollPane, BorderLayout.CENTER);
        
        return panel;
    }

    private JPanel createImagePanel() {
        JPanel panel = new JPanel(new BorderLayout(10, 10));
        panel.setBorder(new EmptyBorder(10, 10, 10, 10));
        panel.setBackground(Color.WHITE);
        
        // 图片路径选择
        JPanel pathPanel = new JPanel(new BorderLayout(10, 10));
        pathPanel.setBackground(Color.WHITE);
        pathPanel.add(new JLabel("图片路径:"), BorderLayout.WEST);
        
        JPanel fieldPanel = new JPanel(new BorderLayout(5, 5));
        imagePathField = new JTextField();
        imagePathField.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        fieldPanel.add(imagePathField, BorderLayout.CENTER);
        
        JButton browseBtn = new JButton("浏览...");
        browseBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        browseBtn.addActionListener(e -> selectImage(imagePathField));
        fieldPanel.add(browseBtn, BorderLayout.EAST);
        
        pathPanel.add(fieldPanel, BorderLayout.CENTER);
        
        // 图片预览
        JPanel previewPanel = new JPanel(new BorderLayout());
        previewPanel.setBorder(BorderFactory.createTitledBorder("图片预览"));
        previewPanel.setBackground(Color.WHITE);
        previewPanel.setPreferredSize(new Dimension(300, 300));
        
        imagePreview = new JLabel("", JLabel.CENTER);
        imagePreview.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        imagePreview.setOpaque(true);
        imagePreview.setBackground(new Color(240, 240, 240));
        imagePreview.setBorder(BorderFactory.createLineBorder(Color.GRAY));
        previewPanel.add(imagePreview, BorderLayout.CENTER);
        
        // 添加按钮
        JButton previewBtn = new JButton("预览图片");
        previewBtn.setFont(new Font("微软雅黑", Font.BOLD, 14));
        previewBtn.setBackground(new Color(70, 130, 180));
        previewBtn.setForeground(Color.WHITE);
        previewBtn.addActionListener(e -> previewImage());
        
        JPanel btnPanel = new JPanel();
        btnPanel.setBackground(Color.WHITE);
        btnPanel.add(previewBtn);
        
        // 布局
        panel.add(pathPanel, BorderLayout.NORTH);
        panel.add(previewPanel, BorderLayout.CENTER);
        panel.add(btnPanel, BorderLayout.SOUTH);
        
        return panel;
    }

    private void selectImage(JTextField textField) {
        JFileChooser fileChooser = new JFileChooser();
        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            textField.setText(file.getAbsolutePath());
        }
    }

    private void previewImage() {
        String path = imagePathField.getText();
        if (path != null && !path.isEmpty()) {
            File file = new File(path);
            if (file.exists()) {
                ImageIcon icon = new ImageIcon(path);
                Image img = icon.getImage().getScaledInstance(300, 250, Image.SCALE_SMOOTH);
                imagePreview.setIcon(new ImageIcon(img));
            } else {
                JOptionPane.showMessageDialog(this, "图片文件不存在", "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private void exportPdf() {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setSelectedFile(new File("report.pdf"));
        int result = fileChooser.showSaveDialog(this);
        
        if (result == JFileChooser.APPROVE_OPTION) {
            File outputFile = fileChooser.getSelectedFile();
            if (!outputFile.getName().toLowerCase().endsWith(".pdf")) {
                outputFile = new File(outputFile.getPath() + ".pdf");
            }
            
            try {
                generatePdfDocument(outputFile);
                JOptionPane.showMessageDialog(this, "PDF导出成功!\n保存位置: " + outputFile.getPath(), 
                        "导出成功", JOptionPane.INFORMATION_MESSAGE);
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "导出失败: " + e.getMessage(), 
                        "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private void generatePdfDocument(File outputFile) throws IOException {
        // 初始化PDF文档
        PdfWriter writer = new PdfWriter(outputFile);
        PdfDocument pdf = new PdfDocument(writer);
        Document document = new Document(pdf);
        
        // 添加自定义页眉处理器
        HeaderEventHandler headerHandler = new HeaderEventHandler(
                headerTextField.getText(), 
                logoPathField.getText()
        );
        pdf.addEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
        
        // 设置字体
        PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", false);
        
        // 添加标题
        Paragraph title = new Paragraph("2023年度销售报告")
                .setFont(font)
                .setFontSize(22)
                .setBold()
                .setTextAlignment(TextAlignment.CENTER)
                .setMarginTop(40);
        document.add(title);
        
        // 添加副标题
        Paragraph subtitle = new Paragraph("销售数据分析与总结")
                .setFont(font)
                .setFontSize(16)
                .setTextAlignment(TextAlignment.CENTER)
                .setMarginBottom(30);
        document.add(subtitle);
        
        // 添加内容
        String[] lines = contentArea.getText().split("\n");
        for (String line : lines) {
            Paragraph p = new Paragraph(line)
                    .setFont(font)
                    .setFontSize(12)
                    .setMarginBottom(8);
            document.add(p);
        }
        
        // 添加表格
        document.add(createPdfTable(font));
        
        // 添加图片
        String imagePath = imagePathField.getText();
        if (imagePath != null && !imagePath.isEmpty()) {
            try {
                ImageData imageData = ImageDataFactory.create(imagePath);
                Image pdfImage = new Image(imageData);
                pdfImage.setWidth(400);
                pdfImage.setHorizontalAlignment(HorizontalAlignment.CENTER);
                pdfImage.setMarginTop(20);
                document.add(pdfImage);
                
                Paragraph caption = new Paragraph("图1: 销售趋势图")
                        .setFont(font)
                        .setFontSize(10)
                        .setTextAlignment(TextAlignment.CENTER)
                        .setMarginBottom(30);
                document.add(caption);
            } catch (MalformedURLException e) {
                System.err.println("图片路径错误: " + e.getMessage());
            }
        }
        
        // 添加页脚
        Paragraph footer = new Paragraph("第 " + pdf.getNumberOfPages() + " 页")
                .setFont(font)
                .setFontSize(10)
                .setTextAlignment(TextAlignment.CENTER)
                .setMarginTop(20);
        document.add(footer);
        
        // 关闭文档
        document.close();
    }

    private Table createPdfTable(PdfFont font) {
        // 创建表格
        float[] columnWidths = {2, 1, 1, 1, 1, 1.5f};
        Table table = new Table(UnitValue.createPercentArray(columnWidths))
                .setWidth(UnitValue.createPercentValue(95))
                .setHorizontalAlignment(HorizontalAlignment.CENTER)
                .setMarginTop(20)
                .setMarginBottom(30);
        
        // 添加表头
        for (int i = 0; i < dataTable.getColumnCount(); i++) {
            Cell cell = new Cell()
                    .setBackgroundColor(new com.itextpdf.kernel.colors.Color(65, 131, 215))
                    .setBorder(Border.NO_BORDER)
                    .add(new Paragraph(dataTable.getColumnName(i))
                            .setFont(font)
                            .setFontSize(12)
                            .setBold()
                            .setFontColor(ColorConstants.WHITE));
            table.addHeaderCell(cell);
        }
        
        // 添加表格内容
        for (int row = 0; row < dataTable.getRowCount(); row++) {
            for (int col = 0; col < dataTable.getColumnCount(); col++) {
                Object value = dataTable.getValueAt(row, col);
                Cell cell = new Cell()
                        .setBorderBottom(new com.itextpdf.layout.borders.SolidBorder(0.5f))
                        .setPadding(5)
                        .add(new Paragraph(value != null ? value.toString() : "")
                                .setFont(font)
                                .setFontSize(11));
                
                // 格式化数字
                if (col > 0 && value instanceof Number) {
                    cell.setTextAlignment(TextAlignment.RIGHT);
                }
                
                // 交替行颜色
                if (row % 2 == 0) {
                    cell.setBackgroundColor(new com.itextpdf.kernel.colors.Color(245, 248, 250));
                }
                
                table.addCell(cell);
            }
        }
        
        return table;
    }

    // 自定义页眉事件处理器
    static class HeaderEventHandler implements IEventHandler {
        private String headerText;
        private String logoPath;
        
        public HeaderEventHandler(String headerText, String logoPath) {
            this.headerText = headerText;
            this.logoPath = logoPath;
        }
        
        @Override
        public void handleEvent(Event event) {
            PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
            PdfPage page = docEvent.getPage();
            Rectangle pageSize = page.getPageSize();
            PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), docEvent.getDocument());
            Canvas canvas = new Canvas(pdfCanvas, pageSize);
            
            try {
                // 设置字体
                PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", false);
                
                // 添加页眉文字
                Paragraph header = new Paragraph(headerText)
                        .setFont(font)
                        .setFontSize(12)
                        .setFontColor(new com.itextpdf.kernel.colors.Color(65, 131, 215))
                        .setFixedPosition(0, pageSize.getTop() - 30, pageSize.getWidth())
                        .setTextAlignment(TextAlignment.CENTER);
                
                canvas.add(header);
                
                // 添加Logo图片
                if (logoPath != null && !logoPath.isEmpty()) {
                    try {
                        ImageData imageData = ImageDataFactory.create(logoPath);
                        Image logo = new Image(imageData);
                        logo.scaleToFit(40, 40);
                        logo.setFixedPosition(30, pageSize.getTop() - 45);
                        canvas.add(logo);
                    } catch (MalformedURLException e) {
                        System.err.println("Logo路径错误: " + e.getMessage());
                    }
                }
                
                // 添加页眉分隔线
                pdfCanvas.setLineWidth(0.8f);
                pdfCanvas.setStrokeColor(new com.itextpdf.kernel.colors.Color(65, 131, 215));
                pdfCanvas.moveTo(30, pageSize.getTop() - 50);
                pdfCanvas.lineTo(pageSize.getWidth() - 30, pageSize.getTop() - 50);
                pdfCanvas.stroke();
                
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                canvas.close();
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                new PdfExportTool().setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}

功能说明

这个PDF导出工具基于iText 7库实现,包含以下功能:

1. 自定义页眉(文字+图片)

  • 支持设置页眉文字内容
  • 可以添加公司Logo或自定义图片
  • 自动在每页顶部显示页眉
  • 页眉下方有装饰分隔线

2. 表格插入

  • 创建美观的数据表格
  • 表头使用特殊样式(蓝色背景、白色文字)
  • 表格行使用交替背景色提高可读性
  • 自动调整列宽比例

3. 图片插入

  • 支持插入任意位置图片
  • 图片预览功能
  • 自动调整图片大小
  • 可为图片添加标题说明

4. 其他功能

  • 简洁直观的用户界面
  • 内容区域支持多行文本
  • 自动生成页码
  • 导出前预览功能
  • 美观的PDF格式设计

使用说明

  1. 页眉设置

    • 在"页眉文字"字段输入自定义文本
    • 点击"浏览…"按钮选择Logo图片
  2. 内容编辑

    • 在内容区域输入报告正文
    • 支持多行文本和换行
  3. 表格数据

    • 表格标签页显示默认数据
    • 可直接在表格中编辑内容
  4. 图片设置

    • 在图片路径字段输入或浏览选择图片
    • 点击"预览图片"查看效果
  5. 导出PDF

    • 点击"导出PDF"按钮
    • 选择保存位置
    • 系统将生成包含所有内容的PDF文档

技术特点

  1. 使用iText 7库

    • 强大的PDF生成功能
    • 支持中文显示
    • 灵活的布局控制
  2. 事件处理机制

    • 使用自定义事件处理器实现页眉
    • 确保页眉在每页顶部显示
  3. 美观的UI设计

    • 现代化界面布局
    • 直观的选项卡导航
    • 响应式组件设计
  4. 表格格式化

    • 交替行颜色提高可读性
    • 表头特殊样式
    • 数字右对齐

这个工具提供了完整的PDF导出功能,满足企业报告、数据分析文档等需求,生成的PDF文档专业且美观。


网站公告

今日签到

点亮在社区的每一天
去签到