【EasyExcel等比例缩小导出图片】

EasyExcel等比例缩小导出图片

一、背景

  • 使用EasyExcel导出excel文件,但是需要同时导出图片信息,且图片信息不能影响行高和单元格宽度,图片本身被导出时,不能因为压缩导致图片变形

二、思路

  • 使用EasyExcel最主要是要实现各种hadler,通过实现CellWriteHandler,获取单元格图片,进行图片压缩;
  • 由于excel的行高和单元格宽度换算方式完全不一样,所以要通过计算得出最合适的压缩比例
  • (excel宽度 / 字符宽度转换为标准字符宽度) * 估算的字符到像素的转换因子 = 宽度像素;
  • (excel高度 / 点转换为英寸) * 英寸转换为像素 = 行高像素;
  • 最终宽度像素或者行高像素 根据行高与像素的转换因子 ,计算出需要设置的单元格间距值,即可正常缩小图片

三、代码

java 复制代码
public static class QuotationCustomCellWriteHandler implements CellWriteHandler {
        // 256分之一的字符宽度转换为标准字符宽度。
        public static final int STANDARD_CHARACTER_WIDTH = 256;
        // 7.5是一个估算的字符到像素的转换因子
        public static final float CHARACTER_2_PIXEL_FACTOR = 7.5f;
        // 将点转换为英寸,因为1点 = 1/72英寸。
        public static final int PIXEL_2_INCH_FACTOR = 72;
        // 英寸转换为像素,其中96是常用的DPI(每英寸像素数)值。
        public static final int DPI = 96;
        // 行高与像素的转换因子
        public static final float ROW_HEIGHT_2_PIXEL_FACTOR = 1.3333f;

        /**
         * 外界传入的行高,内部查不到
         */
        private final int rowHeight;

        public QuotationCustomCellWriteHandler(int rowHeight) {
            this.rowHeight = rowHeight;
        }

        @Override
        public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                           WriteCellData<?> cellData, Cell cell, Head head, Integer relativeRowIndex,
                                           Boolean isHead) {
            boolean noImageValue = Objects.isNull(cellData) || cellData.getImageDataList() == null || cellData.getImageDataList().isEmpty();
            if (Objects.equals(Boolean.TRUE, isHead) || noImageValue) {
                return;
            }
            Sheet sheet = cell.getSheet();
            ImageData imageData = cellData.getImageDataList().get(0);
            imageData.setRelativeLastRowIndex(0);
            imageData.setRelativeLastColumnIndex(0);
            // 处理图像缩放 - 等比例缩放
            try (ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getImage())) {
                BufferedImage image = ImageIO.read(bis);
                int targetWidth = (int) ((double) sheet.getColumnWidth(cell.getColumnIndex()) / STANDARD_CHARACTER_WIDTH * CHARACTER_2_PIXEL_FACTOR);
                int targetHeight = (int) (rowHeight * 1.0 / PIXEL_2_INCH_FACTOR * DPI);

                // 计算图像的缩放比例
                double scaleX = (double) targetWidth / image.getWidth();
                double scaleY = (double) targetHeight / image.getHeight();
                double scale = Math.min(scaleX, scaleY);

                // 计算缩放后的图像大小
                int scaledWidth = (int) (image.getWidth() * scale);
                int scaledHeight = (int) (image.getHeight() * scale);

                // 计算上下左右四个角的空白
                int topPadding = (targetHeight - scaledHeight) / 2;
                int bottomPadding = targetHeight - scaledHeight - topPadding;
                int leftPadding = (targetWidth - scaledWidth) / 2;
                int rightPadding = targetWidth - scaledWidth - leftPadding;

                // 行高(点)= 像素高度 / 1.3333
                imageData.setTop((int) (topPadding / ROW_HEIGHT_2_PIXEL_FACTOR));
                imageData.setBottom((int) (bottomPadding / ROW_HEIGHT_2_PIXEL_FACTOR));
                imageData.setLeft((int) (leftPadding / ROW_HEIGHT_2_PIXEL_FACTOR));
                imageData.setRight((int) (rightPadding / ROW_HEIGHT_2_PIXEL_FACTOR));
            } catch (Exception e) {
                log.error("QuotationCustomCellWriteHandler afterCellDataConverted err", e);
            }
            CellWriteHandler.super.afterCellDataConverted(writeSheetHolder, writeTableHolder, cellData, cell, head, relativeRowIndex, isHead);
        }
    }
相关推荐
腻害兔1 分钟前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
达子66630 分钟前
第9章_HarmonyOs图解 用Java开发UI
java·ui·harmonyos
元Y亨H1 小时前
Pandas 解析 Excel 导致的内存溢出(MemoryError)
python·excel
龙虾PRO2 小时前
能源与股票量化核心差异,AI全链路落地实操手册
java·面试·职场和发展
llwszx2 小时前
【Java/Go后端手撸原生Agent(第九篇):Plan-and-Execute规划模式——从“走一步看一步“到“先谋后动“】
java·python·golang·agent开发·plan模式·规划执行模式
ZJH__GO3 小时前
网络编程v2--多客户端互通
java·运维·服务器·开发语言·计算机网络
霸道流氓气质3 小时前
SpringBoot中基于 AES-GCM + KMS 密钥管理的数据加解密 Starter 实践
java·数据库·spring boot
Gofarlic_OMS3 小时前
NX浮动许可调度黑名单机制,对比两款谁更合理
java·大数据·运维·开源·制造
乐观的Terry3 小时前
8、发布系统-完整流水线的核心
java·spring boot·spring·spring cloud
Alexalbb3 小时前
从角色过滤到可审计授权:单体系统数据权限设计复盘与演进
java