杰瑞科技汇

Java如何将图片导出到Word文档?

核心思路

无论使用哪种库,基本思路都是相似的:

Java如何将图片导出到Word文档?-图1
(图片来源网络,侵删)
  1. 创建/加载 Word 文档:创建一个新文档对象,或者加载一个已有的 Word 模板。
  2. 获取文档的“身体”:Word 文档的内容主要存储在 Document 对象的 Body 中。
  3. 创建图片对象:将本地的图片文件(如 logo.png)读取成一个库可以识别的图片对象(如 XWPFPictureData)。
  4. 将图片添加到段落:在 Word 中,图片通常是作为一个段落元素存在的,所以你需要创建一个段落,然后将图片对象添加到这个段落中。
  5. 设置图片属性(可选):可以设置图片的大小、位置、环绕方式等。
  6. 保存文档:将操作后的 Document 对象保存为一个 .docx 文件。

使用 Apache POI (推荐)

Apache POI 是 Java 操作 Office 文档最强大、最流行的开源库,它支持处理 .xls, .docx 等格式,对于 Word 文档,我们主要使用 POI-OOXML 模块。

优点

  • 功能全面:不仅能插入图片,还能创建复杂的表格、样式、页眉页脚等。
  • 社区活跃:遇到问题容易找到解决方案。
  • 行业标准:是 Java 生态中处理 Office 文档的首选。

缺点

  • API 相对复杂,学习曲线较陡峭。
  • 对于简单的图片插入,代码量会多一些。

Maven 依赖

在你的 pom.xml 文件中添加以下依赖:

Java如何将图片导出到Word文档?-图2
(图片来源网络,侵删)
<dependencies>
    <!-- Apache POI for Word -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.3</version> <!-- 建议使用较新版本 -->
    </dependency>
    <!-- 为了支持 XWPF 相关类,还需要这个依赖 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>ooxml-schemas</artifactId>
        <version>1.4</version>
    </dependency>
</dependencies>

代码示例:插入图片到新文档

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ApachePoiImageToWord {
    public static void main(String[] args) {
        // 1. 创建一个新的 XWPFDocument 对象
        try (XWPFDocument document = new XWPFDocument()) {
            // 2. 创建一个段落
            XWPFParagraph paragraph = document.createParagraph();
            XWPFRun run = paragraph.createRun();
            // 3. 设置图片路径
            String imagePath = "path/to/your/image.png"; // 替换为你的图片路径
            // 4. 将图片添加到段落中
            // Units 类提供了像素、英寸、厘米等单位与 EMU (English Metric Unit) 的转换
            // EMU 是 Office 内部使用的单位,1 英寸 = 914400 EMU
            int width = Units.toEMU(300); // 图片宽度,300像素
            int height = Units.toEMU(200); // 图片高度,200像素
            run.addPicture(new FileInputStream(imagePath), 
                           XWPFDocument.PICTURE_TYPE_PNG, 
                           "image.png", 
                           width, 
                           height);
            // 5. 保存文档
            try (FileOutputStream out = new FileOutputStream("ApachePoi_Image_Document.docx")) {
                document.write(out);
            }
            System.out.println("图片成功插入到 Word 文档!");
        } catch (IOException | InvalidFormatException e) {
            e.printStackTrace();
        }
    }
}

代码示例:在指定位置插入图片(使用占位符)

如果需要在模板的特定位置插入图片,可以在 Word 模板中插入一个书签,然后在 Java 代码中定位到该书签。

  1. 创建模板 template.docx

    • 在 Word 中打开一个空白文档。
    • 输入一些文字,"这里是公司Logo:"。
    • 在要插入图片的位置,点击 插入 -> 链接 -> 书签...,输入一个名字,logoBookmark,然后点击 添加
    • 保存为 template.docx
  2. Java 代码

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ApachePoiImageToBookmark {
    public static void main(String[] args) {
        String templatePath = "path/to/your/template.docx";
        String imagePath = "path/to/your/image.png";
        String outputPath = "ApachePoi_Image_To_Bookmark.docx";
        try (FileInputStream fis = new FileInputStream(templatePath);
             XWPFDocument document = new XWPFDocument(fis)) {
            // 遍历所有段落,查找书签
            for (XWPFParagraph p : document.getParagraphs()) {
                for (XWPFRun r : p.getRuns()) {
                    // 获取 run 中的文本
                    String text = r.getText(0);
                    if (text != null && text.contains("logoBookmark")) {
                        // 替换书签文本为图片
                        r.setText("", 0); // 清空原有文本
                        r.addPicture(new FileInputStream(imagePath),
                                     XWPFDocument.PICTURE_TYPE_PNG,
                                     "logo.png",
                                     Units.toEMU(200),
                                     Units.toEMU(100));
                    }
                }
            }
            // 保存新文档
            try (FileOutputStream out = new FileOutputStream(outputPath)) {
                document.write(out);
            }
            System.out.println("图片已根据书签成功插入!");
        } catch (IOException | InvalidFormatException e) {
            e.printStackTrace();
        }
    }
}

注意:这种方法比较简单,如果书签在表格或页眉页脚中,需要额外处理,更精确的方法是使用 document.getBookmark(bookmarkName),但 POI 对此的支持可能不如直接遍历稳定。

Java如何将图片导出到Word文档?-图3
(图片来源网络,侵删)

使用 docx4j

docx4j 是另一个功能强大的开源库,专门用于处理 Office Open XML 格式(即 .docx, .xlsx 等),它的 API 设计上比 POI 更面向对象,在某些场景下可能更直观。

优点

  • API 设计清晰,对 OOXML 结构的映射更直接。
  • 功能同样非常强大,在处理复杂文档时表现优异。

缺点

  • 相比 POI,社区规模稍小。
  • 许可证与 POI 不同,需要注意商业使用。

Maven 依赖

<dependencies>
    <!-- docx4j core -->
    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-core</artifactId>
        <version>11.4.4</version> <!-- 建议使用较新版本 -->
    </dependency>
    <!-- 用于处理 OOXML -->
    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-export-ooxml</artifactId>
        <version>11.4.4</version>
    </dependency>
</dependencies>

代码示例:插入图片到新文档

import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import java.io.File;
import java.math.BigInteger;
public class Docx4jImageToWord {
    public static void main(String[] args) {
        try {
            // 1. 创建一个新的 WordprocessingMLPackage 对象
            WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
            // 2. 获取主文档部分
            MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
            // 3. 创建一个段落对象
            P paragraph = objectFactory.createP();
            // 4. 创建一个运行对象
            R run = objectFactory.createR();
            // 5. 创建一个图片对象
            Inline inline = objectFactory.createInline();
            // 设置图片关系 ID
            String imageId = documentPart.addImage(new File("path/to/your/image.png"));
            // 设置图片数据
            Blip blip = objectFactory.createBlip();
            blip.setEmbed(imageId);
            // 设置图片尺寸
            // docx4j 使用 EMU 单位
            long widthEmu = 1828800L; // 200像素 (200 * 914400 / 100)
            long heightEmu = 1371600L; // 150像素 (150 * 914400 / 100)
            // 设置图片扩展属性
            Extent extent = objectFactory.createExtent();
            extent.setCx(BigInteger.valueOf(widthEmu));
            extent.setCy(BigInteger.valueOf(heightEmu));
            // 设置图片非视觉属性
            NVpr nvpr = objectFactory.createNVpr();
            // 可以设置图片名称等
            // 组装图片对象
            inline.setBlip(blip);
            inline.setExtent(extent);
            inline.setNvpr(nvpr);
            // 将图片对象添加到运行中
            run.getContent().add(inline);
            // 将运行添加到段落中
            paragraph.getContent().add(run);
            // 将段落添加到文档中
            documentPart.getContent().add(paragraph);
            // 6. 保存文档
            wordMLPackage.save(new File("Docx4j_Image_Document.docx"));
            System.out.println("docx4j 图片插入成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 为了方便,创建一个 ObjectFactory 实例
    private static final ObjectFactory objectFactory = new ObjectFactory();
}

注意:docx4j 的代码看起来更冗长,因为它直接构建了 XML 结构,但这也意味着你对文档结构的控制力更强。


使用 iText (商业/AGPL 许可)

iText 是一个非常著名的 PDF 库,但它也提供了处理 Word 文档(.docx)的功能,即 iText 7 for Office。

优点

  • 如果你的项目已经在使用 iText 7,可以无缝集成。
  • API 现代化,基于 PdfPCell 等概念。

缺点

  • 许可证问题:iText 7 的 AGPL v3 许可证对于闭源的商业项目是“有毒”的,如果你修改了 iText 的源代码,你的项目也必须开源,商业使用需要购买商业许可证,这是选择它时最大的考量点。

Maven 依赖

<dependencies>
    <!-- iText 7 Core -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext7-core</artifactId>
        <version>7.2.5</version> <!-- 建议使用较新版本 -->
        <type>pom</type>
    </dependency>
    <!-- iText 7 for Office -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext-7</artifactId>
        <version>4.0.3</version>
    </dependency>
</dependencies>

代码示例:插入图片到新文档

import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.tool.xmlpipeline.html.HtmlPipelineContext;
import com.itextpdf.tool.xml.pipeline.html.AbstractTagProcessorFactory;
import com.itextpdf.tool.xml.pipeline.end.PdfPipeline;
import com.itextpdf.tool.xml.html.Tags;
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
import com.itextpdf.tool.xml.css.CssFile;
import com.itextpdf.tool.xml.css.StyleSheet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ITextImageToWord {
    public static void main(String[] args) {
        String dest = "iText_Image_Document.docx";
        String imgPath = "path/to/your/image.png";
        try {
            // iText 7 for Word 的处理方式与 PDF 略有不同
            // 通常需要先构建一个 HTML 字符串,然后转换
            // 这是一个简化的示例
            // 创建一个 Document 对象
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
            Document doc = new Document(pdfDoc);
            // 加载图片
            ImageData data = ImageDataFactory.create(imgPath);
            Image img = new Image(data);
            // 设置图片大小
            img.scaleToFit(300, 200); // 按比例缩放,最大宽度300,最大高度200
            // 将图片添加到文档
            doc.add(img);
            // 关闭文档
            doc.close();
            System.out.println("iText 图片插入成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:上面的例子实际上生成了 PDF,对于真正的 .docx 文件,iText 7 的处理方式更复杂,通常涉及使用 HtmlConverter 将 HTML 内容转换为 Word,或者直接操作其底层的 docx 库,对于纯图片插入,POI 和 docx4j 更直接。


总结与对比

特性 Apache POI docx4j iText 7
许可证 Apache 2.0 (宽松) LGPL v2.1 (较宽松) AGPL v3 (严格)
易用性 中等,API 较老但文档多 中等,API 更面向对象 高 (如果你熟悉 iText)
功能 非常全面 非常全面 强大,但侧重 PDF
社区 非常活跃 活跃 活跃
推荐场景 首选方案,几乎所有 Java 处理 Office 的场景。 POI 的一个优秀替代品,尤其在需要精细控制 XML 结构时。 如果项目已深度使用 iText,且不介意许可证问题。

最终建议

对于绝大多数 Java 项目,强烈推荐使用 Apache POI,它拥有最广泛的社区支持、最丰富的功能集和最灵活的许可证,虽然它的 API 可能不是最现代的,但它的稳定性和可靠性已经经过了长时间的考验。

如果你的项目对许可证有特殊要求,或者你对 POI 的 API 不太满意,docx4j 是一个非常棒的备选方案。

请根据你的项目需求、技术栈和许可证政策来选择最适合你的工具。

分享:
扫描分享到社交APP
上一篇
下一篇