如何在表格行插入图片并保持原尺寸?Apache POI尺寸异常问题
在Excel表格行中插入图片并保持原始尺寸的解决方案
我来帮你解决这两个问题,这在使用Apache POI操作Excel图片时是很常见的坑:
一、在表格行中插入图片并保留原始尺寸的核心思路
要实现这个需求,关键是要把图片的原始像素尺寸和Excel的单位体系对应起来,步骤大概是这样:
- 先准确获取图片的原始像素尺寸(就像你用
BufferedImage做的那样) - 把像素尺寸转换成Excel能识别的**点(Point)**单位,因为Excel的行高、图片尺寸都是以点为基础的
- 设置图片的锚点和尺寸,同时调整对应行的行高,让图片刚好贴合行范围
二、解决POI插入图片后尺寸异常的问题
你遇到的455×22和原始1418×70的差异,是因为Apache POI默认会按Excel的96DPI自动转换图片尺寸,而且getImageDimension()返回的是转换后的Excel点单位尺寸,不是原始像素。下面是具体的解决方法:
1. 先搞懂单位换算规则
Excel的单位和像素的换算公式(默认DPI=96):
- 像素转点:
点数值 = 像素值 × 72 ÷ 96(因为1英寸=72点=96像素) - 点转像素:
像素值 = 点数值 × 96 ÷ 72
2. 手动设置图片尺寸,覆盖默认转换
不要依赖POI的自动转换,用你获取的原始像素尺寸手动计算并设置,完整代码示例如下:
import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.nio.file.Files; public class ExcelImageInsert { public static void main(String[] args) throws Exception { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("Sheet1"); // 读取图片并获取原始尺寸 File file = new File("/home/newage/Pictures/signature.png"); BufferedImage imageIO = ImageIO.read(file); int originalWidthPx = imageIO.getWidth(); // 70px int originalHeightPx = imageIO.getHeight(); // 1418px // 换算成Excel的点单位(默认DPI=96) double dpi = 96.0; double widthInPoints = originalWidthPx * 72 / dpi; double heightInPoints = originalHeightPx * 72 / dpi; // 创建锚点:设置图片位置(这里是第1行第1列,从(0,0)单元格到(1,1)单元格) Drawing<?> drawing = sheet.createDrawingPatriarch(); ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 1, 1); // 设置图片随单元格移动和调整大小 anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE); // 插入图片到Excel int pictureIdx = workbook.addPicture(Files.readAllBytes(file.toPath()), Workbook.PICTURE_TYPE_PNG); Picture pict = drawing.createPicture(anchor, pictureIdx); // 手动设置图片的宽高为换算后的点数值 pict.resize(widthInPoints, heightInPoints); // 调整对应行的行高(行高单位是1/20点,所以直接用setHeightInPoints方法更方便) Row row = sheet.createRow(0); row.setHeightInPoints(heightInPoints); // 调整列宽(列宽单位是1/256个字符宽度,这里按图片宽度换算) sheet.setColumnWidth(0, (int) (widthInPoints * 256 / 7)); // 7是默认Calibri 11号字体的字符宽度 // 保存Excel try (var outputStream = Files.newOutputStream(new File("output.xlsx").toPath())) { workbook.write(outputStream); } workbook.close(); } }
3. 验证尺寸是否正确
设置完成后,你可以通过代码验证转换后的尺寸是否和原始一致:
// 获取图片的点尺寸,再转成像素 double actualWidthPx = pict.getImageDimension().getWidth() * dpi / 72; double actualHeightPx = pict.getImageDimension().getHeight() * dpi / 72; System.out.println("实际显示像素尺寸:" + (int)actualWidthPx + "×" + (int)actualHeightPx);
这个输出应该和你用BufferedImage获取的70×1418一致。
额外注意事项
- 如果你的图片实际DPI不是96,需要先获取图片的DPI值(可以通过图片元数据读取),替换代码中的
dpi变量 - 锚点的
col2和row2要设置合适,确保图片能放在目标单元格范围内,避免被截断 - 如果需要图片完全填充单元格,要保证行高和列宽的设置和图片的转换尺寸完全匹配
内容的提问来源于stack exchange,提问作者Mister B
相关产品推荐
相关产品推荐

