You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET 6项目中使用NPOI将图片居中显示在Excel单元格中?

问题

我正在开发一个.NET 6项目,需要使用NPOI库生成.xlsx文件,并在单元格中添加图片且使其居中。

首先我创建了XSSFWorkbook,添加工作表、行和单元格:

var workbook = new XSSFWorkbook();
var currentWorksheet = workbook.CreateSheet("MyWorksheet");

// 设置列默认宽度
currentWorksheet.SetColumnWidth(0, 600);

// 创建行
var currentRow = currentWorksheet.CreateRow(0);
currentRow.Height = 600;

现在我已完成上述操作,想要添加居中的图片,于是通过Base64字符串添加图片:

// 将Base64字符串转换为字节数组
var img = Convert.FromBase64String("MyBase64Image");

var pictureIndex = workbook.AddPicture(img, PictureType.PNG);
IDrawing drawing = currentWorksheet.CreateDrawingPatriarch();

// 定义图片锚点
IClientAnchor anchor = drawing.CreateAnchor(200, 200, 400, 400, 0, 0, 0, 0);
anchor.AnchorType = AnchorType.MoveDontResize;
var picture = drawing.CreatePicture(anchor, pictureIndex);
picture.Resize();

// 调整图片到指定尺寸
var imageSize = picture.GetImageDimension();
double resizeX = 50.0 / imageSize.Width;
double resizeY = 50.0 / imageSize.Height;
picture.Resize(resizeX, resizeY);

但无论我修改锚点的dx1、dx2、dy1、dy2参数(最后四个参数除外),图片都固定在单元格的左上角,位置完全不变。请问如何让图片在单元格中居中?


解决方法

问题核心在于调用无参的picture.Resize()时,NPOI会自动覆盖锚点的偏移参数(dx1、dy1等),导致手动设置的偏移失效。要实现图片居中,需先计算单元格与图片的尺寸差值,手动设置锚点偏移,且避免使用无参的Resize()方法。

具体实现步骤:

  1. 明确NPOI单位规则:列宽单位是1/256字符宽度,行高单位是1/20点;锚点偏移参数dx1/dy1/dx2/dy2的单位是EMU(English Metric Unit),1像素=9525 EMU
  2. 计算目标图片尺寸与单元格尺寸的差值,得出居中所需的偏移量
  3. 用计算后的偏移量创建锚点,再调用带参数的Resize()调整图片尺寸

修正后的完整代码

using System.Drawing;
using System.IO;
using NPOI.XSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;

var workbook = new XSSFWorkbook();
var currentWorksheet = workbook.CreateSheet("MyWorksheet");

// 设置列宽度(单位:1/256字符宽度)
int columnWidth = 600;
currentWorksheet.SetColumnWidth(0, columnWidth);

// 创建行并设置高度(单位:1/20点)
int rowHeight = 600;
var currentRow = currentWorksheet.CreateRow(0);
currentRow.Height = (short)rowHeight;

// 将Base64字符串转换为字节数组
var imgBytes = Convert.FromBase64String("MyBase64Image");
var pictureIndex = workbook.AddPicture(imgBytes, PictureType.PNG);
IDrawing drawing = currentWorksheet.CreateDrawingPatriarch();

// 获取图片原始尺寸
using var imgStream = new MemoryStream(imgBytes);
var imageDimension = Image.FromStream(imgStream);
double originalImgWidth = imageDimension.Width;
double originalImgHeight = imageDimension.Height;

// 定义目标图片尺寸
double targetImgWidth = 50;
double targetImgHeight = 50;

// 计算缩放比例
double resizeX = targetImgWidth / originalImgWidth;
double resizeY = targetImgHeight / originalImgHeight;

// 转换单元格尺寸为像素(列宽=列宽值/256 * 默认字体宽度;行高=行高值/20 * 96/72,96是屏幕DPI,72是打印DPI)
// 假设默认字体宽度为10(可根据实际使用的字体调整)
double cellWidthPx = columnWidth / 256.0 * 10;
double cellHeightPx = rowHeight / 20.0 * 96 / 72;

// 计算居中偏移量(转成EMU单位)
long dx1 = (long)((cellWidthPx - targetImgWidth) / 2 * 9525);
long dy1 = (long)((cellHeightPx - targetImgHeight) / 2 * 9525);
long dx2 = dx1 + (long)(targetImgWidth * 9525);
long dy2 = dy1 + (long)(targetImgHeight * 9525);

// 创建锚点:dx1/dy1是图片左上角偏移,dx2/dy2是右下角偏移;后四个参数指定图片绑定的单元格范围(0,0到0,0表示仅A1单元格)
IClientAnchor anchor = drawing.CreateAnchor(dx1, dy1, dx2, dy2, 0, 0, 0, 0);
anchor.AnchorType = AnchorType.MoveDontResize;

// 创建图片并应用缩放
var picture = drawing.CreatePicture(anchor, pictureIndex);
picture.Resize(resizeX, resizeY);

关键注意事项

  • 不要调用无参的picture.Resize(),它会自动重置锚点偏移,覆盖手动设置的值
  • 列宽转像素时的默认字体宽度需根据实际使用的字体调整(比如常用的Calibri 11号字体,宽度约为10)
  • 若需适配不同DPI环境,可根据实际屏幕DPI调整行高的转换公式

内容的提问来源于stack exchange,提问作者Thomas Fabre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 13:30:41