在处理 Word 文档时,有时需要将其中的图片单独提取出来,例如整理技术文档中的截图、收集报告中的插图,或将图片用于其他系统。如果文档只有几张图片,可以手动右键保存;但对于包含大量图片的 Word 文件,逐张操作就比较麻烦了。
本文介绍如何使用 Java 批量提取 Word 文档中的图片,并将它们保存到指定文件夹。整个过程不需要安装 Microsoft Word,也不需要手动解压 DOCX 文件,同时可以处理正文、表格等位置的图片。
一、安装所需依赖
要使用 Java 提取 Word 文档中的图片,需要先添加相应的文档处理依赖。这里选择Spire.Doc for Java,它可以直接读取 Word 文档并获取其中的图片,无需安装 Microsoft Word。
如果使用 Maven 项目,可以在 pom.xml 文件中添加以下仓库和依赖:
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.doc</artifactId>
<version>14.10.6</version>
</dependency>
</dependencies>
二、使用 Java 提取 Word 文档中的图片
实现思路并不复杂:首先加载 Word 文件,然后遍历文档中的对象,找到图片后获取其字节数据,最后将图片保存到本地。
第一步:导入所需的类
首先导入 Word 文档处理、文件读写以及图片格式识别所需的类。
java
import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.*;
import com.spire.doc.interfaces.*;
import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import java.io.*;
import java.nio.file.*;
import java.util.*;
其中,Document 用于加载 Word 文档,DocPicture 表示文档中的图片对象,Java NIO 用于创建文件夹和保存图片。
第二步:加载 Word 文档并创建输出文件夹
使用 Document.loadFromFile() 方法读取需要处理的 Word 文件,并指定图片保存位置。
ini
// 加载 Word 文档
Document document = new Document();
document.loadFromFile("示例文档.docx");
// 创建图片输出文件夹
Path outputDir = Paths.get("提取的图片");
Files.createDirectories(outputDir);
这里使用相对路径,输入文件默认位于程序的工作目录中。如果文件保存在其他位置,也可以指定完整路径。
Files.createDirectories() 会在文件夹不存在时自动创建目录。
第三步:遍历 Word 文档中的图片
Word 文档中的内容并不只有普通段落,还可能包含表格、页眉页脚以及其他嵌套对象。
为了尽可能找到文档中的常规图片,可以使用队列遍历文档对象树,并通过 DocumentObjectType.Picture 判断当前对象是否为图片。
ini
// 创建队列,将文档加入队列
Queue<ICompositeObject> queue = new LinkedList<>();
queue.add(document);
int imageIndex = 1;
while (!queue.isEmpty()) {
ICompositeObject parent = queue.poll();
for (int i = 0; i < parent.getChildObjects().getCount(); i++) {
IDocumentObject child = parent.getChildObjects().get(i);
if (child.getDocumentObjectType() == DocumentObjectType.Picture) {
// 获取图片对象
DocPicture picture = (DocPicture) child;
// 获取图片字节数据
byte[] imageBytes = picture.getImageBytes();
// 后续将图片保存到本地
} else if (child instanceof ICompositeObject) {
// 将嵌套对象加入队列,继续遍历
queue.add((ICompositeObject) child);
}
}
}
与只遍历普通段落相比,这种方式还可以查找表格等嵌套结构中的图片。
其中,getImageBytes() 用于获取图片的字节数据,后续可以直接将这些数据写入文件,而不必重新生成图片。
第四步:将图片保存到本地
获取图片数据后,可以使用 Files.write() 将其保存到指定目录。
需要注意,提取图片时不应直接将所有文件命名为 .jpg 或 .png,因为 Word 文档中可能同时包含多种图片格式。
这里使用 Java 的 ImageIO 识别常见图片格式,再为文件设置对应的扩展名。
ini
// 识别图片格式
String extension = getImageExtension(imageBytes);
// 生成图片文件名
String fileName = "图片_" + imageIndex + "." + extension;
// 将图片保存到指定目录
Files.write(outputDir.resolve(fileName), imageBytes);
imageIndex++;
getImageExtension() 是下面完整示例中定义的辅助方法,只负责识别格式,不会修改或重新编码图片数据。
三、完整 Java 代码
将前面的步骤组合起来,可以得到一个完整的 Word 图片提取程序。
java
import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.*;
import com.spire.doc.interfaces.*;
import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import java.io.*;
import java.nio.file.*;
import java.util.*;
public class ExtractImagesFromWord {
public static void main(String[] args) throws IOException {
// 加载 Word 文档
Document document = new Document();
document.loadFromFile("示例文档.docx");
// 创建图片输出文件夹
Path outputDir = Paths.get("提取的图片");
Files.createDirectories(outputDir);
// 创建队列并加入文档根对象
Queue<ICompositeObject> queue = new LinkedList<>();
queue.add(document);
int imageIndex = 1;
// 遍历 Word 文档中的对象
while (!queue.isEmpty()) {
ICompositeObject parent = queue.poll();
for (int i = 0; i < parent.getChildObjects().getCount(); i++) {
IDocumentObject child = parent.getChildObjects().get(i);
// 判断当前对象是否为图片
if (child.getDocumentObjectType() == DocumentObjectType.Picture) {
DocPicture picture = (DocPicture) child;
// 获取图片字节数据
byte[] imageBytes = picture.getImageBytes();
// 识别图片格式
String extension = getImageExtension(imageBytes);
// 生成图片文件名
String fileName = "图片_" + imageIndex + "." + extension;
// 保存图片
Files.write(outputDir.resolve(fileName), imageBytes);
imageIndex++;
} else if (child instanceof ICompositeObject) {
// 继续遍历嵌套对象
queue.add((ICompositeObject) child);
}
}
}
// 释放文档资源
document.dispose();
System.out.println("图片提取完成,共保存 "
+ (imageIndex - 1) + " 张图片。");
}
// 识别图片格式,避免使用错误的扩展名
private static String getImageExtension(byte[] bytes) throws IOException {
try (ImageInputStream stream = ImageIO.createImageInputStream(
new ByteArrayInputStream(bytes))) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
String format = reader.getFormatName()
.toLowerCase(Locale.ROOT);
if (format.equals("jpeg")) return "jpg";
if (format.equals("tiff")) return "tif";
return format;
} finally {
reader.dispose();
}
}
}
// 无法识别时,保存为二进制文件
return "bin";
}
}
运行结果
假设输入的 Word 文档中包含多张 JPG、PNG 和 GIF 图片。
执行程序后,会在指定的输出文件夹中得到类似以下文件:
markdown
提取的图片/
图片_1.png
图片_2.jpg
图片_3.png
图片_4.gif
控制台输出:
图片提取完成,共保存 4 张图片。
图片会按照遍历过程中发现的顺序依次编号,避免因文件名相同而相互覆盖。
由于代码直接保存获取到的图片字节数据,没有进行缩放、压缩或格式转换,因此不会因额外的图像编码而降低图片质量。
四、常见问题
1. 这段代码支持 DOC 和 DOCX 文件吗?
支持。Spire.Doc for Java 可以读取 .doc 和 .docx 格式的 Word 文档。
只需要在 loadFromFile() 方法中指定相应的文件路径,例如:
javascript
document.loadFromFile("示例文档.doc");
其他图片提取逻辑不需要修改。
2. 为什么某些提取的图片是 BIN 格式?
Java 内置的 ImageIO 可以识别 JPG、PNG、GIF、BMP 等常见图片格式,但并不支持所有图像类型。
例如,Word 文档中可能包含 EMF、WMF 等矢量图像,而 Java 默认的图片读取器可能无法识别这些格式。
对于无法识别的图片,示例程序会使用 .bin 扩展名保存图片数据,避免将它们错误地命名为 JPG 或 PNG。
如果需要识别这些特殊格式,可以根据图片文件头进一步判断其真实类型。
3. 为什么有些图形没有被提取?
Word 文档中的图片和图形并不完全相同。
普通插入图片通常属于 DocPicture 对象,而文本框、图表、SmartArt 及某些形状可能使用其他对象类型存储。
本文主要提取 DocPicture 类型的图片。如果需要导出 Word 中的图表、形状或其他绘图对象,则需要针对这些对象进行额外处理。
总结
使用 Java 提取 Word 文档中的图片,可以省去逐张复制、保存的操作,尤其适合处理包含大量插图的报告、产品手册和技术文档。
本文通过遍历 Word 文档对象,定位图片并获取其字节数据,再将图片批量保存到本地。整个过程不需要 Microsoft Word,也不涉及图片格式转换,适合用于文档图片整理和自动化处理。