POI操作EXCEL插入图片
POI操作EXCEL插入图片:完整实现与优化技巧
在 Excel 中插入图片(如 Logo、二维码、报表图表)可增强文档的可视化效果。Apache POI 提供了灵活的图片插入功能,支持多种图片格式(PNG、JPG 等)和位置调整。本文将详细讲解插入图片的核心步骤、代码实现及常见问题解决方案。
核心原理与类
POI 插入图片的核心逻辑是:
- 将图片转为字节数组;
- 通过
Workbook.addPicture()注册图片资源; - 使用绘图对象(
Drawing)将图片锚定到指定单元格位置。
关键类说明:
| 类名 | 作用描述 |
|---|---|
HSSFWorkbook/XSSFWorkbook |
工作簿对象,提供 addPicture() 方法注册图片资源(返回图片索引)。 |
HSSFPatriarch/XSSFDrawing |
绘图管理器,负责创建图片对象并关联到工作表。 |
ClientAnchor |
图片锚点,定义图片在工作表中的位置(起始行列、偏移量等)。 |
Picture |
图片对象,支持调整尺寸、获取图片信息等操作。 |
完整代码实现
以下示例支持 .xls(Excel 2003)和 .xlsx(Excel 2007+)格式,演示如何插入本地图片到指定单元格,并调整尺寸。
通用工具类(兼容两种格式)
maven依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ExcelImageUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelImageUtil.class);
/**
* 向 Excel 插入图片
* @param workbook 工作簿对象(HSSFWorkbook 或 XSSFWorkbook)
* @param sheet 目标工作表
* @param imagePath 图片路径(本地文件或资源文件)
* @param rowIndex 起始行索引(0 开始)
* @param colIndex 起始列索引(0 开始)
* @param pictureType 图片类型(如 Workbook.PICTURE_TYPE_PNG)
* @param resizeRatio 缩放比例(1.0 为原尺寸)
*/
public static void insertImage(Workbook workbook, Object sheet, String imagePath,
int rowIndex, int colIndex, int pictureType, double resizeRatio) {
// 1. 读取图片为字节数组
byte[] imageBytes = getImageBytes(imagePath);
if (imageBytes == null) {
LOGGER.error("图片读取失败:{}", imagePath);
return;
}
// 2. 注册图片资源,获取图片索引
int pictureIndex = workbook.addPicture(imageBytes, pictureType);
// 3. 创建绘图管理器和锚点(区分 .xls 和 .xlsx)
if (workbook instanceof HSSFWorkbook) {
// 处理 .xls 格式
HSSFSheet hssfSheet = (HSSFSheet) sheet;
HSSFPatriarch patriarch = hssfSheet.createDrawingPatriarch();
HSSFClientAnchor anchor = (HSSFClientAnchor) workbook.getCreationHelper().createClientAnchor();
setAnchorPosition(anchor, rowIndex, colIndex);
// 创建图片并缩放
HSSFPicture picture = patriarch.createPicture(anchor, pictureIndex);
picture.resize(resizeRatio);
} else if (workbook instanceof XSSFWorkbook) {
// 处理 .xlsx 格式
XSSFSheet xssfSheet = (XSSFSheet) sheet;
XSSFDrawing drawing = xssfSheet.createDrawingPatriarch();
XSSFClientAnchor anchor = (XSSFClientAnchor) workbook.getCreationHelper().createClientAnchor();
setAnchorPosition(anchor, rowIndex, colIndex);
// 创建图片并缩放
drawing.createPicture(anchor, pictureIndex).resize(resizeRatio);
}
LOGGER.info("图片插入成功:{}(位置:行{},列{})", imagePath, rowIndex, colIndex);
}
/**
* 设置图片锚点位置(左上角对齐到指定单元格)
*/
private static void setAnchorPosition(ClientAnchor anchor, int rowIndex, int colIndex) {
anchor.setRow1(rowIndex); // 起始行
anchor.setCol1(colIndex); // 起始列
anchor.setDx1(0); // 列内 x 偏移(0 表示左对齐)
anchor.setDy1(0); // 行内 y 偏移(0 表示上对齐)
// 若需跨单元格显示,可设置 setRow2 和 setCol2
}
/**
* 将图片转为字节数组(支持本地文件和资源文件)
*/
private static byte[] getImageBytes(String imagePath) {
try (InputStream is = imagePath.startsWith("/") ?
ExcelImageUtil.class.getResourceAsStream(imagePath) : // 资源文件
new FileInputStream(imagePath); // 本地文件
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
BufferedImage image = ImageIO.read(is);
if (image == null) {
LOGGER.error("无法识别图片格式:{}", imagePath);
return null;
}
// 根据图片类型写入流(此处以 PNG 为例,可根据实际类型调整)
ImageIO.write(image, "png", out);
return out.toByteArray();
} catch (IOException e) {
LOGGER.error("图片读取异常:{}", imagePath, e);
return null;
}
}
}
调用示例
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import java.io.FileOutputStream;
import java.io.IOException;
public class ExcelImageDemo {
public static void main(String[] args) {
// 示例 1:生成 .xlsx 格式并插入图片
String xlsxPath = "带图片的Excel.xlsx";
try (Workbook xssfWorkbook = new XSSFWorkbook();
FileOutputStream fos = new FileOutputStream(xlsxPath)) {
// 创建工作表
XSSFSheet xssfSheet = xssfWorkbook.createSheet("图片示例");
// 插入图片(资源文件 logo.png,位置:行1,列1,缩放 0.5 倍)
ExcelImageUtil.insertImage(
xssfWorkbook, xssfSheet, "/logo.png", // 资源文件路径
1, 1, // 行1,列1(B2单元格)
Workbook.PICTURE_TYPE_PNG, // 图片类型
0.5 // 缩放比例
);
xssfWorkbook.write(fos);
} catch (IOException e) {
e.printStackTrace();
}
// 示例 2:生成 .xls 格式并插入图片
String xlsPath = "带图片的Excel.xls";
try (Workbook hssfWorkbook = new HSSFWorkbook();
FileOutputStream fos = new FileOutputStream(xlsPath)) {
HSSFSheet hssfSheet = hssfWorkbook.createSheet("图片示例");
ExcelImageUtil.insertImage(
hssfWorkbook, hssfSheet, "D:/qrcode.jpg", // 本地文件路径
3, 2, // 行3,列2(C4单元格)
Workbook.PICTURE_TYPE_JPEG,
1.0 // 原尺寸
);
hssfWorkbook.write(fos);
} catch (IOException e) {
e.printStackTrace();
}
}
}
关键参数与高级配置
图片位置与跨单元格显示
通过 ClientAnchor 的 setRow2 和 setCol2 可设置图片跨单元格显示,例如:
// 图片从 B2 单元格跨到 D4 单元格
anchor.setRow1(1); // 起始行:1(第2行)
anchor.setCol1(1); // 起始列:1(B列)
anchor.setRow2(3); // 结束行:3(第4行)
anchor.setCol2(3); // 结束列:3(D列)
图片缩放与尺寸调整
resize(double ratio):按比例缩放(如0.5表示缩小到 50%);resize():无参方法,自动调整图片尺寸以适应锚定的单元格范围;- 注意:
.xls格式的resize()可能存在精度问题,建议手动指定比例。
图片类型常量
Workbook 定义了常见图片类型的常量,需与实际图片格式匹配:
| 常量 | 图片格式 |
|---|---|
PICTURE_TYPE_PNG |
PNG |
PICTURE_TYPE_JPEG |
JPG/JPEG |
PICTURE_TYPE_GIF |
GIF |
PICTURE_TYPE_BMP |
BMP |
常见问题与解决方案
1. 图片插入后不显示
- 原因:
- 图片路径错误(资源文件需以
/开头,本地文件需绝对路径); - 图片格式不支持(如 SVG 格式,POI 不支持);
- 锚点位置设置错误(如行列索引越界)。
- 图片路径错误(资源文件需以
- 解决:
- 检查
getImageBytes()方法是否返回有效字节数组; - 替换为 PNG/JPG 等支持的格式;
- 简化锚点设置(先测试插入到
row=0, col=0位置)。
- 检查
2. 图片模糊或变形
- 原因:缩放比例不当或图片本身分辨率过低;
- 解决:
- 使用高分辨率图片,按原比例缩放(如
1.0); - 避免过度放大(超过原尺寸会模糊)。
- 使用高分辨率图片,按原比例缩放(如
3. 大图片导致 Excel 体积过大
- 原因:未压缩的高清图片(如几 MB 的 PNG)会显著增加文件体积;
- 解决:
- 插入前压缩图片(如通过工具将分辨率调整为 72dpi);
- 转换为 JPG 格式(比 PNG 体积更小,适合照片类图片)。
4. .xls 与 .xlsx 兼容性问题
- 现象:
.xls中插入的图片在.xlsx中显示异常; - 解决:严格区分两种格式的类(
HSSF对应.xls,XSSF对应.xlsx),避免混用。