java将pdf文件转换为图片工具类

一、相关依赖

java 复制代码
	<!-- PDFBox for PDF processing -->
		<dependency>
			<groupId>org.apache.pdfbox</groupId>
			<artifactId>pdfbox</artifactId>
			<version>2.0.27</version>
		</dependency>

二、工具类

java 复制代码
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.rendering.PDFRenderer;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: PdfConvertImage
 * @Description: PDF文件转图片
 * @Author: zhanghui
 * @Date: 2025-06-06
 * @Version: 1.0
 **/
public class PdfConvertImage {
    
    /**
     * 默认图片格式
     */
    private static final String DEFAULT_IMAGE_FORMAT = "png";
    
    /**
     * 默认图片分辨率 - 保持原始比例的高清输出
     */
    private static final double DEFAULT_SCALE = 2.0;

    /**
     * 将多个PDF文件转换为图片,使用平衡的高清分辨率
     * 
     * @param pdfFiles PDF文件列表
     * @param outputDir 输出根目录
     * @return 生成的图片路径列表
     * @throws Exception 转换异常
     */
    public static List<String> convertPdfsToImagesWithBalancedResolution(List<File> pdfFiles, String outputDir) throws Exception {
        // 使用2K分辨率,平衡质量和文件大小
        return convertPdfsToImagesWithBalancedResolution(pdfFiles, outputDir, 2560, 1440);
    }

    /**
     * 将多个PDF文件转换为图片,使用平衡的高清分辨率(可配置)
     * 
     * @param pdfFiles PDF文件列表
     * @param outputDir 输出根目录
     * @param targetWidth 目标宽度(推荐:1920-2560)
     * @param targetHeight 目标高度(推荐:1080-1440)
     * @return 生成的图片路径列表
     * @throws Exception 转换异常
     */
    public static List<String> convertPdfsToImagesWithBalancedResolution(List<File> pdfFiles, String outputDir, int targetWidth, int targetHeight) throws Exception {
        if (pdfFiles == null || pdfFiles.isEmpty()) {
            throw new IllegalArgumentException("PDF文件列表不能为空");
        }
        
        // 创建项目文件夹
        String projectDir = createProjectDirectory(outputDir);
        
        List<String> allImagePaths = new ArrayList<>();
        
        // 处理每个PDF文件
        for (int i = 0; i < pdfFiles.size(); i++) {
            File pdfFile = pdfFiles.get(i);
            if (!pdfFile.exists() || !pdfFile.isFile()) {
                System.err.println("警告:文件不存在或不是有效文件: " + pdfFile.getPath());
                continue;
            }
            
            String pdfName = getFileNameWithoutExtension(pdfFile.getName());
            
            // 将所有图片保存到同一个目录中,通过文件名前缀区分不同的PDF
            List<String> imagePaths = convertSinglePdfToImagesWithBalancedResolution(pdfFile, projectDir, pdfName, targetWidth, targetHeight);
            allImagePaths.addAll(imagePaths);
        }
        
        return allImagePaths;
    }

    /**
     * 转换单个PDF文件为图片,使用平衡的高清分辨率
     * 
     * @param pdfFile PDF文件
     * @param outputDir 输出目录
     * @param pdfNamePrefix PDF名称前缀,用于区分不同PDF的图片
     * @param targetWidth 目标宽度
     * @param targetHeight 目标高度
     * @return 生成的图片路径列表
     * @throws Exception 转换异常
     */
    private static List<String> convertSinglePdfToImagesWithBalancedResolution(File pdfFile, String outputDir, String pdfNamePrefix, int targetWidth, int targetHeight) throws Exception {
        List<String> imagePaths = new ArrayList<>();
        
        try (PDDocument document = PDDocument.load(pdfFile)) {
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            int pageCount = document.getNumberOfPages();
            
            for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
                // 获取PDF页面尺寸
                PDRectangle pageSize = document.getPage(pageIndex).getBBox();
                double originalWidth = pageSize.getWidth();
                double originalHeight = pageSize.getHeight();
                
                // 根据原始比例调整目标尺寸
                double originalRatio = originalWidth / originalHeight;
                double targetRatio = (double) targetWidth / targetHeight;
                
                int finalWidth = targetWidth;
                int finalHeight = targetHeight;
                
                if (originalRatio > targetRatio) {
                    // 原始更宽,以宽度为准
                    finalHeight = (int) Math.round(targetWidth / originalRatio);
                } else {
                    // 原始更高,以高度为准
                    finalWidth = (int) Math.round(targetHeight * originalRatio);
                }
                
                // 计算缩放比例
                double scale = Math.min((double) finalWidth / originalWidth, (double) finalHeight / originalHeight);
                
                System.out.println("PDF页面 " + (pageIndex + 1) + " 原始尺寸:" + originalWidth + "x" + originalHeight);
                System.out.println("目标尺寸:" + finalWidth + "x" + finalHeight);
                System.out.println("缩放比例:" + String.format("%.2f", scale));
                
                // 渲染PDF页面为图片
                BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, (float) (scale * 72));
                
                // 创建最终尺寸的图片
                BufferedImage finalImage = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics = finalImage.createGraphics();
                
                // 设置高质量渲染参数
                graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
                graphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
                
                // 填充白色背景
                graphics.setColor(Color.WHITE);
                graphics.fillRect(0, 0, finalWidth, finalHeight);
                
                // 计算居中位置
                int x = (finalWidth - image.getWidth()) / 2;
                int y = (finalHeight - image.getHeight()) / 2;
                
                // 绘制图片
                graphics.drawImage(image, x, y, null);
                graphics.dispose();
                
                // 保存图片
                String imagePath = outputDir + File.separator + pdfNamePrefix + "_page_" + (pageIndex + 1) + "." + DEFAULT_IMAGE_FORMAT;
                File imageFile = new File(imagePath);
                writeHighQualityImage(finalImage, imageFile, DEFAULT_IMAGE_FORMAT);
                imagePaths.add(imagePath);
                
                // 显示文件大小信息
                if (imageFile.exists()) {
                    long fileSizeKB = imageFile.length() / 1024;
                    System.out.println("图片 " + (pageIndex + 1) + " 大小:" + fileSizeKB + " KB");
                }
            }
        }
        
        return imagePaths;
    }

    /**
     * 创建项目目录
     * 
     * @param baseDir 基础目录
     * @return 项目目录路径
     */
    private static String createProjectDirectory(String baseDir) {
        String projectDir = baseDir + File.separator;
        
        File directory = new File(projectDir);
        if (!directory.exists()) {
            directory.mkdirs();
        }
        
        return projectDir;
    }
    
    /**
     * 获取不包含扩展名的文件名
     * 
     * @param fileName 文件名
     * @return 不包含扩展名的文件名
     */
    private static String getFileNameWithoutExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex > 0) {
            return fileName.substring(0, lastDotIndex);
        }
        return fileName;
    }

    /**
     * 高质量图片输出方法
     * 
     * @param image 要保存的图片
     * @param imageFile 输出文件
     * @param format 图片格式
     * @throws IOException IO异常
     */
    private static void writeHighQualityImage(BufferedImage image, File imageFile, String format) throws IOException {
        // 使用PNG格式确保无损压缩,保持原PDF质量
        if ("png".equalsIgnoreCase(format)) {
            ImageIO.write(image, format, imageFile);
        } else {
            // 如果是其他格式,也使用高质量设置
            ImageIO.write(image, format, imageFile);
        }
    }

    public static void main(String[] args) {
        try {
            // 测试:将多个PDF文件转换为图片,所有图片保存到一个文件夹中
            String outputDir = "/Users/engine/Desktop/img";

            List<File> pdfFiles = new ArrayList<>();
            // 添加你的PDF文件路径
            pdfFiles.add(new File("/Users/engine/Desktop/小程序注册全流程_1749436018969.pdf"));
            pdfFiles.add(new File("/Users/engine/Desktop/演示文稿1.pdf"));

            // 使用平衡分辨率方法(推荐:解决文字挤压且控制文件大小)
            System.out.println("=== 使用平衡分辨率模式转换(2K分辨率) ===");
            List<String> imagePaths = PdfConvertImage.convertPdfsToImagesWithBalancedResolution(pdfFiles, outputDir);

            System.out.println("=== PDF转图片完成 ===");
            System.out.println("输出目录:" + outputDir);
            System.out.println("转换模式:平衡分辨率模式(2K分辨率平衡质量与文件大小)");
            System.out.println("总共生成了 " + imagePaths.size() + " 张图片:");

            // 按顺序显示所有图片路径(前端轮播可以直接使用这个列表)
            for (int i = 0; i < imagePaths.size(); i++) {
                System.out.println((i + 1) + ". " + imagePaths.get(i));
            }

            System.out.println("前端轮播提示:");
            System.out.println("- 所有图片都在同一个文件夹中");
            System.out.println("- 图片命名格式:[PDF文件名]_page_[序号].png");
            System.out.println("- 可以直接使用返回的图片路径列表进行轮播展示");
            System.out.println("- 图片采用高质量无损PNG格式,保持原PDF文字布局和显示效果");
            System.out.println("- 渲染改进:使用2K分辨率平衡质量与文件大小,解决文字挤压问题");
            System.out.println("- 文件大小:每张图片显示实际大小,便于监控");

        } catch (Exception e) {
            System.err.println("转换失败:" + e.getMessage());
            e.printStackTrace();
        }
    }
} 
相关推荐
struggle202527 分钟前
Burn 开源程序是下一代深度学习框架,在灵活性、效率和可移植性方面毫不妥协
人工智能·python·深度学习·rust
腾飞开源30 分钟前
17_Flask部署到网络服务器
python·flask·python web开发·flask快速入门教程·flask框架·flask视频教程·flask会话技术
我在北国不背锅37 分钟前
基于Java开发的浏览器自动化Playwright-MCP服务器
java·playwright·mcp
Mikhail_G44 分钟前
Python应用八股文
大数据·运维·开发语言·python·数据分析
mikes zhang1 小时前
Flask文件上传与异常处理完全指南
后端·python·flask
烛阴1 小时前
深入浅出地理解Python元类【从入门到精通】
前端·python
LUCIAZZZ1 小时前
钉钉机器人-自定义卡片推送快速入门
java·jvm·spring boot·机器人·钉钉·springboot
优秀1351 小时前
java33
java
weixin_464078072 小时前
Python学习小结
python·学习
fajianchen2 小时前
Spring中观察者模式的应用
java·开发语言