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

news2024/9/26 19:50:27

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);

    @Override
    public 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<>());
        }
    }

    @Override
    public 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点
        row.setHeightInPoints((float) (pictureHeight * 0.75));

        // 设置列宽,列宽单位是1/256个字符,1个字符大约为7像素
        sheet.setColumnWidth(cell.getColumnIndex(), pictureWidth * 37);
    }

步骤3:导出图片

入参:

{
  "imagePath": "http://business-center.oss-cn-shenzhen.aliyuncs.com/8pJTiC_1724644117200.png",
   …… //其他参数
}
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.coloradmin.cn/o/2077274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++学习笔记】数据类型与运算符(一)

目录 一、常量与变量 1.1 常量 字面常量 符号常量 1.2 变量 1.3 标识符命名规范 二、数据类型 2.1 整型 2.2 实型&#xff08;浮点型&#xff09; 2.3 字符型 2.4 字符串 2.5 布尔型 三、cin控制台输入 3.1 输入代码 3.2 解决输入中文乱码 四、运算符 4.1 算术…

OpenCV杂项图像变换(1)自适应阈值处理函数adaptiveThreshold()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 函数对数组应用自适应阈值。 该函数根据以下公式将灰度图像转换为二值图像&#xff1a; 对于 THRESH_BINARY: t e x t d s t ( x , y ) { maxV…

# NLP-transformer学习:(5)Bert 实战

NLP-transformer学习&#xff1a;&#xff08;5&#xff09;模型训练和预测 基于 NLP-transformer学习&#xff1a;&#xff08;2,3,4&#xff09;&#xff0c;这里对transformer 更近一步&#xff0c;学习尝试使用其中的bert 文章目录 NLP-transformer学习&#xff1a;&#x…

在 Debian 上安装 IntelliJ IDEA 笔记

在 Debian&#x1f4a9; 上安装 IntelliJ IDEA &#x1f4a1; 笔记 下载安装 JDK17安装 IntelliJ IDEA Community添加创建桌面启动项&#xff08;快捷方式&#xff09; 参考资料 下载 两个包已经下好了&#xff0c;一个JDK17&#xff0c;一个IntelliJ IDEA Community 使用 wge…

【Liunx入门】Liunx软件包管理器

文章目录 前言一、什么是软件包二、网络相关指令三、Ubuntu包管理软件apt1.查看软件包2.sudo权限3.软件安装4.卸载软件5.软件更新6.升级软件包 总结 前言 Linux软件包管理器是Linux系统中用于安装、升级和卸载软件包的工具。它们提供了一个方便的方式来管理软件包&#xff0c;…

c++习题25-大整数加法

目录 一&#xff0c;题目 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;题目 描述 求两个不超过200位的非负整数的和。 输入 有两行&#xff0c;每行是一个不超过200位的非负整数&#xff0c;可能有多余的前导0。 输出 一行&#xff0c;即相加后的结果。结果里不…

Physics of Language Models学习小结

1.概述 Physics of Language Models 参考&#xff1a;https://zhuanlan.zhihu.com/p/711391378 这是一系列论文和一个新的LLM研究方向&#xff0c;官网的概述如下。 苹果掉落&#xff0c;盒子移动&#xff0c;但重力和惯性等普遍规律对技术进步至关重要。虽然GPT-5或LLaMA-…

Threejs学习-三维坐标系、相机控件

坐标系&#xff1a; Three.js 使用的是右手坐标系&#xff0c;x 轴朝右&#xff0c;y 轴朝上&#xff0c;z 轴朝向自己。 相机控件轨道控制器 相机控件OrbitControls 通过相机控件OrbitControls实现旋转缩放预览效果。 // 设置相机控件轨道控制器OrbitControls const contr…

fastjson漏洞分析与复现

一、基础知识 Fastjson介绍&#xff1a; fastjson是阿里巴巴开源的JSON解析库&#xff0c;它可以解析JSON格式的字符串&#xff0c;支持将Java Bean序列化为JSON字符串&#xff0c;也可以从JSON字符串反序列化到JavaBean。即fastjson的主要功能就是将Java Bean序列化成JSON字…

IDEA插件支持API调试、接口用例支持一键同步API变更,MeterSphere开源持续测试工具v3.2.0版本发布

2024年8月26日&#xff0c;MeterSphere开源持续测试工具正式发布v3.2.0版本。 在这一版本中&#xff0c;接口测试方面&#xff0c;MeterSphere API Debugger插件支持API调试&#xff0c;接口用例支持一键同步API变更&#xff1b;测试管理方面&#xff0c;在“测试用例”模块中…

牛客笔试训练

牛客.过桥 在函数 public static int n;public static int[]arrnew int[2001];public static int bfs(){int left1;int right1;int ret0;while(left<right){ret;int rright;for(int ileft;i<right;i){rMath.max(r,arr[i]i);if(r>n){return ret;}}leftright1;rightr;}…

网络原理 TCP与UDP协议

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多数据结构知识 1.应用层 之前编写完了基本的 java socket &#xff0c;要知道&#xff0c;我们之前所写的所有代码都在应⽤层&#xff0c;都是为了 完成某项…

关键点检测——HRNet源码解析篇

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;专栏推荐&#xff1a;深度学习网络原理与实战 &#x1f34a;近期目标&#xff1a;写好专栏的每一篇文章 &#x1f34a;支持小苏&#xff1a;点赞&#x1f44d;&#x1f3fc;、…

linux下部署数据库总结

数据库 数据库主要分为两大类&#xff1a;关系型数据库与 NoSQL 数据库 关系型数据库&#xff0c;是建立在关系模型基础上的数据库&#xff0c;其借助于集合代数等数学概念和方法来处理数据库 中的数据主流的 MySQL、Oracle、MS SQL Server 和 DB2 都属于这类传统数据库。 NoSQ…

JVM理论篇(一)

一、类加载子系统 1.1 类加载子系统作用 类加载子系统负责从文件系统或者网络中加载Class文件&#xff0c;Class文件在文件开头有特定的文件标识。(CAFEBABE)ClassLoader只负责class文件的加载&#xff0c;至于它是否可以运行&#xff0c;则由Execution Engine 执行引擎决定。…

Spire.PDF for .NET【文档操作】演示:创建标记的 PDF 文档

带标签的 PDF&#xff08;也称为 PDF/UA&#xff09;是一种包含底层标签树&#xff08;类似于 HTML&#xff09;的 PDF&#xff0c;用于定义文档的结构。这些标签可以帮助屏幕阅读器浏览整个文档而不会丢失任何信息。本文介绍如何使用Spire.PDF for .NET在 C# 和 VB.NET 中从头…

Python中csv文件的操作3

在《Python中csv文件的操作2》中提到&#xff0c;with as语句可以自动关闭文件&#xff0c;而该语句可以和csv模块中的函数配合使用&#xff0c;达到读取和写入csv文件的目的。 1 csv文件的读取 使用csv模块中的函数读取csv文件的代码如图1所示。 图1 使用csv模块中的函数读取…

AI终于杀死了Leetcode!网友:面试神器已到位

家人们&#xff0c;今早起来 x 上一个帖子引起了奶茶的注意&#xff1a; 什么&#xff1f;奶茶以为自己没睡醒&#xff0c;揉了揉眼睛一看&#xff0c;没看错的话&#xff0c;这不就是AI结束了比赛吗。。。。 原文链接&#xff1a; https://www.reddit.com/r/leetcode/comments…

【ES6新特性】ES6新特性中Promise对象的概念,Async函数的使用以及Module语法

目录 1.Promise 对象 1.1 概念 1.2 使用 2.Async函数 2.1 同步和异步的区别 3.Mdule语法 1.Promise 对象 1.1 概念 Promise 是异步编程的一种解决方案&#xff0c;简单说就是一个容器&#xff0c;里面保存着某个未来才会结束 的事件&#xff08;通常是一个异步操作&#…

初识QT:从创建到认识

QT怎么安装这里就不说了&#xff0c;直接从使用开始 文章目录 1.QT项目的创建及介绍2.Hello QT&#xff01;2.1 图形化形式创建2.2 代码形式创建 3.对象树3.1 内存泄漏与对象树3.2 通过C类理解释放过程 4.乱码问题4.1 如何查看编码方式4.2 如何处理乱码 提示&#xff1a;QT项目…