EPPlus AddPicture 100% size

Update: part of the problem is Excels fault. Its changing the image size between different view settings (normal layout vs page layout). I may have to re-evaluate, whether the remaining difference even matters...


How can I add an image to an excel sheet via EPPlus without any resizing (open in Excel afterwards and have 100% scaling set in the image properties)?

The image ( Testfile.jpg ) in my test case is a jpg with 508px width, 177px height and 300 DPI resolution.

My Test code:

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"));
        }
    }
}

For EPPlus 4.0.5, I get the following results when looking at the image size in the resulting xlsx file:

  • With an unformatted empty input xlsx file, I get 4.31cm instead of 4.30cm image width.
  • A different input xlsx file with more complicated formatting (different row size, different column size, connected cells) is giving me even worse results: 4.47cm instead of 4.30cm image width.
  • For EPPlus 4.1.0, I get completely different results:

  • With an unformatted empty input xlsx file, I get 13,44cm instead of 4.30cm image width.
  • With the pre-formatted xlsx file, I get 13,81cm instead of 4.30cm image width.
  • The heigth properties are behaving similar, but unfortunately the width:height ratio is not consistent.

    I already experimented with a few things like img.SetSize(widthPx, heigthPx) and different image formats without success.

    So for now I'm lost with inconsistent results

  • Between EPPlus versions
  • Between different excel input files
  • and I need at least guaranteed width:height proportions, best would be guaranteed image size.

    Note: I can't create and use an image at 96 DPI here, since this results in very pixelated printing.

    Edit:

    The following image shows the result for a file with a bit irregular layout that I just created as showcase. The green box is the inserted image, the messed up proportions are highlighted in the dialog window (its in german, but the relevant things are the numbers anyway).

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


    In case someone runs into a similar problem, here is what I do to fix my specific problem.

    Excel is stretching the image in page view , compared to normal view . Since I don't care about image proportions in normal view, I can adjust the image size. I analyzed the stretching for my case and found the following ranges for 96 DPI adjusted image widths (height was not changed in my case):

    Note that the correction values are not 100% accurate, since there are also some rounding errors in image size transformation for different 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
    

    This means that most widths can be adjusted by subtracting the mentioned offset. For border cases between different offsets, a small error will remain. The following width transformation function ( AdjustExcelPageViewImageWidth ) implements correction for the described errors

    /// <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;
    }
    

    The other problem - different behavior of EPPlus SetSize(percentage) between versions was avoided by using the SetSize(widthPx, heightPx) function.

    So, my final implementation would be similar to the following:

  • Adjust width and height from image resolution (300 DPI) to screen resolution (96 DPI)
  • Then adjust width for excel page view
  • .

    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"));
        }
    }
    

    The result naturally has some minor rounding errors, since EPPlus takes size as integers, but the image proportions are not visibly distorted anymore.

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

    上一篇: CSV与EPPlus解析问题

    下一篇: EPPlus AddPicture 100%大小