近期拿到一個需求,要求將圖片寫入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