[alibaba/easyexcel]导出excel,其中图片在Microsoft Office正常显示,在WPS Office显示不了。

2024-05-10 526 views
5

导出代码:

ExcelWriterSheetBuilder builder = EasyExcel.write(response.getOutputStream())
          // 默认自动关闭流,出现异常时会返回一个有部分数据的Excel。这里设置不关闭流,由catch处理,返回错误json
          .autoCloseStream(Boolean.FALSE)
          // 单一表
          .sheet(fileName)
          // 表头
          .head(excelHeader)
          // 写策略:自动列宽
          .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy());
      // 注册自定义写策略
      if (!CollectionUtils.isEmpty(writeHandlers)) {
        for (WriteHandler writeHandler : writeHandlers) {
          builder.registerWriteHandler(writeHandler);
        }
      }
      // 写自定义内容
      builder.doWrite(excelContent);

excelContent:fillVehicleFile就是图片

int size = data.size();
if (size == 0) {
  return Collections.emptyList();
}
// 所有行
List<List<Object>> rows = new ArrayList<>(size);
// 一行的所有列
List<Object> columns;
EnterVehicleInfoBo enterVehicleInfoBo;
String fileBaseUrl = Global.getProperty("userfiles.basedir");
File file;
SysFile sysFile;
Object fillVehicleFile = "加载失败";
for (int i = 0; i < size; i++) {
  enterVehicleInfoBo = data.get(i);
  columns = new ArrayList<>(10);
  columns.add(String.valueOf(i + 1));
  columns.add(enterVehicleInfoBo.getVehicleNum());
  columns.add(enterVehicleInfoBo.getVehicleName());
  columns.add(enterVehicleInfoBo.getCarOwnerName());
  columns.add(enterVehicleInfoBo.getCarOwnerPhone());
  columns.add(enterVehicleInfoBo.getCurrentWeight().toPlainString());
  columns.add(enterVehicleInfoBo.getOriginalWeight().toPlainString());
  // 填充行驶证图片
  sysFile = enterVehicleInfoBo.getVehicleFile();
  if (sysFile != null) {
    file = new File(fileBaseUrl + sysFile.getFilePath());
    if (file.exists()) {
      fillVehicleFile = file;
    }
  }
  columns.add(fillVehicleFile);
  columns.add(enterVehicleInfoBo.getCreateBy());
  columns.add(DateUtil.format(enterVehicleInfoBo.getCreateDate()));
  rows.add(columns);
}
return rows;

Microsoft Office显示效果:

Snipaste_2022-07-04_17-57-10

WPS Office显示效果:

Snipaste_2022-07-04_17-56-53

Microsoft Office图片另存后显示效果:纯黑

Snipaste_2022-07-04_18-09-15

回答

4

我也遇到这个问题,后来解决了吗?

0

我也遇到这个问题,后来解决了吗?

还没有呢,没有头绪。

1

我也碰到这个问题了,目前发现是因为drawing.xml文件少了standalone="yes"标签导致的

把excel解压,在对应的drawing.xml头部插入standalone="yes"标签,在压缩回xlsx后图片就可以正常展示了,但是我不知道怎么通过easyexcel来实现这个 image

5

我也碰到这个问题了,目前发现是因为drawing.xml文件少了standalone="yes"标签导致的

把excel解压,在对应的drawing.xml头部插入standalone="yes"标签,在压缩回xlsx后图片就可以正常展示了,但是我不知道怎么通过easyexcel来实现这个 image

我后来又进行了一些验证,发现根本原因不是因为修改了drawing.xml文件,只要把xlsx解压,然后在压缩回xlsx就可以让图片显示,感觉应该是easyexcel打包时的问题

4

我也碰到这个问题了,目前发现是因为drawing.xml文件少了standalone="yes"标签导致的 把excel解压,在对应的drawing.xml头部插入standalone="yes"标签,在压缩回xlsx后图片就可以正常展示了,但是我不知道怎么通过easyexcel来实现这个 image

我后来又进行了一些验证,发现根本原因不是因为修改了drawing.xml文件,只要把xlsx解压,然后在压缩回xlsx就可以让图片显示,感觉应该是easyexcel打包时的问题

说一下我得解决办法吧,基于上面的进度最后还是基于解压在压缩的思路实现的 将生成好的excel文件路径传入该方法即可,如果是基于文件流的可以自己封装zipinputstream

public static void easyExcelRepairPic(String excelPath) {
        File file = new File(excelPath);
        if (!file.isFile()) {
            throw new RuntimeException("excel文件不存在");
        }
        if (!excelPath.endsWith(".xlsx")) {
            throw new RuntimeException("文件格式必须为xlsx");
        }

        // 创建解压后的临时目录
        File tempDir = new File(file.getParent(), IdUtil.fastSimpleUUID());
        // 解压源文件到临时目录
        ZipUtil.unzip(file, tempDir);
        // 删除源文件
        FileUtil.del(file);
        // 压缩临时目录 替换源文件
        ZipUtil.zip(tempDir.getPath(), file.getPath());
        // 删除临时目录
        FileUtil.del(tempDir);
    }
4

我也碰到这个问题了,目前发现是因为drawing.xml文件少了standalone="yes"标签导致的 把excel解压,在对应的drawing.xml头部插入standalone="yes"标签,在压缩回xlsx后图片就可以正常展示了,但是我不知道怎么通过easyexcel来实现这个 image

我后来又进行了一些验证,发现根本原因不是因为修改了drawing.xml文件,只要把xlsx解压,然后在压缩回xlsx就可以让图片显示,感觉应该是easyexcel打包时的问题

说一下我得解决办法吧,基于上面的进度最后还是基于解压在压缩的思路实现的 将生成好的excel文件路径传入该方法即可,如果是基于文件流的可以自己封装zipinputstream

public static void easyExcelRepairPic(String excelPath) {
        File file = new File(excelPath);
        if (!file.isFile()) {
            throw new RuntimeException("excel文件不存在");
        }
        if (!excelPath.endsWith(".xlsx")) {
            throw new RuntimeException("文件格式必须为xlsx");
        }

        // 创建解压后的临时目录
        File tempDir = new File(file.getParent(), IdUtil.fastSimpleUUID());
        // 解压源文件到临时目录
        ZipUtil.unzip(file, tempDir);
        // 删除源文件
        FileUtil.del(file);
        // 压缩临时目录 替换源文件
        ZipUtil.zip(tempDir.getPath(), file.getPath());
        // 删除临时目录
        FileUtil.del(tempDir);
    }

成功了,感谢!!

7

我也碰到这个问题了,目前发现是因为drawing.xml文件少了standalone="yes"标签导致的 把excel解压,在对应的drawing.xml头部插入standalone="yes"标签,在压缩回xlsx后图片就可以正常展示了,但是我不知道怎么通过easyexcel来实现这个 image

我后来又进行了一些验证,发现根本原因不是因为修改了drawing.xml文件,只要把xlsx解压,然后在压缩回xlsx就可以让图片显示,感觉应该是easyexcel打包时的问题

说一下我得解决办法吧,基于上面的进度最后还是基于解压在压缩的思路实现的 将生成好的excel文件路径传入该方法即可,如果是基于文件流的可以自己封装zipinputstream

public static void easyExcelRepairPic(String excelPath) {
        File file = new File(excelPath);
        if (!file.isFile()) {
            throw new RuntimeException("excel文件不存在");
        }
        if (!excelPath.endsWith(".xlsx")) {
            throw new RuntimeException("文件格式必须为xlsx");
        }

        // 创建解压后的临时目录
        File tempDir = new File(file.getParent(), IdUtil.fastSimpleUUID());
        // 解压源文件到临时目录
        ZipUtil.unzip(file, tempDir);
        // 删除源文件
        FileUtil.del(file);
        // 压缩临时目录 替换源文件
        ZipUtil.zip(tempDir.getPath(), file.getPath());
        // 删除临时目录
        FileUtil.del(tempDir);
    }

针对这个问题最近有了一些新发现,应该是easyExcel和poi兼容性的问题,easyExcel目前(3.2.1)依赖的poi是4.x版本的,如果poi版本变成5.X就会出现这个问题,我就是项目中手动引入了5.X的poi导致的 还有一点是使用5.X poi 然后开启easyExcel的内存模式 图片也可以正常显示

4

开启easyExcel的内存模式没用哇

5

在使用 maven poi 的时候, 发现 zip64 有兼容问题, poi 5.x 之后默认使用 zip64, 通过 SXSSFWorkbook.setZip64Mode 可以关闭 zip64.

跟这个 issue 可能有关联.