Excel居中插入图片

近期拿到一个需求,要求将图片写入Excel,且等比例缩小或者放大,且上下左右居中。

因为历史原因,只能使用POI进行操作。遂去实践了一番。

POI操作Excel插入图片(以XSSF为例),一般是如下操作

 1     public static void writeImageV1(XSSFSheet sheet,byte[] imageByte) {
 2         XSSFDrawing drawing = sheet.createDrawingPatriarch();
 3         XSSFClientAnchor anchors = new XSSFClientAnchor();
 4         anchors.setCol1(1);
 5         anchors.setCol2(13);
 6         anchors.setRow1(1);
 7         anchors.setRow2(13);
 8         anchors.setAnchorType(AnchorType.MOVE_AND_RESIZE);
 9         drawing.createPicture(anchors, sheet.getWorkbook().addPicture(imageByte, XSSFWorkbook.PICTURE_TYPE_JPEG));
10     }

但得到的效果如下

图片自己被拉伸。这肯定不是客户想要的东西。所以,对于拉伸,有两种选择

1、自己根据锚点去调整图片的长度宽度

2、调用XSSFPicture.resize() 或者 XSSFPicture.resize(double scale);

先说第二种方式

 1     public static void writeImageV2(XSSFSheet sheet,byte[] imageByte) {
 2         XSSFDrawing drawing = sheet.createDrawingPatriarch();
 3         XSSFClientAnchor anchors = new XSSFClientAnchor();
 4         anchors.setCol1(1);
 5         anchors.setCol2(13);
 6         anchors.setRow1(1);
 7         anchors.setRow2(13);
 8         anchors.setAnchorType(AnchorType.MOVE_AND_RESIZE);
 9         XSSFPicture pic = drawing.createPicture(anchors, sheet.getWorkbook().addPicture(imageByte, XSSFWorkbook.PICTURE_TYPE_JPEG));
10         pic.resize();
11     }

这个就刺激了,有兴趣可以自己去试试。

这时回到第一种方式。直接进行相对位置的调整。直接进行相对位置的调整。先尝试缩小100个单位。

 1     public static void writeImageV3(XSSFSheet sheet,byte[] imageByte) {
 2         XSSFDrawing drawing = sheet.createDrawingPatriarch();
 3         XSSFClientAnchor anchors = new XSSFClientAnchor();
 4         anchors.setCol1(1);
 5         anchors.setCol2(13);
 6         anchors.setRow1(1);
 7         anchors.setRow2(13);
 8         
 9         anchors.setDx1(Units.EMU_PER_PIXEL * 100);
10         anchors.setDx2(Units.EMU_PER_PIXEL *(-100));
11         anchors.setDy1(Units.EMU_PER_PIXEL *(100));
12         anchors.setDy2(Units.EMU_PER_PIXEL *(-100));
13         anchors.setAnchorType(AnchorType.MOVE_AND_RESIZE);
14         drawing.createPicture(anchors, sheet.getWorkbook().addPicture(imageByte, XSSFWorkbook.PICTURE_TYPE_JPEG));
15     }

效果如下

但是看上去并不是这么回事。左上角貌似恰好只移动了一个单元格。看API说明。

Within the first cell ??换句话说,只能在cell单元格里面进行调整??这tm不是捣乱吗?

等等,不对,原始图片左下角单元格不是(13,B) 吗?为何调整后的图片左下角却是(9,C)?如果是限制在单元格里面,为何此处可以跳出单元格???(有知道的朋友不妨留个言)

仅从目前得到的信息来看:调整图片似乎只能往左上的方向进行调整,而不能往右下进行调整。

那只能调整思路,切换锚点了。

 1     public static void writeImageV4(XSSFSheet sheet,byte[] imageByte) {
 2         XSSFDrawing drawing = sheet.createDrawingPatriarch();
 3         XSSFClientAnchor anchors = new XSSFClientAnchor();
 4         int col1 = 1,col2 = 13,row1 = 1,row2 = 13; //四个坐标
 5         anchors.setCol1(col2); anchors.setCol2(col2); //锚点1
 6         anchors.setRow1(row2); anchors.setRow2(row2); //锚点2
 7         //计算区域的大小
 8         XSSFRow row = sheet.createRow(row1);
 9         double rowHeight = row.getHeightInPoints()/72*96; //行高,此处的值不精确
10         double colWidth  = sheet.getColumnWidthInPixels(col1); //列宽(注意,可能不准)
11         logger.info("rowHeight {} colWidth {}",rowHeight,colWidth);
12         double collWidthSum = colWidth * (col2 - col1), rowHeightSum = rowHeight * (row2 - row1);  //区域的实际大小
13         logger.info("collWidthSum {} rowHeightSum {}",collWidthSum,rowHeightSum);
14         InputStream bais = new ByteArrayInputStream(imageByte);  //图片大小
15         int imgaeWidth = 0,imageHeight = 0; //图片宽高
16         try {
17             BufferedImage bufferImage = ImageIO.read(bais);
18             imgaeWidth = bufferImage.getWidth(); 
19             imageHeight = bufferImage.getHeight();
20         } catch (IOException e) { /** TODO 异常处理**/}
21         finally { /** TODO 关闭流 **/ }
22         logger.info("imgaeWidth {} imageHeight {}",imgaeWidth,imageHeight);
23         double scale = Math.min(collWidthSum/imgaeWidth, rowHeightSum/imageHeight);  //计算缩放比例
24         logger.info("scale {}",scale);
25         double realImageWidth = imgaeWidth*scale,realImageHeight = imageHeight*scale;  //处理后图片的大小
26         logger.info("realImageWidth {} realImageHeight {}",realImageWidth,realImageHeight);
27         double moveX = realImageWidth == collWidthSum ? 0 : (collWidthSum - realImageWidth)/2; //计算出需要图片需要移动的坐标 X轴
28         double moveY = realImageHeight == rowHeightSum ? 0 : (rowHeightSum - realImageHeight)/2; //计算出需要图片需要移动的坐标 Y轴
29         logger.info("moveX {} moveY {}",moveX,moveY);
30         anchors.setDx1(Units.EMU_PER_PIXEL *(int)(-realImageWidth - moveX));
31         anchors.setDx2(Units.EMU_PER_PIXEL *(int)(-moveX));
32         anchors.setDy1(Units.EMU_PER_PIXEL *(int)(-realImageHeight - moveY));
33         anchors.setDy2(Units.EMU_PER_PIXEL *(int)(-moveY));
34         anchors.setAnchorType(AnchorType.MOVE_AND_RESIZE);
35         drawing.createPicture(anchors, sheet.getWorkbook().addPicture(imageByte, XSSFWorkbook.PICTURE_TYPE_JPEG));
36     }

效果如下

因为计算行高和列宽都不是精确值,所以,上下左右居中,会稍微有一点点偏移~

有兴趣的朋友可以自己尝试写一个更精确的。

 java文件如下

https://files.cnblogs.com/files/brave-rocker/WriteImageToExcel.java.zip

原文地址:https://www.cnblogs.com/brave-rocker/p/14674267.html