这个缩放的比例不是很准确,但还凑合能用,目前本人找不到其它方法,就先用这个。
先看一个关键的API方法:void org.apache.poi.ss.usermodel.Picture.resize(double scaleX, double scaleY),一定要清楚这个方法中的参数 scaleX 和 scaleY 的比例是最终图片的宽高与单元格宽高的比例,不是与原图片宽高的比例。(而且当scaleX=1时,按道理应该占满单元格,但我测试后一直占不满不知道为什么,这可能也是最后比例不准确的原因之一)
测试代码在下面,大体说明一下这个代码:根据旧的excel,生成新的excel,新的excel需要在原有基础上插入一个图片,插入图片的位置是批注为“img”的单元格,生成的图片宽是70PX(可以根据参数调整),高度是根据最终图片宽度与原图的比例调整的,如果原图的宽度小于70PX,则直接插入原图。引入需要的依赖后,创建新类复制代码,可直接测试,缩放图片的关键部分都有注释,这是写好的业务代码,不是demo,所以有些冗长,可根据自身需要删除不必要的部分。
package com.buptnu.excel;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import javax.imageio.ImageIO;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ExcelUtils {
/**
* 生成Excel
* @param targetPath 原excel文件地址
* @param imgPath 图片地址
* @param newFilePath 生成的新excel文件地址
* @param width 生成的新的图片宽度,单位是像素
*/
public static void dataExportExcel(String targetPath, String imgPath, String newFilePath, double width) {
InputStream input = null;
OutputStream output = null;
Workbook workbook = null;
try {
input = new FileInputStream(targetPath);
if (!input.markSupported()) {
input = new PushbackInputStream(input, 8);
}
if (POIFSFileSystem.hasPOIFSHeader(input)) {
workbook= new HSSFWorkbook(input);// excel 2003
} else if (POIXMLDocument.hasOOXMLHeader(input)) {
workbook = new XSSFWorkbook(OPCPackage.open(input));// excel 2007
}
Sheet sheet = workbook.getSheetAt(0);
for (int i = 0; i < sheet.getLastRowNum() + 1; i++) {
Row row = sheet.getRow(i);
if (row == null) {
continue;
}
for (int j = 0; j < row.getLastCellNum(); j++) {
Cell cell = row.getCell(j);
if (cell == null) {
continue;
}
Comment comment = cell.getCellComment();
if (comment == null) {
continue;
}
String commentValue = comment.getString().getString().trim();
if (commentValue.equals("img")) {
ExcelUtils.replaceImage(workbook, sheet, cell, imgPath, j, i, width);
}
cell.removeCellComment();
}
}
File file = new File(newFilePath);
if (!file.exists()) {
file.createNewFile();
}
output = new FileOutputStream(newFilePath);
workbook.write(output);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) { }
}
if (output != null) {
try {
output.close();
} catch (IOException e) { }
}
}
}
/**
* 替换图片
* @param book
* @param sheet
* @param cell
* @param jdImagePath
* @param jdcol
* @param jdrow
* @param width
* @return
* @throws Exception
*/
public static Workbook replaceImage(Workbook book, Sheet sheet, Cell cell, String jdImagePath, int jdcol, int jdrow, double width) throws Exception {
InputStream jdis;
byte[] jdbytes = null;
try {
jdis = new FileInputStream(jdImagePath);
jdbytes = IOUtils.toByteArray(jdis);
} catch (Exception e) {
e.printStackTrace();
}
CreationHelper helper = book.getCreationHelper();
Drawing drawing = null;
if (sheet instanceof XSSFSheet) {
XSSFSheet xSSFSheet = (XSSFSheet)sheet;
drawing = xSSFSheet.getDrawingPatriarch();
} else if (sheet instanceof HSSFSheet) {
HSSFSheet hSSFSheet = (HSSFSheet)sheet;
drawing = hSSFSheet.getDrawingPatriarch();
}
if (drawing == null) {
drawing = sheet.createDrawingPatriarch();
}
// 图片插入坐标
if (-1 != jdcol && -1 != jdrow) {
int jdpictureIdx = book.addPicture(jdbytes, Workbook.PICTURE_TYPE_JPEG);// 根据需要调整参数,如果是PNG,就改为 Workbook.PICTURE_TYPE_PNG
ClientAnchor jdanchor = helper.createClientAnchor();
jdanchor.setCol1(jdcol);
jdanchor.setRow1(jdrow);
// 获取原图片的宽度和高度,单位都是像素
File image = new File(jdImagePath);
BufferedImage sourceImg = ImageIO.read(image);
double imageWidth = sourceImg.getWidth();
double imageHeight = sourceImg.getHeight();
// 获取单元格宽度和高度,单位都是像素
double cellWidth = sheet.getColumnWidthInPixels(cell.getColumnIndex());
double cellHeight = cell.getRow().getHeightInPoints() / 72 * 96;// getHeightInPoints()方法获取的是点(磅),就是excel设置的行高,1英寸有72磅,一般显示屏一英寸是96个像素
// 插入图片,如果原图宽度大于最终要求的图片宽度,就按比例缩小,否则展示原图
Picture pict = drawing.createPicture(jdanchor, jdpictureIdx);
if (imageWidth > width) {
double scaleX = width / cellWidth;// 最终图片大小与单元格宽度的比例
// 最终图片大小与单元格高度的比例
// 说一下这个比例的计算方式吧:( imageHeight / imageWidth ) 是原图高于宽的比值,则 ( width * ( imageHeight / imageWidth ) ) 就是最终图片高的比值,
// 那 ( width * ( imageHeight / imageWidth ) ) / cellHeight 就是所需比例了
double scaleY = ( width * ( imageHeight / imageWidth ) ) / cellHeight;
pict.resize(scaleX, scaleY);
} else {
pict.resize();
}
}
return book;
}
public static void main(String[] args) {
ExcelUtils.dataExportExcel("F:\\test.xlsx", "F:\\test1.jpg", "F:\\test2.xlsx", 70);
}
}
maven的POI依赖:
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-poi</artifactId>
<version>1.0.9</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.12</version>
</dependency>