Java使用EasyExcel导出图片(原比例大小)到Excel中

server/2024/9/23 6:19:34/

EasyExcel导出图片

又开始写Excel导出的需求了,哈哈哈……

目前的需求是将图表分析对的饼图和折线图,也就是一张完整的图片单独导出到Excel中

为了方便客户在业务报告时,可以使用数据分析图片,从而更清晰准确地展示数据趋势

因此关键点是将图片原比例尺寸大小导出,不能进行压缩

原数据是由图表📈+表格数据组成,下图所示:

现在需要将上述数据,分两个Sheet导出到Excel:图表📈Sheet +表格数据Sheet

关于表格数据导出,此处就不做展示了,往期的Excel导出有文章说明,此文只导出图表📈Sheet

步骤1:将图片保存成url

将图片转为url的形式传参

{"imagePath": "http://www.echola.com/8pJTiC_1724644117200.png",…… //其他参数
}

步骤2:自定义图片导出工具类

@Slf4j
public class CustomImageStrategy implements CellWriteHandler {private final HashMap<String, List<ImageData>> imageDataMap = new HashMap<>(16);@Overridepublic void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData<?> cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {if (isHead) {return;}// 将单元格图片数据复制出来,清空单元格图片数据if (!CollectionUtils.isEmpty(cellData.getImageDataList())) {imageDataMap.put(cell.getRowIndex() + "_" + cell.getColumnIndex(), cellData.getImageDataList());cellData.setType(CellDataTypeEnum.EMPTY);cellData.setImageDataList(new ArrayList<>());}}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {if (isHead || CollectionUtils.isEmpty(cellDataList)) {return;}String key = cell.getRowIndex() + "_" + cell.getColumnIndex();List<ImageData> imageDataList = imageDataMap.get(key);if (CollectionUtils.isEmpty(imageDataList)) {return;}// 插入图片for (int i = 0; i < imageDataList.size(); i++) {ImageData imageData = imageDataList.get(i);if (ObjectUtils.isEmpty(imageData)) {continue;}byte[] image = imageData.getImage();this.insertImage(writeSheetHolder.getSheet(), cell, image, i);}imageDataMap.remove(key);}private void insertImage(Sheet sheet, Cell cell, byte[] pictureData, int i) {// 读取图片的宽度和高度int pictureWidth = 0;int pictureHeight = 0;try (ByteArrayInputStream bis = new ByteArrayInputStream(pictureData)) {BufferedImage bufferedImage = ImageIO.read(bis);pictureWidth = bufferedImage.getWidth();pictureHeight = bufferedImage.getHeight();} catch (Exception e) {log.error("Error reading image dimensions", e);}// 将像素转换为 EMU 单位int emuWidth = Units.pixelToEMU(pictureWidth);int emuHeight = Units.pixelToEMU(pictureHeight);int index = sheet.getWorkbook().addPicture(pictureData, Workbook.PICTURE_TYPE_PNG);Drawing<?> drawing = sheet.getDrawingPatriarch();if (drawing == null) {drawing = sheet.createDrawingPatriarch();}CreationHelper helper = sheet.getWorkbook().getCreationHelper();ClientAnchor anchor = helper.createClientAnchor();// 设置图片在哪个单元格中anchor.setCol1(cell.getColumnIndex());anchor.setCol2(cell.getColumnIndex() + 1);anchor.setRow1(cell.getRowIndex());anchor.setRow2(cell.getRowIndex() + 1);// 设置图片在单元格中的位置// 横向偏移量anchor.setDx1(0);anchor.setDx2(emuWidth);// 纵向偏移量anchor.setDy1(0);anchor.setDy2(emuHeight);// 设置图片可以随着单元格移动anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);drawing.createPicture(anchor, index);// 设置行高和列宽为图片的实际大小Row row = sheet.getRow(cell.getRowIndex());if (row == null) {row = sheet.createRow(cell.getRowIndex());}// 设置行高,1像素大约等于0.75点float maxRowHeight = 300;float imageHeight = (float) (pictureHeight * 0.75);row.setHeightInPoints(Math.min(imageHeight, maxRowHeight));// 设置列宽,列宽单位是1/256个字符,1个字符大约为7像素int maxColumnWidth = 255 * 256;int imageWidth = pictureWidth * 37;sheet.setColumnWidth(cell.getColumnIndex(), Math.min(imageWidth, maxColumnWidth));}

调试过程中,出了一点小问题,出了这个异常:

The maximum column width for an individual cell is 255 characters

由于图片宽度过大,导致超过了Excel单元格的最大宽度255,因此需要兼容最大行高和列宽

原代码段是:

 // 设置行高,1像素大约等于0.75点
row.setHeightInPoints((float) (pictureHeight * 0.75));// 设置列宽,列宽单位是1/256个字符,1个字符大约为7像素
sheet.setColumnWidth(cell.getColumnIndex(), pictureWidth * 37);

修改后代码段:

// 设置行高,1像素大约等于0.75点
float maxRowHeight = 300;
float imageHeight = (float) (pictureHeight * 0.75);
row.setHeightInPoints(Math.min(imageHeight, maxRowHeight));// 设置列宽,列宽单位是1/256个字符,1个字符大约为7像素
int maxColumnWidth = 255 * 256;
int imageWidth = pictureWidth * 37;
sheet.setColumnWidth(cell.getColumnIndex(), Math.min(imageWidth, maxColumnWidth));

步骤3:导出图片

public void exportAnalysis(EnergyStatisticDTO param, HttpServletResponse response) {String fileName = "数据分析" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);try {EasyExcelUtils.setResponse(response, fileName);ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();//各用电用途趋势String sheetName = "数据分析图示";this.meterImageSheet(sheetName, param.getImagePath(), excelWriter);String imagePath = param.getImagePath();if (StringUtils.isEmpty(imagePath)) return;//支持多图片导出,此处只是单图片List<ImageDTO> imageList = new ArrayList<>();ImageDTO imageDTO = new ImageDTO();imageDTO.setImageUrl(Collections.singletonList(imagePath));imageList.add(imageDTO);WriteSheet imageSheet = EasyExcel.writerSheet(1, sheetName).registerWriteHandler(new CustomImageStrategy()).build();excelWriter.write(imageList, imageSheet);excelWriter.finish();} catch (Exception e) {log.error("数据分析:{}", e.getMessage());}}

Excel导出图片效果图

可以看出和Web的图表的大小是基本一致的

撒花完结……


http://www.ppmy.cn/server/108392.html

相关文章

Java 集合之List

一、集合常用API 1.添加相关的方法 add(E e) 确保此collection包含指定的元素&#xff08;可选操作&#xff09; addAll(Collection<? extends E> c) 将指定集合中的元素都添加到此集合中&#xff08;可选操作&#xff09; 2.删除相关的方法 clear() 移除这个…

深度学习500问——Chapter13:优化算法(1)

文章目录 13.1 如何解决训练样本少的问题 13.2 深度学习是否能胜任所有数据集 13.3 有没有可能找到比已知算法更好的算法 13.4 什么是共线性&#xff0c;如何判断和解决共线性问题 13.5 权值初始化方法有哪些 13.6 如何防止梯度下降陷入局部最优解 13.7 为什么需要激活函数 13.…

LabVIEW中10μs方波生成问题

在LabVIEW中使用NI PCIe-6353卡生成并控制10μs级别的方波输出可能遇到频率调整的问题。下面将详细分析常见问题的原因&#xff0c;如采样率设置、时钟源配置、波形生成方式等&#xff0c;并提供具体的解决方案&#xff0c;帮助用户成功生成并调整高精度方波信号。 为了在LabVI…

神州数码半年业绩双增长,AI驱动数云服务及软件业务增长62.7%

发布 | 大力财经 8月30日晚间&#xff0c;神州数码集团&#xff08;000034.SZ&#xff09;发布2024年度中期业绩报告。 报告期内&#xff0c;神州数码营业收入实现625.6亿元&#xff0c;同比增长12.5%&#xff1b;归母净利润实现5.1亿元&#xff0c;同比增长17.5%&#xff1b…

国产SRAM存储芯片替代方案

为满足客户对更大更快的SRAM 的普遍需求&#xff0c;伟凌创芯SRAM产品线&#xff0c;容量最高可达64Mb。产品线包括提供256Kb~64Mb不同容量的器件&#xff0c;为传统的并行SRAM产品提供成本更低的替代方案&#xff0c;并在SRAM存储器中包含可选的电池备份切换电路&#xff0c;以…

【C++】如何解决“pointer to incomplete class type is not allowed”。

这个错误信息 “pointer to incomplete class type is not allowed” 在 C 中通常表示你正在尝试使用一个尚未完全定义的类的指针。 可能的原因及解决方法如下&#xff1a; 一、类定义不完整 前向声明后就使用指针&#xff1a; 如果你只是对一个类进行了前向声明&#xff08…

【Qt】Spacer

Spacer 在使用布局管理的时候&#xff0c;如果需要在控件之间添加一段空白&#xff0c;就可以使用QSpacerItem来表示。 核心属性 属性说明 width 宽度 height ⾼度 hData ⽔平⽅向的 sizePolicy QSizePolicy::Ignored : 忽略控件的尺⼨&#xff0c;不对布局产⽣影响。 QS…

通过C# 读取PDF页面大小、方向、旋转角度

在处理PDF文件时&#xff0c;了解页面的大小、方向和旋转角度等信息对于PDF的显示、打印和布局设计至关重要。本文将介绍如何使用免费.NET 库通过C#来读取PDF页面的这些属性。 文章目录 C# 读取PDF页面大小&#xff08;宽度、高度&#xff09;C# 判断PDF页面方向C# 检测PDF页面…