You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PDFBox v2中不使用PDFPagePanel查看PDF并显示于JFrame

嘿,我来帮你搞定这个问题!既然PDFBox 2.x版本已经把问题多多的PDFPagePanel给移除了,咱们换个更靠谱的方式——直接把PDF页面渲染成图片,然后放到Swing的JFrame里展示就行,下面是具体的实现步骤和代码示例:

实现方案:手动渲染PDF页面到JFrame

1. 先搞定依赖

首先确保你的项目里引入了PDFBox的核心包,以Maven为例:

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.32</version> <!-- 建议用最新稳定版 -->
</dependency>

Gradle的话就这么加:

implementation 'org.apache.pdfbox:pdfbox:2.0.32'

2. 核心:把PDF页面转成图片

PDFBox提供了PDFRenderer类,专门用来把PDF页面渲染成BufferedImage,我们可以封装成一个工具方法,还能自定义分辨率(DPI)来控制清晰度:

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class PdfRenderHelper {
    // 渲染指定页码的PDF页面(注意:页码从0开始计数)
    public static BufferedImage renderPage(File pdfFile, int pageIndex, float dpi) throws IOException {
        // 用try-with-resources自动关闭文档,避免内存泄漏
        try (PDDocument doc = PDDocument.load(pdfFile)) {
            PDFRenderer renderer = new PDFRenderer(doc);
            // 第三个参数是旋转角度,0表示不旋转
            return renderer.renderImageWithDPI(pageIndex, dpi);
        }
    }
}

3. 把图片放到JFrame里展示

接下来我们写一个完整的JFrame示例,支持翻页、滚动查看,逻辑很简单:把渲染好的图片放到JLabel里,再套个滚动面板,加上翻页按钮就行:

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class CustomPdfViewer extends JFrame {
    private final File targetPdf;
    private int currentPage = 0;
    private final JLabel pageDisplayLabel = new JLabel();
    private final float renderDpi = 96; // 这个分辨率显示效果刚好,也可以改成144更清晰

    public CustomPdfViewer(File pdfFile) {
        this.targetPdf = pdfFile;
        initWindow();
        showCurrentPage();
    }

    private void initWindow() {
        setTitle("自定义PDF查看器");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 650);
        setLocationRelativeTo(null); // 窗口居中

        // 顶部工具栏:加翻页按钮
        JToolBar toolBar = new JToolBar();
        JButton prevBtn = new JButton("上一页");
        JButton nextBtn = new JButton("下一页");

        prevBtn.addActionListener(e -> {
            if (currentPage > 0) {
                currentPage--;
                showCurrentPage();
            }
        });

        nextBtn.addActionListener(e -> {
            try (PDDocument doc = PDDocument.load(targetPdf)) {
                if (currentPage < doc.getNumberOfPages() - 1) {
                    currentPage++;
                    showCurrentPage();
                }
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(this, "加载PDF失败:" + ex.getMessage(), "出错啦", JOptionPane.ERROR_MESSAGE);
            }
        });

        toolBar.add(prevBtn);
        toolBar.add(nextBtn);
        add(toolBar, BorderLayout.NORTH);

        // 图片放滚动面板里,支持上下左右滚动
        JScrollPane scrollPane = new JScrollPane(pageDisplayLabel);
        add(scrollPane, BorderLayout.CENTER);
    }

    private void showCurrentPage() {
        try {
            BufferedImage pageImage = PdfRenderHelper.renderPage(targetPdf, currentPage, renderDpi);
            pageDisplayLabel.setIcon(new ImageIcon(pageImage));
            // 更新窗口标题,显示当前页码/总页数
            setTitle(String.format("自定义PDF查看器 - 第 %d 页 / 共 %d 页", currentPage + 1, getTotalPages()));
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this, "渲染页面失败:" + ex.getMessage(), "出错啦", JOptionPane.ERROR_MESSAGE);
        }
    }

    // 获取PDF总页数
    private int getTotalPages() {
        try (PDDocument doc = PDDocument.load(targetPdf)) {
            return doc.getNumberOfPages();
        } catch (IOException ex) {
            return 0;
        }
    }

    public static void main(String[] args) {
        // Swing组件要在事件调度线程里初始化
        SwingUtilities.invokeLater(() -> {
            File pdfFile = new File("你的PDF文件路径.pdf");
            if (pdfFile.exists()) {
                new CustomPdfViewer(pdfFile).setVisible(true);
            } else {
                JOptionPane.showMessageDialog(null, "找不到指定的PDF文件!", "出错啦", JOptionPane.ERROR_MESSAGE);
            }
        });
    }
}

4. 一些实用提示

  • 资源释放:一定要用try-with-resources包裹PDDocument,确保文档资源被及时释放,避免内存泄漏。
  • 性能优化:如果是大PDF,不要一次性渲染所有页面,按需渲染当前页即可;如果需要流畅翻页,可以提前预加载前后1-2页,但要注意内存占用。
  • 缩放支持:如果需要缩放功能,可以对BufferedImage进行缩放处理,比如用Image.getScaledInstance(),或者用更高效的第三方缩放库(比如Thumbnails)。
  • 异常处理:实际项目里要多考虑异常场景,比如PDF损坏、文件不存在、权限不足等,给用户清晰的提示。

内容的提问来源于stack exchange,提问作者nymvno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:41:43