EPPlus AddPicture 100%大小

时间:2016-10-05 14:43:00

标签: c# epplus

更新:部分问题是Excels故障。它改变了不同视图设置之间的图像大小(正常布局与页面布局)。我可能需要重新评估,剩下的差异是否重要......

如何通过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:\UserTemp\Test\TestFormat.xlsx")))
        {
            OfficeOpenXml.ExcelWorksheet worksheet = package.Workbook.Worksheets[1];

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

            package.SaveAs(new FileInfo(@"C:\UserTemp\Test\TestFormat2.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图片宽度。

高度属性表现相似,但不幸的是宽度:高度比不一致。

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

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

  • 在EPPlus版本之间
  • 在不同的Excel输入文件之间

我需要至少保证宽度:高度比例,最好保证图像尺寸。

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

编辑:

下图显示了我刚刚创建的展示位不规则布局的文件的结果。绿色框是插入的图像,在对话框窗口中突出显示混乱的比例(用德语表示,但无论如何相关的东西都是数字)。

Image for another formatted testfile

1 个答案:

答案 0 :(得分:0)

如果有人遇到类似的问题,我会采取以下措施来解决我的具体问题。

普通视图相比,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(percentage)函数避免了版本之间EPPlus SetSize(widthPx, heightPx)的不同行为。

因此,我的最终实施将类似于以下内容:

  • 从图像分辨率(300 DPI)到屏幕分辨率(96 DPI)调整宽度和高度
  • 然后调整Excel页面视图的宽度

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

        var img = worksheet.Drawings.AddPicture("Test", new FileInfo(@"C:\UserTemp\Test\Testfile.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:\UserTemp\Test\TestFormat2.xlsx"));
    }
}

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