EPPlus插入图片至Excel单元格B1时高度拉伸问题排查求助
EPPlus 4.0.6 插入图片到Excel单元格后高度拉伸的问题解决
问题场景
最近在用EPPlus 4.0.6.0、.NET 4.5.2和VS 2013做开发时,遇到个头疼的问题:把图片插入Excel的B1单元格,虽然成功插进去了,但图片高度比原图大了一圈,明显被拉伸变形了。
我当前用的插入代码
先给大家看看我现在的插入逻辑:
if (imgCompanyLogo != null) { var picture = ws.Drawings.AddPicture("Test", imgCompanyLogo); int pixelHeight=GetHeightInPixels(ws.Cells[1,2]); int pixelWidth = GetWidthInPixels(ws.Cells[1, 2]); picture.SetSize(pixelWidth, pixelHeight); picture.SetPosition(0, 0, 1, 0); }
配套的单元格像素计算代码
为了获取B1单元格的像素尺寸,我用了下面这些方法:
private static int GetHeightInPixels(ExcelRange cell) { using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero)) { float dpiY = graphics.DpiY; return (int)(cell.Worksheet.Row(cell.Start.Row).Height * (1 / 72.0) * dpiY); } } public static float MeasureString(string s, Font font) { using (var g = Graphics.FromHwnd(IntPtr.Zero)) { g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; return g.MeasureString(s, font, int.MaxValue, StringFormat.GenericTypographic).Width; } } private static int GetWidthInPixels(ExcelRange cell) { double columnWidth = cell.Worksheet.Column(cell.Start.Column).Width; Font font = new Font(cell.Style.Font.Name, cell.Style.Font.Size, FontStyle.Regular); double pxBaseline = Math.Round(MeasureString("1234567890", font) / 10); return (int)(columnWidth * pxBaseline); }
其他尝试过的计算方式
我还试过另一种计算像素宽高的方法,但问题还是没解决:
decimal mdw = ws.Workbook.MaxFontWidth; int pixelHeight = (int)(ws.Row(1).Height / 0.75); int pixelWidth = (int)decimal.Truncate(((256 * (decimal)ws.Column(2).Width + decimal.Truncate(128 / (decimal)mdw)) / 256) * mdw);
问题排查与解决思路
核心问题出在哪?
- EPPlus 4.x的单位坑:你可能没注意到,EPPlus 4.x里的
SetSize方法用的是EMU(英制公制单位),不是直接的像素值。你直接把计算出来的像素传进去,肯定会导致尺寸转换错误,尤其是高度部分。 - 行高计算的偏差:Excel的行高单位是点(1点=1/72英寸),你的
GetHeightInPixels方法在DPI转换时,没有和EPPlus内部的单位规则对齐,再加上系统DPI缩放的影响,计算出来的高度就不准了。 - 忽略了图片宽高比:你直接把图片强制缩放到单元格的宽高,不管原图比例,这本身就会导致拉伸,哪怕尺寸计算对了也会变形。
修正后的解决方案
方案1:用EPPlus内置的单位转换,同时保留宽高比
EPPlus自带了PixelToEMU静态方法,用来处理像素到EMU的转换,同时我们要先计算图片的原始比例,避免拉伸:
if (imgCompanyLogo != null) { var picture = ws.Drawings.AddPicture("Test", imgCompanyLogo); // 先获取单元格的尺寸(单位:点) double cellHeightPoints = ws.Row(1).Height; // Excel列宽单位是字符宽度,默认字体下转成点需要乘7.2 double cellWidthPoints = ws.Column(2).Width * 7.2; // 计算图片的原始宽高比 double imgRatio = (double)imgCompanyLogo.Width / imgCompanyLogo.Height; double cellRatio = cellWidthPoints / cellHeightPoints; // 根据比例计算合适的显示尺寸,避免拉伸 double displayWidth, displayHeight; if (cellRatio > imgRatio) { // 单元格更宽,以高度为准,宽度按比例缩放 displayHeight = cellHeightPoints; displayWidth = displayHeight * imgRatio; } else { // 单元格更高,以宽度为准,高度按比例缩放 displayWidth = cellWidthPoints; displayHeight = displayWidth / imgRatio; } // 把点转成像素,再转成EPPlus需要的EMU(96DPI下1点=96/72像素) picture.SetSize( (int)ExcelDrawing.PixelToEMU(displayWidth * 96 / 72), (int)ExcelDrawing.PixelToEMU(displayHeight * 96 / 72) ); // 设置图片到B1单元格的左上角 picture.SetPosition(ws.Row(1).StartRow - 1, 0, ws.Column(2).StartColumn - 1, 0); }
方案2:修正行高像素计算,同时保留比例
如果你还是想用像素来计算,可以调整行高的计算逻辑,再结合比例处理:
private static int GetRowHeightInPixels(ExcelRow row) { // Excel行高是点,转成像素要结合系统DPI(1点=DPI/72像素) using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) { return (int)(row.Height * g.DpiY / 72.0); } } // 使用时的代码 if (imgCompanyLogo != null) { var picture = ws.Drawings.AddPicture("Test", imgCompanyLogo); int cellHeightPx = GetRowHeightInPixels(ws.Row(1)); int cellWidthPx = GetWidthInPixels(ws.Cells[1,2]); // 计算比例,避免拉伸 double imgRatio = (double)imgCompanyLogo.Width / imgCompanyLogo.Height; double cellRatio = (double)cellWidthPx / cellHeightPx; int finalWidth, finalHeight; if (cellRatio > imgRatio) { finalHeight = cellHeightPx; finalWidth = (int)(finalHeight * imgRatio); } else { finalWidth = cellWidthPx; finalHeight = (int)(finalWidth / imgRatio); } // 把像素转成EMU再设置尺寸 picture.SetSize( ExcelDrawing.PixelToEMU(finalWidth), ExcelDrawing.PixelToEMU(finalHeight) ); picture.SetPosition(0, 0, 1, 0); }
关键提醒
- 一定要保留宽高比:这是避免图片变形的核心,不管怎么设置尺寸,都不能强制把图片拉成单元格的形状。
- 注意EPPlus版本差异:EPPlus 4.x和5+的API不一样,你用的4.0.6没有简化的单元格适配方法,必须手动处理单位转换。
- DPI适配要到位:不同系统的DPI可能不同,用
Graphics.DpiY获取当前系统的DPI是正确的做法,这样计算出来的尺寸才会适配用户的屏幕。
内容的提问来源于stack exchange,提问作者user15940620
相关产品推荐
相关产品推荐

