Java 批量提取 Word 文档中的图片并保存到本地

在处理 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,也不涉及图片格式转换,适合用于文档图片整理和自动化处理。

相关推荐
SL_staff36 分钟前
BI项目失败率90%?JVS如何用三阶闭环构建可落地的数据生产力平台
java·开源·全栈
nice_lcj5202 小时前
ThreadLocal 入门:它是怎么隔离数据的、为什么会导致内存泄漏
java·开发语言·后端·面试·并发编程·内存泄漏·threadlocal
秋天的怀念_David2 小时前
算法一千零一夜 · 第二十六夜 协议的母语
java·spring boot·算法
灿飞2 小时前
Kotlin与Java虚拟机八:控制流与 when:卫语句、上下文相关解析与穷尽性
java·kotlin
文丑颜不良啊3 小时前
LeetCode2021~2040题目解析
java·leetcode
bksczm3 小时前
InnoDB 行格式详解:DYNAMIC / COMPACT / COMPRESSED / REDUNDANT
java·开发语言·数据库
liangbo74 小时前
Spring系列03:Bean 的三种注册方式
java·spring
余槐i4 小时前
MySQL 8.0 联合索引走错:为什么加了索引查询反而从 200ms 变成 8s
java·spring boot·mysql·docker·性能优化
SL_staff4 小时前
制造业订单交付总在最后一刻爆雷?用结构化计划模板打通跨系统协同断点
java·开源·全栈