一、需求背景:

做一个大屏管理系统,基础信息包括管理的应用名称,大屏的截图,通过一个excel批量导入

excel的单元格里要插入图片,对应一个大屏应用的信息

导入需要读取到大屏截图,至于存哪还没说....

二、技术实现

Hutool这块没有做图片读取的封装,看了网上的方式都是通过poi原生的api实现的

但是Hutool读取很方便,返回的Workbook接口对象可以识别新旧工作簿类型

然后原生的api的话,只能自己去封装想要的逻辑了

几个图片的关键信息,图片字节,图片类型,图片对应的记录坐标

我还纳闷怎么拿不到图片的文件名,仔细找了API才发现是压根没存这个信息

那就算了不强求了

根据上述需求,我需要封装一个存储图片的集合,拿到后提供给业务做具体实现

或者也可以在读取到这个图片的时候,执行业务逻辑

maven 依赖坐标:

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.1</version>
</dependency>

poi 的坐标没找着...

下面就是封装的工具类:

import cn.hutool.poi.excel.ExcelReader;
import lombok.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.*; import java.io.FileOutputStream;
import java.util.*;
import java.util.function.Consumer; public class ExcelPicUtil { /**
* @description 读取Excel中的图片 返回sheet下标和对应图片的集合
* @author OnCloud9
* @date 2024/3/20 13:39
* @params ExcelReader excelReader
* @return Map<Integer, List<ExcelPic>>
*/
public static Map<Integer, List<ExcelPic>> getExcelPic(ExcelReader excelReader) {
Workbook workbook = excelReader.getWorkbook();
if (Objects.isNull(workbook)) return null;
boolean isXSSF = workbook instanceof XSSFWorkbook;
boolean isHSSF = workbook instanceof HSSFWorkbook;
if (isXSSF) return getExcelPicByXssfType((XSSFWorkbook) workbook, null);
else if (isHSSF) return getExcelPicByHssfType((HSSFWorkbook) workbook, null);
return null;
} /**
* @description
* @author OnCloud9
* @date 2024/3/20 14:12
* @params
* @return
*/
public static Map<Integer, List<ExcelPic>> getExcelPic(ExcelReader excelReader, Consumer<ExcelPic> consumer) {
Workbook workbook = excelReader.getWorkbook();
if (Objects.isNull(workbook)) return null;
boolean isXSSF = workbook instanceof XSSFWorkbook;
boolean isHSSF = workbook instanceof HSSFWorkbook;
if (isXSSF) return getExcelPicByXssfType((XSSFWorkbook) workbook, consumer);
else if (isHSSF) return getExcelPicByHssfType((HSSFWorkbook) workbook, consumer);
return null;
} @Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static final class ExcelPic {
private Integer sheetIdx;
private String suffix;
private String mimeType;
private byte[] data;
private Integer rowIdx;
private Integer colIdx;
} /**
* @description XSSF工作簿读取图片
* @author OnCloud9
* @date 2024/3/20 13:57
* @params
* @return
*/
private static Map<Integer, List<ExcelPic>> getExcelPicByXssfType(XSSFWorkbook xssfWorkbook, Consumer<ExcelPic> excelPicConsumer) {
int numberOfSheets = xssfWorkbook.getNumberOfSheets();
Map<Integer, List<ExcelPic>> picMap = new HashMap<>(); for (int xssfSheetIdx = 0; xssfSheetIdx < numberOfSheets; xssfSheetIdx++) {
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(xssfSheetIdx);
XSSFDrawing drawingPatriarch = xssfSheet.getDrawingPatriarch();
if (Objects.isNull(drawingPatriarch)) {
picMap.put(xssfSheetIdx, Collections.emptyList());
continue;
}
List<XSSFShape> shapes = drawingPatriarch.getShapes();
List<ExcelPic> excelPicList = new ArrayList<>(shapes.size());
for (XSSFShape xssfShape : shapes) {
XSSFPicture xssfPicture = (XSSFPicture) xssfShape;
XSSFClientAnchor clientAnchor = xssfPicture.getClientAnchor();
XSSFPictureData xssfPictureData = xssfPicture.getPictureData(); String fileExtension = xssfPictureData.suggestFileExtension();
byte[] data = xssfPictureData.getData();
String mimeType = xssfPictureData.getMimeType(); short col2 = clientAnchor.getCol2();
int row2 = clientAnchor.getRow2(); ExcelPic build = ExcelPic.builder()
.sheetIdx(xssfSheetIdx)
.suffix(fileExtension)
.mimeType(mimeType)
.data(data)
.rowIdx(row2)
.colIdx((int) col2)
.build();
if (Objects.nonNull(excelPicConsumer)) excelPicConsumer.accept(build);
excelPicList.add(build);
}
picMap.put(xssfSheetIdx, excelPicList);
}
return picMap;
} /**
* @description HSSF工作簿读取图片
* @author OnCloud9
* @date 2024/3/20 13:58
* @params
* @return
*/
private static Map<Integer, List<ExcelPic>> getExcelPicByHssfType(HSSFWorkbook hssfWorkbook, Consumer<ExcelPic> excelPicConsumer) {
int numberOfSheets = hssfWorkbook.getNumberOfSheets();
Map<Integer, List<ExcelPic>> picMap = new HashMap<>(); for (int hssfSheetIdx = 0; hssfSheetIdx < numberOfSheets; hssfSheetIdx++) {
HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(hssfSheetIdx);
HSSFPatriarch drawingPatriarch = hssfSheet.getDrawingPatriarch();
if (Objects.isNull(drawingPatriarch)) {
picMap.put(hssfSheetIdx, Collections.emptyList());
continue;
}
List<HSSFShape> hssfShapeList = drawingPatriarch.getChildren();
List<ExcelPic> excelPicList = new ArrayList<>(hssfShapeList.size());
for (HSSFShape hssfShape : hssfShapeList) {
HSSFPicture hssfPicture = (HSSFPicture) hssfShape;
HSSFClientAnchor clientAnchor = hssfPicture.getClientAnchor();
HSSFPictureData hssfPictureData = hssfPicture.getPictureData(); String fileExtension = hssfPictureData.suggestFileExtension();
byte[] data = hssfPictureData.getData();
String mimeType = hssfPictureData.getMimeType(); short col2 = clientAnchor.getCol2();
int row2 = clientAnchor.getRow2(); ExcelPic build = ExcelPic.builder()
.sheetIdx(hssfSheetIdx)
.suffix(fileExtension)
.mimeType(mimeType)
.data(data)
.rowIdx(row2)
.colIdx((int) col2)
.build(); if (Objects.nonNull(excelPicConsumer)) excelPicConsumer.accept(build);
excelPicList.add(build);
}
picMap.put(hssfSheetIdx, excelPicList);
}
return picMap;
} /**
* @description 根据文件路径和图片字节输出
* @author OnCloud9
* @date 2024/3/20 13:56
* @params
* @return
*/
@SneakyThrows
public static void writePicByteTo(byte[] picBytes, String outPutPath) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outPutPath);
fos.write(picBytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (Objects.nonNull(fos)) fos.close();
}
}
}

 

测试代码DEMO:

    @Test
public void excelPicRead() {
String file = "C:\\Users\\Administrator\\Desktop\\工作日志\\图片导入测试.xlsx";
ExcelReader excelReader = ExcelUtil.getReader(file); List<List<Object>> read = excelReader.read();
System.out.println(read); Map<Integer, List<ExcelPicUtil.ExcelPic>> excelPicMap = ExcelPicUtil.getExcelPic(excelReader, excelPic -> {
// todo ...... 自己实现读取到这个图片时做啥
}); String rootPath = "D:\\ymcd-project\\config\\ouput\\";
excelPicMap.values().forEach(excelPics -> excelPics.forEach(excelPic -> {
ExcelPicUtil.writePicByteTo(excelPic.getData(), rootPath + excelPic.getRowIdx() + "-" + excelPic.getColIdx() + "." + excelPic.getSuffix());
})); System.out.println(excelPicMap.size());
}

  

演示文件:

读取后输出到目录:

三、图片写入

代码参考自51CTO

https://blog.51cto.com/u_16213405/9673126

  

关于图片写入Anchor参数的详细说明见:

https://www.bilibili.com/video/BV1eA41157va?p=25

我想到有图片读取导入,就有图片导出的功能

然后导出的时候和导入一样,一定是基于单元格定位的。

然后图片的呈现是根据单元格大小控制的(不影响图片质量)

这里继续对工具类追加了方法:

    /**
* @description 将图片写入到Excel中
* @author OnCloud9
* @date 2024/3/20 16:40
* @params
* @return
*/
@SneakyThrows
public static void writePicToExcel(ExcelWriter excelWriter, List<ExcelPicWrite> excelPicWriteList) {
Workbook workbook = excelWriter.getWorkbook();
CreationHelper creationHelper = workbook.getCreationHelper();
Sheet sheet;
for (ExcelPicWrite picWrite : excelPicWriteList) {
/* 判断是否提供sheet名称,不提供默认写入到第一个,遍历时不一定存在,所以要判断,不存在时创建出来 */
String sheetName = picWrite.getSheetName();
if (StringUtils.isBlank(sheetName)) sheet = workbook.getSheetAt(0);
else {
sheet = workbook.getSheet(sheetName);
if (Objects.isNull(sheet)) sheet = workbook.createSheet(sheetName);
} /* 获取图片内容,写入工作簿中 */
byte[] picContent = picWrite.getData();
Integer picType = picWrite.getPicType();
int picIdx = workbook.addPicture(picContent, picType); /* 设置图片存放的位置 */
Integer rowIdx = picWrite.getRowIdx();
Integer colIdx = picWrite.getColIdx();
ClientAnchor clientAnchor = creationHelper.createClientAnchor();
clientAnchor.setRow1(rowIdx);
clientAnchor.setRow2(rowIdx + 1);
clientAnchor.setCol1(colIdx);
clientAnchor.setCol2(colIdx + 1); /* 图片绘制渲染 */
Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();
Picture picture = drawingPatriarch.createPicture(clientAnchor, picIdx);
}
} /**
* @description 图片类型翻译
* @author OnCloud9
* @date 2024/3/20 17:46
* @params
* @return
*/
public static int picTypeTranslate(String picType) {
if (StringUtils.isBlank(picType)) return Workbook.PICTURE_TYPE_JPEG;
switch (picType) {
case "png":
case "PNG":
return Workbook.PICTURE_TYPE_PNG;
case "bmp":
case "BMP":
return Workbook.PICTURE_TYPE_DIB;
default:
case "jpeg":
case "JPEG":
case "jpg":
case "JPG":
return Workbook.PICTURE_TYPE_JPEG;
}
} @Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static final class ExcelPicWrite {
private String sheetName; /* 导出创建时依照sheetName名称为标识,如果不写则默认放到第一个sheet页 */
private byte[] data; /* 图片字节数组 这里不关心图片输入的方式 */
private Integer rowIdx; /* 定位的单元格行 */
private Integer colIdx; /* 定位的单元格列 */
private Integer picType; /* 图片类型 见上面翻译方法 */
}

  

测试代码:

这里图省事我就都用同一个图片源了,导出的Excel上的图片会跟随单元格宽高变化而变化

右键另存为的图片大小也是一样的

    @Test
public void excelPicWrite() {
ExcelWriter excelWriter = ExcelUtil.getWriter();
String picPath = "D:\\ymcd-project\\config\\ouput\\3-2.jpeg";
byte[] demoData = FileUtil.readBytes(picPath);
ExcelPicUtil.writePicToExcel(excelWriter, Arrays.asList(
ExcelPicUtil.ExcelPicWrite.builder()
.picType(Workbook.PICTURE_TYPE_JPEG)
.data(demoData)
.rowIdx(1)
.colIdx(3)
.build(),
ExcelPicUtil.ExcelPicWrite.builder()
.picType(Workbook.PICTURE_TYPE_JPEG)
.data(demoData)
.rowIdx(2)
.colIdx(3).build(),
ExcelPicUtil.ExcelPicWrite.builder()
.picType(Workbook.PICTURE_TYPE_JPEG)
.data(demoData)
.rowIdx(3)
.colIdx(3)
.build()
)); excelWriter.flush(new File("D:\\ymcd-project\\config\\ouput\\write-test.xlsx"));
excelWriter.close();
}

  

【Java】Excel 读写图片工具类的更多相关文章

  1. java excel转pdf 工具类

    package com.elitel.hljhr.comm.web.main.controller; import java.io.File; import java.io.FileOutputStr ...

  2. java Excel导入导出工具类

    本文章,导入导出依赖提前定义好的模板 package com.shareworx.yjwy.utils; import java.io.File; import java.io.FileInputSt ...

  3. Java图片工具类,完成图片的截取和任意缩放

    package com.common.util; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Renderin ...

  4. Java基础学习总结(49)——Excel导入导出工具类

    在项目的pom文件中引入 <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifac ...

  5. 拍照、本地图片工具类(兼容至Android7.0)

    拍照.本地图片工具类:解决了4.4以上剪裁会提示"找不到文件"和6.0动态授予权限,及7.0报FileUriExposedException异常问题. package com.hb ...

  6. 一个基于POI的通用excel导入导出工具类的简单实现及使用方法

    前言: 最近PM来了一个需求,简单来说就是在录入数据时一条一条插入到系统显得非常麻烦,让我实现一个直接通过excel导入的方法一次性录入所有数据.网上关于excel导入导出的例子很多,但大多相互借鉴. ...

  7. Workbook导出excel封装的工具类

    在实际中导出excel非常常见,于是自己封装了一个导出数据到excel的工具类,先附上代码,最后会写出实例和解释.支持03和07两个版本的 excel. HSSF导出的是xls的excel,XSSF导 ...

  8. Android--很实用的图片工具类

    import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; imp ...

  9. Excel解析easyexcel工具类

    Excel解析easyexcel工具类 easyexcel解决POI解析Excel出现OOM <!-- https://mvnrepository.com/artifact/com.alibab ...

  10. 最全的Java操作Redis的工具类,使用StringRedisTemplate实现,封装了对Redis五种基本类型的各种操作!

    转载自:https://github.com/whvcse/RedisUtil 代码 ProtoStuffSerializerUtil.java import java.io.ByteArrayInp ...

随机推荐

  1. OpenTelemetry agent 对 Spring Boot 应用的影响:一次 SPI 失效的案例

    背景 前段时间公司领导让我排查一个关于在 JDK21 环境中使用 Spring Boot 配合一个 JDK18 新增的一个 SPI(java.net.spi.InetAddressResolverPr ...

  2. js数据类型的检查

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  3. Windows SERVER 新建FTP 服务器

    Windows SERVER 新建FTP 服务器 FTP主机上的操作(本机IP为:192.168.137.2): 1.新建一个名为 ftpa 的Windows用户. 2.在D盘新建一个 FtpBook ...

  4. python rabbitmq官方文档demo

    1.生产者 #!/usr/bin/env python import pika import json # https://www.rabbitmq.com/tutorials/tutorial-on ...

  5. post请求方式 - 使用restTemplate而不使用httpClient,headers.setContentType(MediaType.APPLICATION_JSON_UTF8)

    public static String doPostForJson(String url, String json,String byteAuthorization) { RestTemplate ...

  6. mybatis执行insert语句后,返回当前插入数据主键的方法 keyProperty区分大小写

    mybatis执行insert语句后,返回当前插入数据主键的方法 keyProperty区分大小写 #这样查询没有返回主键值 <insert id="addLog" useG ...

  7. Big Exponential Addition

    Big Exponential Addition 给定一非负整数n计算2^n的值,一般而言把 2 乘上 n 次,就能得到答案.然而,当n特别大时,2^n要一次次地乘2可能稍嫌太慢,面对此一巨大问题利用 ...

  8. 使用AWS Glue进行 ETL 工作

    数据湖 数据湖的产生是为了存储各种各样原始数据的大型仓库.这些数据根据需求,进行存取.处理.分析等.对于存储部分来说,开源版本常见的就是 hdfs.而各大云厂商也提供了各自的存储服务,如 Amazon ...

  9. GUI测试

    标签(空格分隔): GUI 我要用到 Chrome 浏览器,所以需要先下载 Chrome Driver 并将其放入环境变量.接下来,你可以用自己熟悉的方式建立一个空的 Maven 项目,然后在 POM ...

  10. ubuntu22 装物理机

    前言 最近需要使用u盘装一个ubuntu物理机,原本想试试麒麟,但还需要申请.. 自己捣鼓半天,终于把ubuntu系统装上了,现在记录一下过程. 正文 下载镜像文件 从官网下载 ubuntu22 的镜 ...