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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM