java POI Excel工作表:在保持比例的同时重新绘制图片

你好,我创build一个使用POI的Excel shhet,并在一个点上添加一个JPG文件的图像:

Workbook wb = new HSSFWorkbook(); CreationHelper helper = wb.getCreationHelper(); //... InputStream is = new FileInputStream("img.jpg"); byte[] bytes = IOUtils.toByteArray(is); int picIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG); Drawing drawing = sheet.createDrawingPatriarch(); ClientAnchor anchor = helper.createClientAnchor(); anchor.setCol1(5); anchor.setRow1(5); Picture pict = drawing.createPicture(anchor, picIdx); pict.resize(); 

现在我想要把这张照片放进那个单元格,但是我不想改变它的宽高比。 我可以调整的尺度是相对于细胞,显然可以有不同的比例。 我试图计算比例尺,但问题是,我无法得到或设置像素中的行高度,只有在PT,我无法计算单元格比例或者BC我无法获得宽度和高度在同样的单位…任何build议?

POI中有一个Units类,提供像素和点之间的转换。
这里有一些其他的方法可能会有所帮助。
(使用下面的方法来设置单位的宽度和高度,如果你使用更多的像素,只需忽略cmToPx() ,而不是使用像素。

1.Centimeters像素

 public static int cmToPx(double cm) { return (int) Math.round(cm * 96 / 2.54D); } 

96是我的显示器的DPI(从dpilove检查你的)
和1英寸= 2.54厘米

2.Centimers到RowHeight

 public static int cmToH(double cm) { return (int) (Units.pixelToPoints(cmToPx(cm)) * 20); //POI's Units } 

该公式来自HSSFRow#getHeightInPoints

将高度设置为“缇”或1/20的点。

设置行高时使用cmToH() ,如sheet.setDefaultRowHeight()

3.Centimeters到ColumnWidth

 public static int cmToW(double cm) { return (int) Math.round(((cmToPx(cm) - 5.0D) / 8 * 7 + 5) / 7 * 256); } 

使用(px - 5.0D) / 8将像素转换为excel宽度的点(当在excel中拖动列的宽度时,像素和点将在光标周围显示)
该公式来自HSSFSheet#setColumnWidth

设置宽度( 以字符宽度的1/256为单位

Excel使用以下公式(OOXML规范的第3.3.1.12节):

 // Excel width, not character width width = Truncate([{Number of Visible Characters} * {Maximum Digit Width} + {5 pixel padding}]/{Maximum Digit Width} * 256) / 256 

以Calibri字体为例,11点字体的最大数字宽度为7像素(96 dpi)。 如果将列宽设置为八个字符宽度,例如setColumnWidth(columnIndex,8 * 256),则可见字符的实际值(Excel中显示的值)从以下公式导出:

 Truncate([numChars * 7 + 5] / 7 * 256) / 256 = 8; 

设置列宽( 字符宽度 cmToW()时使用cmToW() ,如sheet.setColumnWidth()


下面我设置XSSFClientAnchor来调整图片的大小,以保持它的比例。

 // set padding between picture and gridlines so gridlines would not covered by the picture private static final double paddingSize = 10; private static final int padding = Units.toEMU(paddingSize); public static int[] calCellAnchor(double cellX, double cellY, int imgX, int imgY) { // assume Y has fixed padding first return calCoordinate(true, cellX, cellY, imgX, imgY); } public static int[] calCoordinate(boolean fixTop, double cellX, double cellY, int imgX, int imgY) { int x = imgX; double ratio = ((double) imgX) / imgY; x = (int) Math.round(Units.toEMU(cellY - 2 * paddingSize) * ratio); x = (Units.toEMU(cellX) - x) / 2; if (x < padding) { return calCoordinate(false, cellY, cellX, imgY, imgX); } return calDirection(fixTop, x); } public static int[] calDirection(boolean fixTop, int x) { if (fixTop) { return new int[] { x, padding, -x, -padding }; } else { return new int[] { padding, x, -padding, -x }; } } ... // set XSSFClientAnchor here BufferedImage img = ImageIO.read(new File(path)); int[] anchorArray = calCellAnchor(Units.pixelToPoints(cellW), Units.pixelToPoints(cellH), img.getWidth(), img.getHeight()); XSSFClientAnchor anchor = new XSSFClientAnchor(anchorArray[0], anchorArray[1], anchorArray[2], anchorArray[3], col1, row1, col2, row2); ...