You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Apache POI替换Word指定图片为自定义生成图片

问题描述
  • 基于Apache POI编写Word文档图片替换逻辑时,现有代码会无差别替换文档内所有嵌入图片,无法精准选中目标图片替换,导致非占位图片被错误覆盖为生成的二维码。
  • 替换前文档效果:
    图片替换前的Word文档
  • 错误替换后的文档效果:
    图片替换后的Word文档
原有问题代码
private void findImages(XWPFParagraph p) {
    for (XWPFRun r : p.getRuns()) {
        for (XWPFPicture pic : r.getEmbeddedPictures()) {
            XWPFPicture picture = pic;
                XWPFPictureData source = picture.getPictureData();
                BufferedImage qrCodeImage = printVersionService.generateQRCodeImage("JASAW EMA WWS");
                File imageFile = new File("image.jpg");
                try {
                    ImageIO.write(qrCodeImage, "jpg", imageFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try ( FileInputStream in = new FileInputStream(imageFile);
                      OutputStream out = source.getPackagePart().getOutputStream();
                ) {
                    byte[] buffer = new byte[2048];
                    int length;
                    while ((length = in.read(buffer)) > 0) {
                        out.write(buffer, 0, length);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
        }
     }
}
核心诉求
  • 实现仅替换指定目标图片,不影响文档内其他非目标图片
  • 支持识别带自定义标识的占位图形,将其替换为自定义函数生成的图片
实现方案

问题根源是原有逻辑遍历到任意嵌入图片就直接覆盖图片数据流,没有加身份校验逻辑。要实现精准替换,按以下步骤操作即可:

  • 给占位图加唯一识别标记
    制作Word模板时,给需要替换的占位图片设置可选文字(Alt文本)作为唯一标识,比如给二维码占位图统一设置可选文字为QR_CODE_PLACEHOLDER。该标识不会在文档正常浏览时显示,POI可直接读取识别。
    设置路径:Word中右键点击占位图片 -> 选择「查看Alt文本」/「大小和属性」-> 在可选文字的说明栏填入自定义的唯一标识即可。
  • 替换逻辑增加标识校验,仅替换匹配到标记的图片
    遍历图片时先读取图片的可选文字,和预设的占位标识匹配成功后再执行替换操作,同时注意覆盖数据流前先清空原有内容,避免新旧图片内容拼接导致文件损坏。修正后的代码如下:
private void findImages(XWPFParagraph p) {
    // 此处标识和模板中给占位图设置的可选文字保持一致
    final String TARGET_MARK = "QR_CODE_PLACEHOLDER";
    for (XWPFRun r : p.getRuns()) {
        for (XWPFPicture pic : r.getEmbeddedPictures()) {
            // 读取当前图片的描述文本(即可选文字)
            String picDesc = pic.getDescription();
            // 非目标图片直接跳过,不做处理
            if (picDesc == null || !picDesc.trim().equals(TARGET_MARK)) {
                continue;
            }

            // 匹配到目标占位图,执行替换逻辑
            XWPFPictureData sourceData = pic.getPictureData();
            BufferedImage qrCodeImage = printVersionService.generateQRCodeImage("JASAW EMA WWS");
            File tempImageFile = new File("temp_qr.jpg");
            try {
                ImageIO.write(qrCodeImage, "jpg", tempImageFile);
            } catch (IOException e) {
                e.printStackTrace();
            }

            try (FileInputStream in = new FileInputStream(tempImageFile);
                 OutputStream out = sourceData.getPackagePart().getOutputStream()) {
                // 清空原有图片的数据流,避免残留旧内容导致图片损坏
                out.flush();
                byte[] buffer = new byte[2048];
                int readLength;
                while ((readLength = in.read(buffer)) > 0) {
                    out.write(buffer, 0, readLength);
                }
                // 替换完成后删除临时文件
                tempImageFile.delete();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}

补充:如果之前是用文本占位符(比如{{QR_IMG}})标记图片位置,也可以先遍历段落文本匹配占位符,删除占位文本和相邻的临时占位图后,在对应run位置插入新生成的图片即可。但用图片可选文字做标记的方案实现成本更低,也不容易打乱原有文档格式。


内容的提问来源于stack exchange,提问作者Beigut Beisenkhan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 01:18:24