在一些文档处理场景中,PDF 里经常会包含大量图片,例如扫描件、产品手册、报告附件、合同图片等。 有时候我们需要把 PDF 里的图片单独提取出来,用于归档、识别、二次编辑;也有时候 PDF 文件过大,原因正是里面嵌入了高分辨率图片,这时就需要对图片进行压缩。
本文以 Spire.PDF for Java 为例,实现两类常见图片操作:
- 从 PDF 文档中提取图片
- 压缩 PDF 文档中的高质量图片
一、准备工作
示例代码使用 Maven 项目。先在 pom.xml 中加入 Spire.PDF for Java 依赖。
xml
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.pdf</artifactId>
<version>12.6.1</version>
</dependency>
</dependencies>
如果是普通 Java 项目,也可以手动引入对应的 Jar 包。 为了方便演示,下面的代码都使用本地文件路径,需要根据自己的实际目录修改。
二、从 PDF 中提取图片
1. 实现思路
提取图片的核心流程并不复杂:
- 加载 PDF 文件;
- 遍历 PDF 的每一页;
- 获取当前页中的图片信息;
- 将图片对象保存为本地图片文件。
Spire.PDF 中可以使用 PdfImageHelper 获取页面里的图片信息,再通过 PdfImageInfo.getImage() 拿到 BufferedImage 对象,最后用 ImageIO.write() 写出到本地。
2. 示例代码
ini
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.utilities.PdfImageHelper;
import com.spire.pdf.utilities.PdfImageInfo;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ExtractPdfImages {
public static void main(String[] args) throws IOException {
String inputPdf = "C:/pdf/input.pdf";
String outputDir = "C:/pdf/images/";
PdfDocument document = new PdfDocument();
try {
// 加载 PDF 文件
document.loadFromFile(inputPdf);
// 创建输出目录
File dir = new File(outputDir);
if (!dir.exists()) {
dir.mkdirs();
}
PdfImageHelper imageHelper = new PdfImageHelper();
int imageIndex = 1;
// 遍历 PDF 每一页
for (int pageIndex = 0; pageIndex < document.getPages().getCount(); pageIndex++) {
PdfPageBase page = document.getPages().get(pageIndex);
// 获取当前页中的所有图片
PdfImageInfo[] imageInfos = imageHelper.getImagesInfo(page);
// 保存图片
for (PdfImageInfo imageInfo : imageInfos) {
BufferedImage image = imageInfo.getImage();
String fileName = String.format(
"page-%d-image-%d.png",
pageIndex + 1,
imageIndex++
);
File outputFile = new File(outputDir + fileName);
ImageIO.write(image, "PNG", outputFile);
}
}
System.out.println("图片提取完成,共导出 " + (imageIndex - 1) + " 张图片。");
} finally {
document.dispose();
}
}
}
3. 代码说明
这里没有直接使用简单的 图片-1.png 命名,而是把页码也放进了文件名,例如:
arduino
page-1-image-1.png
page-2-image-3.png
这样做的好处是,后续排查图片来源时更方便。 尤其是 PDF 页数较多时,只用连续编号不太容易判断图片原本属于哪一页。
需要注意的是,提取出来的图片格式在示例中统一保存为 PNG。 如果原 PDF 中图片本身较大,保存为 PNG 后文件体积可能并不会变小。如果只是为了预览或网页展示,也可以根据需求改成 JPG。
例如:
arduino
ImageIO.write(image, "JPG", outputFile);
不过 JPG 是有损格式,适合照片类图片,不太适合文字截图、表格截图或带透明背景的图片。
三、压缩 PDF 中的图片
1. 适用场景
PDF 文件过大时,图片通常是主要原因之一。比如:
- 扫描件分辨率过高;
- 报告中插入了大量高清图片;
- 图片没有经过压缩就直接嵌入 PDF;
- 页面内容不多,但 PDF 文件却几十 MB。
这类情况可以尝试压缩 PDF 中的图片,从而减小整个 PDF 文件体积。
不过要注意,图片压缩通常会带来一定清晰度损失。 如果 PDF 用于打印、归档或正式交付,建议先备份原文件,再对副本进行压缩。
2. 示例代码
ini
import com.spire.pdf.FileFormat;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.utilities.PdfImageHelper;
import com.spire.pdf.utilities.PdfImageInfo;
import java.io.File;
public class CompressPdfImages {
public static void main(String[] args) {
String inputPdf = "C:/pdf/input.pdf";
String outputPdf = "C:/pdf/output-compressed.pdf";
PdfDocument document = new PdfDocument();
try {
// 加载 PDF 文件
document.loadFromFile(inputPdf);
// 关闭增量更新,避免保存后文件体积异常增大
document.getFileInfo().setIncrementalUpdate(false);
PdfImageHelper imageHelper = new PdfImageHelper();
// 遍历每一页,对页面中的图片进行压缩
for (int pageIndex = 0; pageIndex < document.getPages().getCount(); pageIndex++) {
PdfPageBase page = document.getPages().get(pageIndex);
PdfImageInfo[] imageInfos = imageHelper.getImagesInfo(page);
for (PdfImageInfo imageInfo : imageInfos) {
imageInfo.tryCompressImage();
}
}
// 保存压缩后的 PDF
document.saveToFile(outputPdf, FileFormat.PDF);
printFileSize(inputPdf, outputPdf);
} finally {
document.dispose();
}
}
private static void printFileSize(String beforePath, String afterPath) {
File before = new File(beforePath);
File after = new File(afterPath);
double beforeMb = before.length() / 1024.0 / 1024.0;
double afterMb = after.length() / 1024.0 / 1024.0;
System.out.printf("压缩前:%.2f MB%n", beforeMb);
System.out.printf("压缩后:%.2f MB%n", afterMb);
}
}
四、关于 setIncrementalUpdate(false) 的说明
压缩 PDF 时,代码里有一行:
javascript
document.getFileInfo().setIncrementalUpdate(false);
这一步建议保留。
PDF 保存时可能会使用增量更新机制,也就是在原文件后面追加修改内容,而不是完全重写整个文件。 这种方式适合部分编辑场景,但在压缩图片时,可能导致旧数据仍然保留在文件中,最终出现"明明压缩了,文件却没有明显变小"的情况。
所以在压缩 PDF 图片时,可以关闭增量更新,让保存结果更符合预期。
五、提取和压缩的区别
虽然两个功能都和 PDF 图片有关,但它们解决的问题不同。
| 操作 | 目的 | 输出结果 |
|---|---|---|
| 提取图片 | 把 PDF 中的图片单独导出 | 多个图片文件 |
| 压缩图片 | 减小 PDF 中图片占用空间 | 一个新的 PDF 文件 |
简单理解:
- 想拿到 PDF 里的图片,用"提取";
- 想让 PDF 文件变小,用"压缩"。
六、常见问题
1. 为什么有些 PDF 提取不到图片?
并不是所有看起来像图片的内容都一定是图片对象。
例如:
- 页面内容可能是矢量图;
- 文字和图形可能是由绘制指令组成;
- 扫描件可能整页就是一张大图;
- 某些 PDF 的图片可能经过特殊编码或封装。
所以实际项目中要根据 PDF 来源测试,不能只用一个样例判断兼容性。
2. 压缩后文件体积没有明显变化怎么办?
可能有几种原因:
- PDF 主要体积不在图片,而在字体、附件或其他资源;
- 图片本身已经被压缩过;
- 图片数量不多;
- 原 PDF 保存结构比较特殊;
- 压缩比例有限,变化不明显。
建议压缩前后对比文件大小,并尽量使用真实业务文件测试。
3. 压缩会不会影响图片清晰度?
有可能会。
图片压缩的目标是减少文件体积,通常会在一定程度上影响图片质量。 如果 PDF 需要打印、盖章、归档,建议不要直接覆盖原文件,而是输出一个新的压缩版本。
七、总结
本文使用 Java 演示了两个常见 PDF 图片处理需求:
- 使用
PdfImageHelper.getImagesInfo()获取 PDF 页面中的图片信息; - 使用
PdfImageInfo.getImage()提取图片; - 使用
PdfImageInfo.tryCompressImage()压缩 PDF 中的图片; - 保存 PDF 时关闭增量更新,避免压缩结果不明显。
在实际业务中,建议把"提取图片"和"压缩 PDF"封装成独立工具方法,并增加文件大小校验、异常处理、目录检查等逻辑。 这样无论是做文档归档、附件处理,还是后台批量压缩 PDF,都更容易复用。