POI提供了HSSF、XSSF以及SXSSF三种方式操作Excel。区别如下:
HSSF:操作Excel97-2003版本,文件扩展名为.xls。
XSSF:操作Excel2007版本开始,文件扩展名为.xlsx。
SXSSF:是在XSSF基础上,POI3.8版本开始提供的一种支持低内存占用的操作方式,扩展名为.xlsx。
下面代码适用于Excel 97-2003,文件后缀为.xls,使用的poi版本为5.1.0
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.1.0</version>
</dependency>
HSSFClientAnchor构造方法参数的含义:
下面代码功能,将一张图片放在excel的某个单元格,等比例放置图片并居中,默认宽占满或者高占满单元格
package com.test.util;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.ClientAnchor;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
public class ExcelTest {
public static void main(String[] args) {
String outFilePath = "d:/test.xls";//生成的文件
String templatePath = "D:\\material\\2022\\01\\05\\template.xls";//模板文件
String imagePath = "D:\\material\\2022\\01\\05\\2333.png";//图片
InputStream in = null;
FileOutputStream out = null;
try{
in = new FileInputStream(templatePath);
HSSFWorkbook wb = new HSSFWorkbook(in);
HSSFSheet sheet = wb.getSheetAt(0);
in.close();
sheet.setForceFormulaRecalculation(true);
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
// 将图片设置到A4单元格中:后面两个参数,0代表第1列,3代表第4行
insertImageToCell(wb,patriarch,imagePath,(short) 0,(short)3);
out = new FileOutputStream(outFilePath);
// 将最新的 Excel 文件写入到文件输出流中,更新文件信息!
wb.write(out);
// 执行 flush 操作, 将缓存区内的信息更新到文件上
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void insertImageToCell(HSSFWorkbook wb, HSSFPatriarch patriarch, String imageFile, short col1, short row1) {
BufferedImage bufferImg;
int maxWidth = 1023,maxHeight=255;
//x1=12左侧预留12宽度,y1=15上方预留15宽度
int x1=12,y1=15,x2=maxWidth,y2=maxHeight;
// 先把读进来的图片放到一个ByteArrayOutputStream中,以便产生ByteArray
try {
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
File file = new File(imageFile);
if (file.exists()) {
long lenth=file.length();
if (lenth>10) {
bufferImg = ImageIO.read(file);
/* 原始图像的宽度和高度 */
int width = bufferImg.getWidth();
int height = bufferImg.getHeight();
if (width>height) {//宽大于高
//假设左右各留出12宽度,图片宽设置为最大,占据约1000(=maxWidth-12*2)
double rate = (double)(maxWidth-x1*2)/width;//比例
int eHeight = (int)(height*rate);//等比例算出需要的高度
//如果图片高度+y1大于255,则设置图片的高度为255-y1=240,重新计算宽度
if(eHeight+y1>maxHeight) {
rate = (double) (maxHeight-y1)/height;//重新计算比例
int ewidth = (int)(width*rate);//等比例算出需要的宽度
y2 = (maxHeight-y1);//y2坐标
x2 = ewidth+x1;
if(x2<1012){//如果图片不居中,重新计算x1位置,使图片居中
x1 = (maxWidth-x2)/2;//图片居中
x2 = ewidth+x1;
}
}else {
y2 = y1+eHeight;//这里就不设置图片上下居中了(保留图片距离上方15)
x2 = (maxWidth-x1*2);
}
}else{//高大于宽
//假设上留出15宽度,图片高设置为最大,占据240(=255-15)
double rate = (double)(maxHeight-y1)/height;//比例
int ewidth = (int)(width*rate);//等比例算出需要的宽度
//如果图片高度>宽,高最大为240,宽最大为1012,所以宽不会超出
y2 = (maxHeight-y1);
x2 = ewidth+x1;
if(x2<1012){//如果图片不居中,重新计算x1位置,使图片居中
x1 = (maxWidth-x2)/2;//图片居中
x2 = ewidth+x1;
}
}
ImageIO.write(bufferImg, "jpg", byteArrayOut);
//x1,y1,x2,y2
HSSFClientAnchor anchor = new HSSFClientAnchor(x1, y1, x2, y2,
col1, row1, col1, row1);
anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
// 插入图片
patriarch.createPicture(anchor, wb.addPicture(
byteArrayOut.toByteArray(),
HSSFWorkbook.PICTURE_TYPE_JPEG));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
解决ImageIO.read(file);读取的图片,缩放处理后变色问题:
BufferedImage bufferImg= ImageIO.read(file);
改为
//解决图片变色问题
BufferedImage _img = ImageIO.read(file);
BufferedImage bufferImg= new BufferedImage(_img.getWidth(),_img.getHeight(),BufferedImage.TYPE_INT_RGB);
bufferImg.getGraphics().drawImage(_img, 0, 0, null);
//...
ImageIO.write(bufferImg, "jpg", byteArrayOut);