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

一、相关依赖

	<!-- PDFBox for PDF processing --><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.27</version></dependency>

二、工具类

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());// 将所有图片保存到同一个目录中,通过文件名前缀区分不同的PDFList<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();}}
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/909578.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/909578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零门槛探索国产数据库硬核实力 —— 金仓数据库在线体验平台体验记

1、 金仓数据库在线体验平台 最近&#xff0c;我发现了一个超棒的数据库宝藏 —— 金仓数据库在线体验平台。它在金仓社区上线后&#xff0c;凭借 “零门槛体验 多场景交互” 的特点&#xff0c;迅速吸引了众多数据库爱好者的目光&#xff0c;我也忍不住去体验了一番。 2、 …

Linux基本操作指令和vim编译器

基本指令 查看日期与日历 data 指令 显示日期 用法1&#xff1a;data CST&#xff1a;China Standard Time 时区&#xff0c;中国标准时间 用法2&#xff1a; data 指定格式 常用格式&#xff1a; “%Y-%m-%d”(%F): 2025-06-16“%H:%M:%S”(%T): 20:19:45“%F%T”用法3&am…

“从HTTP到TCP/IP的旅程“-----深入浅出Java Web通信

先放结构图&#xff1a; 一、引言&#xff1a;网络通信就像寄快递 想象一下我们在网上买了一本书&#xff0c;整个配送过程是这样的&#xff1a; 应用层&#xff1a;你在购物网站填好收货地址&#xff08;HTTP请求&#xff09;传输层&#xff1a;快递公司把包裹打包&#xf…

docker build使用代理以实现构建过程中下载Github源码等操作

在通过Dockerfile构建docker容器的过程中&#xff0c;经常会需要在构建过程中拉取Github上的代码。当宿主机配好代理&#xff0c;但容器内是一个隔离的环境&#xff0c;若想在容器内访问&#xff0c;则需再打通容器和宿主机之间的代理配置。 方法一&#xff1a; 若宿主机上的…

Docker 快速搭建一个基于 GPT-Vis 组件的统计图表生成服务

以下是对工具简单介绍&#xff1a; 可以在服务端使用 GPT-Vis 统计图表组件直接渲染成图片支持Docker一键部署&#xff0c;提供统计图表渲染生成API接口支持多种GPT-Vis支持的组件&#xff0c;包括折线图、柱形图、饼图、面积图、条形图、直方图、散点图、词云图、雷达图、思维…

hal库练习1

要求&#xff1a;一个按键实现呼吸灯的控制&#xff0c;一个按键控制LED灯的闪烁&#xff0c;串口发送数据控制灯的开关 定时器配置 1.选择需要的定时器2.配置基础参数&#xff08;根据时钟树给定时器输入的时钟&#xff09;3.打开中断4.在主函数里打开中断 定时器扫描按键 …

java线程(4)

程序(program) 是为完成制定任务,用某种语言编写的一组指令的集合.简单的话说:就是我们写的代码. 进程 1.进程是指进行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存空间,当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间. 2、…

02《F8Framework》核心入口 FF8.cs

FF8.cs类是 F8Framework的核心入口 采用单例模式 提供对各个功能模块的全局访问 【特点】通过静态类FF8统一访问所有功能 1.模块化设计&#xff1a; 每个功能独立 通过 ModuleCenter 统一管理 2.懒加载机制&#xff1a; …

【硬件】相机的硬件测试

相机测试 author: Alla Imatest 提供超过 30 种测试项目&#xff0c;主要包括&#xff1a; 1&#xff09;图像基础参数‌&#xff1a;MTF&#xff08;调制传递函数&#xff09;、畸变、均匀性、动态范围 2&#xff09;色彩与光学特性‌&#xff1a;白平衡误差、饱和度、gamma …

Profinet与Modbus TCP协议转换技术:西门子S7-1500(主站)和欧姆龙NJ PLC的高效数据交换

一、项目背景 某大型现代化智慧农业养殖场致力于打造全方位智能化的养殖环境。其养殖系统中&#xff0c;环境监测与调控部分选用了西门子S7-1500PLC作为Profinet协议主站。该PLC凭借强大的运算能力和丰富的功能模块&#xff0c;能够精准地采集和处理养殖场内的温度、湿度、空气…

希尔伯特变换,实信号转复信号的FPGA实现思路

希尔伯特变换将实信号转复信号的原理 将实信号的相位推迟90度后作为复信号的虚部。 错误实现方式 实信号经过希尔伯特滤波后得到复信号的虚部&#xff0c;之后直接与实信号组成复信号。而由于滤波器本身会对信号延时&#xff0c;故I路与Q路并不是相差90度&#xff0c;所以此方…

多模态大语言模型演进:从视觉理解到具身智能的技术突破

多模态大语言模型演进:从视觉理解到具身智能的技术突破 多模态大语言模型(MLLMs)正在重塑人工智能的边界,实现从"看见"到"理解"再到"行动"的全链条智能。本文将深入解析苹果最新多模态研究进展,揭示视觉-语言模型十年演进的技术脉络,剖析…

window显示驱动开发—渲染管道

支持 Direct3D 版本 10 的图形硬件可以使用共享可编程着色器核心进行设计。 GPU) (图形处理单元可以编程着色器核心&#xff0c;这些着色器核心可以跨构成呈现管道的功能块进行计划。 这种负载均衡意味着硬件开发人员不需要使用每种着色器类型&#xff0c;而只需要使用执行呈现…

时序数据库Apache IoTDB核心技术深度解析

一、引言 ‌背景‌&#xff1a;5G技术加速了IoT领域的发展&#xff0c;物联网设备数据的收集、存储和计算需求日益增长。Apache IoTDB作为一款专为物联网时序数据设计的软件系统&#xff0c;在2020年被Apache基金会认可为顶级项目。 二、IoT领域发展趋势 ‌5G与IoT‌&#x…

Next.js面试题:API深度解析

Next.js面试题&#xff1a;API深度解析 Next.js 通过 App Router 的引入彻底改变了 Web 开发范式。在这个新时代&#xff0c;深入理解 Next.js 的 API 函数不再只是锦上添花&#xff0c;而是技术面试中的关键区分点。这些函数构成了构建高性能、可扩展、现代化 Web 应用的基石…

Docker-MCP quickstart

项目概述 Docker-MCP 是一个 支持mcp的Docker 管理服务器&#xff0c;它允许 客户端 通过 MCP&#xff08;Model Control Protocol&#xff09;接口直接与 Docker 进行交互。该项目提供了一套工具&#xff0c;使 AI 助手能够创建容器、部署 Docker Compose 、获取容器日志以及…

git 的变基操作(适合一个功能进行了多次commit提交,提交记录过多不美观)

git提交的 commit 的记录很多&#xff0c;想多个 commit 进行合并&#xff0c;对代码进行整理&#xff0c;帮助更好的阅读代码 IDEA 的操作步骤&#xff1a; 这里&#xff0c;给出你想进行合并的记录 hash 值&#xff0c;完了点击“Rebase”进行合并 点击后&#xff0c;会进行…

【完整源码+数据集+部署教程】路边广告牌实例分割系统源码和数据集:改进yolo11-SEAMHead

研究背景与意义 研究背景与意义 随着城市化进程的加快&#xff0c;路边广告牌作为重要的商业宣传媒介&#xff0c;越来越多地出现在城市的各个角落。它们不仅承担着信息传播的功能&#xff0c;还对城市的视觉环境产生了深远的影响。然而&#xff0c;随着广告牌数量的激增&…

C++ 中文件 IO 操作详解

在C中&#xff0c;文件操作是通过流(stream)来实现的。标准库提供了三种主要的文件流类来处理文件IO操作&#xff1a; ofstream&#xff1a;用于写入文件&#xff08;output file stream&#xff09;ifstream&#xff1a;用于读取文件&#xff08;input file stream&#xff0…

第32节 Node.js 全局对象

在Node.js中我们可以直接访问到全局对象。 这些对象在所有模块里都是可用的&#xff0c;有些对象不是在全局作用域而是在模块作用域里&#xff0c;这些情况将在本文的内容中进行介绍。 global {Object} 全局命名空间对象。 在浏览器中&#xff0c;全局作用域就是顶级域。如…