这两天帮一朋友做一简单的商品管理的系统,遇到这么一个需求,将想要导出的商品信息及图片导出到Excel中。

起初觉得功能还是比较简单的。做个Excel导入导出的Java开发户都知道,可以利用Apache的POI来实现,为Excel创建每一行,每一单元及对应的内容。当然,图片的话需要用到POI中的HSSFClientAnchor这个类型来实现,HSSFClientAnchor的构造函数中有八个参数,分类为:int dx1,int dy1,int dx2,int dy2,short col1,int row1,short col2, int row2,其中dx1、dy1定义了该图片在开始cell的起始位置,dx2、dy2定义了在终cell的结束位置,col1、row1定义了开始cell、col2、row2定义了结束cell。

那么,我们就可以用这个方法来讲图片定位到每一个单元格中。我的做法是:

//铺满整个单元格,这里的j和i是代码中要到处多张图做了循环定义的变量
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) j, i + 1, (short) j, i + 1);

很顺利,成功导出!

问题来了,打开成功到处的Excel一看,商品对应的图片都很规矩的按照我的设置铺满了整个单元格。但是,商品图片却都变形了,也就是图片的 宽高被强行设置了成对应单元格的宽高。

这样肯定是不行的,于是第一反应就是将图片等比例导出,但是怎么让图片等比例的导出在Excel中呢,苦恼了许久,终于想到了一个可行的方案。就是利用POI设置每一行对应要放图片的那个单元格的宽度固定,也就是所有导出的图片的宽度固定,然后根据这个固定宽度与原图宽高对比,算出该固定宽度的等比例高度,然后动态设置该单元格的高度,然后再利用HSSFClientAnchor来铺满整个单元格,这样看起来就不会变形,而且等比例缩放到指定单元格中。

关键2步实现:

第一步 设置单元格固定宽度: 循环创建每一行的时候,如何设置要放图片的那个单元的宽度呢?大家都知道,在Excel中,同一列的单元格的宽度都是一样的,故可以在创建工作簿的时候,就设定好要放图片的那个单元格的宽度,我是这样做的:

// 生成一个表格
HSSFSheet sheet = workbook.createSheet(title);
// 设置B列的宽度为30*256;
sheet.setColumnWidth(1, 30 * 256);

这里我们看到,SetColumnWidth的第二个参数要乘以256,是因为这个参数的单位是1/256个字符宽度,也就是说这里我设置的是30个字符的宽度,至于一个字符宽度是多少,可以用FontDesignMetrics来获得,一般一个12号字体的宽度大约是13像素。

第二步,设置单元等比率高度:在循环每一行中,当创建对应放图片的单元的时候,设置对应的高度。我的做法是,先获取要导出的图片,在获取图片的原始宽度和高度(主要,这里获取的是像素宽高),然后根据前面设置的固定宽度算出等比例的高度:

ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
BufferedImage bufferImg = ImageIO.read(new File(savePath + System.getProperty("file.separator") + map.get("productImg")));
ImageIO.write(bufferImg, "jpg", byteArrayOut);
int width = bufferImg.getWidth();//原始宽度
int height = bufferImg.getHeight();//原始高度
// 一个12号字体的宽度为13,前面已设置了列的宽度为30*256,故这里的等比例高度计算如下
height = (int) Math.round((height * (30 * 13) * 1.0 / width));
// excel单元格高度是以点单位,1点=2像素; POI中Height的单位是1/20个点,故设置单元的等比例高度如下
row.setHeight((short) (height / 2 * 20));
// 画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
// anchor主要用于设置图片的属性
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) j, i + 1, (short) j, i + 1);
anchor.setAnchorType(3);
// 插入图片
patriarch.createPicture(anchor,workbook.addPicture(byteArrayOut.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG));

至此,等比率图片及相关信息以完美导出到Excel中。


如有什么需要改进,大家多多指点!


java 导入excel中图片 java导出图片到excel_java