市面上大多数excel转图片为收费工具,借鉴他人用awt的Graphics2D自己实现的工具类,只涉及poi依赖。

/**
* 版权: taylor
* 描述: 将excel转为图片工具类
* 创建时间:2020年08月13日
*/
package com.excel.taylor.util;import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;/**
* 〈功能简述〉将excel转为图片工具类
*
* @author Taylor
* @version [V1.0, 2020年08月13日]
* @since [XX系统]
*/
public class ExcelToImageUtil {/*** 将包含excel的输入流转为图片写入输出流中,支持xls及xlsx格式* @param sheetName 表格名,可以为null,默认取第一个* @param inputStream 输入流* @param outputStream 输出流* @throws  RuntimeException 解析或IO异常*/public static void excelToImageOutput(@Nullable String sheetName, @NonNull InputStream inputStream, @NonNull OutputStream outputStream){try (Workbook workbook = WorkbookFactory.create(inputStream)) {Sheet sheet;if (StringUtils.isNotBlank(sheetName)) {sheet = workbook.getSheet(sheetName);}else {sheet = workbook.getSheetAt(0);}BufferedImage bufferedImage = ExcelToImageUtil.parseExcelToImage(sheet);ImageIO.write(bufferedImage,"png",outputStream);} catch (InvalidFormatException e) {throw new RuntimeException("excel解析失败:"+e.getMessage(),e);} catch (IOException e) {throw new RuntimeException(e);}}/*** 解析要画图的表格* @param sheet 表格* @return {@link BufferedImage} 可以用{@link ImageIO}来处理*/@NonNullpublic static BufferedImage parseExcelToImage(@NonNull Sheet sheet){//图片宽度int imageWidth = 0;//图片高度int imageHeight = 0;// 获取整个sheet中合并单元格组合的集合List<CellRangeAddress> rangeAddress = sheet.getMergedRegions();//根据读取数据,动态获得表边界行列int totalRow = sheet.getLastRowNum()+1;int totalCol = 0;for (Row cells : sheet) {totalCol = cells.getLastCellNum() > totalCol? cells.getLastCellNum():totalCol;}//创建单元格数组,用于遍历单元格UserCell[][] cells = new UserCell[totalRow + 1][totalCol + 1];// 存放行边界int[] rowPixPos = new int[totalRow + 1];rowPixPos[0] = 0;// 存放列边界int[] colPixPos = new int[totalCol + 1];colPixPos[0] = 0;//开始遍历单元格for (int i = 0; i < totalRow; i++) {for (int j = 0; j < totalCol; j++) {imageWidth = getImageWidth(sheet, imageWidth, cells, colPixPos, i, j);}// 计算所求区域高度 // 行序列在指定区域中间 // 行序列不能隐藏boolean ifShow = !sheet.getRow(i).getZeroHeight();// 如果该单元格是隐藏的,则置高度为0float heightPoint = !ifShow ? 0 : (sheet.getRow(i).getHeightInPoints());imageHeight += heightPoint;rowPixPos[i + 1] = (int) (heightPoint * 96 / 72) + rowPixPos[i];}imageHeight = imageHeight * 96 / 72;imageWidth = imageWidth * 115 / 100;/* ------------------------------ */List<Grid> grids = new ArrayList<>();Workbook workbook = sheet.getWorkbook();for (int i = 0; i < totalRow; i++) {for (int j = 0; j < totalCol; j++) {Grid grid = getGrid(cells[i][j], rowPixPos, colPixPos, i, j);// 判断是否为合并单元格int[] isInMergedStatus = isInMerged(grid.getRow(), grid.getCol(), rangeAddress);if (isInMergedStatus[0] == 0 && isInMergedStatus[1] == 0) {// 此单元格是合并单元格,并且不是第一个单元格,需要跳过本次循环,不进行绘制continue;} else if (isInMergedStatus[0] != -1 && isInMergedStatus[1] != -1) {// 此单元格是合并单元格,并且属于第一个单元格,则需要调整网格大小int lastRowPos = isInMergedStatus[0] > totalRow - 1 ? totalRow - 1 : isInMergedStatus[0];int lastColPos = isInMergedStatus[1] > totalCol - 1 ? totalCol - 1 : isInMergedStatus[1];grid.setWidth(colPixPos[lastColPos + 1] - colPixPos[j]);grid.setHeight(rowPixPos[lastRowPos + 1] - rowPixPos[i]);}// 单元格背景颜色Cell cell = cells[i][j].getCell();if (cell != null) {coverCell(workbook, grid, cell);}grids.add(grid);}}BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);Graphics2D g2d = image.createGraphics();g2d.setColor(Color.white);g2d.fillRect(0, 0, imageWidth, imageHeight);setRenderingHint(g2d);// 绘制表格for (Grid g : grids) {coverGrid(g2d, g);}//表格最后一行有可能不显示,手动画上一行g2d.drawLine(0, imageHeight - 1, imageWidth - 4, imageHeight - 1);g2d.dispose();return image;}private static Grid getGrid(UserCell userCell, int[] rowPixPos, int[] colPixPos, int i, int j) {Grid grid = new Grid();// 设置坐标和宽高grid.setX(colPixPos[j]);grid.setY(rowPixPos[i]);grid.setWidth(colPixPos[j + 1] - colPixPos[j]);grid.setHeight(rowPixPos[i + 1] - rowPixPos[i]);grid.setRow(userCell.getRow());grid.setCol(userCell.getCol());grid.setShow(userCell.isShow());return grid;}private static void coverCell(Workbook workbook, Grid grid, Cell cell) {CellStyle cs = cell.getCellStyle();grid.setBgColor(cs.getFillForegroundColorColor());// 设置字体org.apache.poi.ss.usermodel.Font font = workbook.getFontAt(cs.getFontIndex());grid.setFont(font);// 设置前景色grid.setFtColor(cs.getFillBackgroundColorColor());// 设置文本String strCell = getString(cell);grid.setText(strCell.matches("\\w*\\.0") ? strCell.substring(0, strCell.length() - 2) : strCell);}private static int getImageWidth(Sheet sheet, int imageWidth, UserCell[][] cells, int[] colPixPos, int i, int j) {cells[i][j] = new UserCell();cells[i][j].setCell(sheet.getRow(i).getCell(j));cells[i][j].setRow(i);cells[i][j].setCol(j);boolean ifShow = !(sheet.isColumnHidden(j) || sheet.getRow(i).getZeroHeight());cells[i][j].setShow(ifShow);// 计算所求区域宽度  // 如果该单元格是隐藏的,则置宽度为0float widthPix = !ifShow ? 0 : (sheet.getColumnWidthInPixels(j));if (i == 0) {imageWidth += widthPix;}colPixPos[j + 1] = (int) (widthPix * 1.15 + colPixPos[j]);return imageWidth;}private static void coverGrid(Graphics2D g2d, Grid g) {if (!g.isShow()) {return;}// 绘制背景色g2d.setColor(g.getBgColor() == null ? Color.white : g.getBgColor());g2d.fillRect(g.getX(), g.getY(), g.getWidth(), g.getHeight());// 绘制边框g2d.setColor(Color.black);g2d.setStroke(new BasicStroke(1));g2d.drawRect(g.getX(), g.getY(), g.getWidth(), g.getHeight());// 绘制文字,居中显示g2d.setColor(g.getFtColor());Font font = g.getFont();if (font == null) {return;}FontMetrics fm = g2d.getFontMetrics(font);// 获取将要绘制的文字宽度int strWidth = fm.stringWidth(g.getText());g2d.setFont(font);g2d.drawString(g.getText(), g.getX() + (g.getWidth() - strWidth) / 2,g.getY() + (g.getHeight() - font.getSize()) / 2 + font.getSize());}private static void setRenderingHint(Graphics2D g2d) {// 平滑字体g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);g2d.setRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST, 140);g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);}private static String getString(Cell cell) {CellType cellType = cell.getCellTypeEnum();String strCell;switch (cellType) {case STRING:strCell = cell.getStringCellValue();break;case NUMERIC:strCell = String.valueOf(cell.getNumericCellValue());break;case BLANK:strCell = "";break;case FORMULA:try {strCell = String.valueOf(cell.getNumericCellValue());} catch (IllegalStateException e) {strCell = String.valueOf(cell.getRichStringCellValue());}break;default:strCell = "";break;}if (cell.getCellStyle().getDataFormatString().contains("0.00%")) {try {double dbCell = Double.valueOf(strCell);strCell = new DecimalFormat("0.00").format(dbCell * 100) + "%";} catch (NumberFormatException e) {//异常不会发生}}return strCell;}/*** 判断Excel中的单元格是否为合并单元格** @param row 行* @param col 列* @param rangeAddress 合并项* @return 如果不是合并单元格返回{-1,-1},如果是合并单元格并且是一个单元格返回{lastRow,lastCol},*         如果是合并单元格并且不是第一个格子返回{0,0}*/private static int[] isInMerged(int row, int col, List<CellRangeAddress> rangeAddress) {int[] isInMergedStatus = { -1, -1 };for (CellRangeAddress cra : rangeAddress) {if (row == cra.getFirstRow() && col == cra.getFirstColumn()) {isInMergedStatus[0] = cra.getLastRow();isInMergedStatus[1] = cra.getLastColumn();return isInMergedStatus;}if (row >= cra.getFirstRow() && row <= cra.getLastRow()) {if (col >= cra.getFirstColumn() && col <= cra.getLastColumn()) {isInMergedStatus[0] = 0;isInMergedStatus[1] = 0;return isInMergedStatus;}}}return isInMergedStatus;}/*** 预处理 传输excel数据的dto*/@Getter@Setterprivate static class UserCell {private Cell cell;private int row;private int col;private boolean show;private String text;private org.apache.poi.ss.usermodel.Color color;}/***过渡用 awt数据类*/@Getter@Setterprivate static class Grid {private boolean show;private int row; // 对应Excel中的row,也可以理解为cells[i][j]的iprivate int col; // 对应Excel中的col,也可以理解为cells[i][j]的jprivate int x; // x坐标private int y; // y坐标private int width;private int height;private String text;//= new Font("微软雅黑", Font.PLAIN, 12);private Font font;private Color bgColor;private Color ftColor;/*** 将poi.ss.usermodel.Color 转换成 java.awt.Color* <a href="http://home.cnblogs.com/u/309701/" target="_blank">@param</a>* color*/private void setBgColor(org.apache.poi.ss.usermodel.Color color) {this.bgColor = poiColor2awtColor(color);}private void setFtColor(org.apache.poi.ss.usermodel.Color color) {this.ftColor = poiColor2awtColor(color);}private void setFont(org.apache.poi.ss.usermodel.Font font) {if (font != null) {this.font = new java.awt.Font(font.getFontName(), Font.BOLD, font.getFontHeight() / 20 + 2);}}private java.awt.Color poiColor2awtColor(org.apache.poi.ss.usermodel.Color color) {Color awtColor = null;if (color instanceof XSSFColor) { // .xlsxXSSFColor xc = (XSSFColor) color;String rgbHex = xc.getARGBHex();if (rgbHex != null) {awtColor = new Color(Integer.parseInt(rgbHex.substring(2), 16));}} else if (color instanceof HSSFColor) { // .xlsHSSFColor hc = (HSSFColor) color;short[] s = hc.getTriplet();if (s != null) {awtColor = new Color(s[0], s[1], s[2]);}}return awtColor;}}
}

常用工具类五 Excel转图片工具类相关推荐

  1. excel转图片工具类

    添加依赖 <repository><id>AsposeJavaAPI</id><name>Aspose Java API</name>< ...

  2. Python实现的解压缩软件及excel转图片工具源代码,基于pyqt5

    Python实现的解压缩软件源码及excel转图片工具源代码,基于pyqt5 1.GUI.py和GUI.ui:绘制界面相关 2. UnRAR64.dll和compress.py:压缩解压相关 3. e ...

  3. PHPExcel类导入excel表带图片

    使用PHPExcel类导入excel表格数据,表中带图片导入 public function importPost(){// 上传成功后的excel文件路径$file = $this->requ ...

  4. base64图片转换工具类以及base转图片工具

    import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import ...

  5. 图片转字符图片工具类

    ├── cn.xsshome.imagetool //包名├── convert │ └── ImageToChar //图片转字符图片.文本方法 ├── slideverifycode │ └── ...

  6. 免费PDF批量转换图片工具

    免费PDF批量转换图片工具 免费PDF批量转换图片工具 程序界面 测试效果 程序说明 使用说明 使用注意 开发环境 测试环境 程序版本 源文章出处 下载地址(百度云) 免费PDF批量转换图片工具 一款 ...

  7. Java操作百万数据量Excel导入导出工具类(程序代码教程)

    Java操作百万数据量Excel导入导出工具类(程序代码教程): # 功能实现1.自定义导入数据格式,支持配置时间.小数点类型(支持单/多sheet)(2种方式:本地文件路径导入(只支持xls.xls ...

  8. 炎炎夏日最新版Excel导入导出工具类火热出炉

    辛苦写的,转载请注明来源^_^ 一.为什么要写这个Excel工具类 上个项目有个功能点需要导出信息到Excel文件,于是到网上找了工具类xdemo,首先感谢原作者的奉献,使用很简单.但在使用的过程中也 ...

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

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

最新文章

  1. C#winform使用+=和-=订阅事件和移除事件订阅
  2. java map操作_Java 8 中的 Map 骚操作,学习下!
  3. 在Windows下搭建Android开发环境及遇到的问题
  4. Java集合框架:TreeMap
  5. python增加一列数据_python数据怎么添加列?
  6. Python面向对象介绍
  7. 使用memcached显著提升站点性能
  8. java 获取mysql路径_如何使用JPQL收集MySQL基本路径?
  9. 青岛Uber优步司机奖励政策(9月14日~9月20日)
  10. iphone远程连接mysql_如何远程连接数据库 原来是这样的
  11. @程序员,你真的会用 Unix 命令?
  12. Another FTP daemon is already running?
  13. 手把手带你免费申请《软件著作权》 超详细计算机软件著作权申请教程 文末送模板
  14. 毕设题目:Matlab身份证识别
  15. 边缘计算在物联网领域的发展前景
  16. ft232h引脚_K9K8G08U0B-PIB0--斗门--镁光MICRON内存收购
  17. 设计简单计算机主机系统,【效率】专为Win7系统设计的最小Pomodoro-MiniPomodoro(随附...
  18. 在一起计时器_没想到吧?快手竟然给厕所上安装了计时器,或许职场从此再无带薪拉屎...
  19. 中级微观经济学:Chap 31 行为经济学
  20. EIB智能家居系统技术及应用

热门文章

  1. python小技巧大应用--基础实用漂亮界面(无边框,圆角,可拖拽)
  2. smart210驱动(12)audio
  3. 工具类——汉字转拼音
  4. 启迪国信灵通与Gartner共同发布研究报告
  5. well-posed problem and ill-posed problem
  6. (30 gadget day 2) 最简单也最复杂的Gadget - YubiKey
  7. 聊一聊天酬汇适合哪些人吧
  8. 云存储——Hotfile
  9. vs读取mysql数据库文件_VS 读写sql server 完整步骤
  10. 「图文教程」Windows系统Microsoft Edge浏览器设置搜索框搜索引擎为百度