EPPlus AddPicture 100%大小

更新:部分问题是Excels故障。 它在不同的视图设置(普通布局vs页面布局)之间更改图像大小。 我可能不得不重新评估,剩下的差别是否重要...


如何通过EPPlus将图像添加到Excel表格中而无需调整大小(之后在Excel中打开,并在图像属性中设置了100%缩放比例)?

我测试用例中的图像( Testfile.jpg )是一个宽度为508px,高度为177px,分辨率为300 DPI的jpg。

我的测试代码:

class Program
{
    static void Main(string[] args)
    {
        using (var package = new OfficeOpenXml.ExcelPackage(new FileInfo(@"C:UserTempTestTestFormat.xlsx")))
        {
            OfficeOpenXml.ExcelWorksheet worksheet = package.Workbook.Worksheets[1];

            var img = worksheet.Drawings.AddPicture("Test", new FileInfo(@"C:UserTempTestTestfile.jpg"));
            img.SetPosition(4, 0, 5, 0);
            img.SetSize(100);

            package.SaveAs(new FileInfo(@"C:UserTempTestTestFormat2.xlsx"));
        }
    }
}

对于EPPlus 4.0.5,在生成的xlsx文件中查看图像大小时,我会得到以下结果:

  • 随着一个未格式化的空输入XLSX文件,我得到4.31cm而不是4.30cm图像宽度。
  • 具有更复杂格式(不同行大小,不同列大小,连接单元)的不同输入xlsx文件给我的结果更糟糕: 4.47cm而不是4.30cm图像宽度。
  • 对于EPPlus 4.1.0,我得到完全不同的结果:

  • 使用未格式化的空输入xlsx文件,我可以获得13,44cm而不是4.30cm图像宽度。
  • 使用预格式化的xlsx文件,我可以获得13,81cm而不是4.30cm图像宽度。
  • heigth属性表现相似,但不幸的是宽高比不一致。

    我已经尝试了一些东西,如img.SetSize(widthPx, heigthPx)和不同的图像格式,但没有成功。

    所以现在我失去了不一致的结果

  • 在EPPlus版本之间
  • 在不同的Excel输入文件之间
  • 我需要至少保证宽度:高度比例,最好是保证图像大小。

    注意:我无法在这里创建和使用96 DPI的图像,因为这会导致非常像素化的打印。

    编辑:

    下面的图片显示了我刚刚创建为展示的布局有点不规则的文件的结果。 绿色方框是插入的图像,在对话窗口中突出显示了杂乱的比例(德文,但相关的东西都是数字)。

    图像为另一个格式化的测试文件


    如果有人遇到类似的问题,这是我做什么来解决我的具体问题。

    普通视图相比,Excel在页面视图中拉伸图像。 由于我不关心正常视图中的图像比例,因此我可以调整图像大小。 我分析了我的情况下拉伸,发现96 DPI调整后的图像宽度的下列范围(在我的情况下,高度没有改变):

    请注意,校正值不是100%准确的,因为对于不同的DPI,图像大小转换中也存在舍入误差

    0px - 54px: 0px to much width
    55px - 109px: 4px to much width
    110px - 165px: 8px to much width
    166px - 317px: 12px to much width
    318px - 442px: 23px to much width
    443px - ???: 32px to much width // I didn't bother to investigate larger values
    

    这意味着大多数宽度可以通过减去所提到的偏移来调整。 对于不同偏移量之间的边界情况,一个小错误将会保留。 以下宽度转换函数( AdjustExcelPageViewImageWidth )对所描述的错误实施了更正

    /// <summary>
    /// Excel is changing the image size in page view, this is an attempt to correct the change for a range of widths.
    /// Input width is required as pixel equivalent of the desired width for 96 DPI.
    /// </summary>
    int AdjustExcelPageViewImageWidth(int desiredWidth96DPI)
    {
        return
            LimitedRangeTransform(desiredWidth96DPI, 0, 54, 0, 4) ??
            LimitedRangeTransform(desiredWidth96DPI, 55, 109, 4, 8) ??
            LimitedRangeTransform(desiredWidth96DPI, 110, 165, 8, 12) ??
            LimitedRangeTransform(desiredWidth96DPI, 166, 317, 12, 23) ??
            LimitedRangeTransform(desiredWidth96DPI, 318, 442, 23, 32) ??
            // no data gathered for larger images
            desiredWidth96DPI - 32;
    }
    /// <summary>
    /// Interpolation function between ranges with different limit and offset. Returns the transformed width or null.
    /// </summary>
    /// <param name="width">the desired width</param>
    /// <param name="lower">the lower bound of the range, where the offset applies</param>
    /// <param name="upper">the upper bound of the range, where the offset applies</param>
    /// <param name="offset">the offset value will be subtracted for width within the range</param>
    /// <param name="nextOffset">the offset value for the next range following the upper bound</param>
    /// <returns></returns>
    int? LimitedRangeTransform(int width, int lower, int upper, int offset, int nextOffset)
    {
        // not handling those cases
        if (upper < lower || width < lower + offset)
        {
            return null;
        }
        if (width <= upper + offset)
        {
            return width - offset;
        }
        if (width <= upper + offset + (nextOffset - offset) / 2)
        {
            // border cases, can't be accurate
            return upper;
        }
        if (width <= upper + nextOffset)
        {
            // border cases, can't be accurate
            return upper + 1;
        }
        return null;
    }
    

    另一个问题 - 通过使用SetSize(widthPx, heightPx)函数避免版本之间EPPlus SetSize(percentage)不同行为。

    所以,我最后的实现将类似于以下内容:

  • 从图像分辨率(300 DPI)到屏幕分辨率(96 DPI)调整宽度和高度
  • 然后调整excel页面视图的宽度
  • static void Main(string[] args)
    {
        using (var package = new OfficeOpenXml.ExcelPackage(new FileInfo(@"C:UserTempTestTestFormat.xlsx")))
        {
            OfficeOpenXml.ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
    
            var img = worksheet.Drawings.AddPicture("Test", new FileInfo(@"C:UserTempTestTestfile.jpg"));
            img.SetPosition(4, 0, 5, 0);
    
            var width = (int)Math.Round(img.Image.Width * 96.0 / img.Image.HorizontalResolution);
            var height = (int)Math.Round(img.Image.Height * 96.0 / img.Image.VerticalResolution);
            var adjustedWidth = AdjustExcelPageViewImageWidth(width);
            img.SetSize(adjustedWidth, height);
    
            package.SaveAs(new FileInfo(@"C:UserTempTestTestFormat2.xlsx"));
        }
    }
    

    结果自然会有一些小的舍入误差,因为EPPlus将大小视为整数,但图像比例不再明显失真。

    链接地址: http://www.djcxy.com/p/72031.html

    上一篇: EPPlus AddPicture 100% size

    下一篇: Autofit rows in EPPlus