以OpenXML格式将.NET像素转换为Excel宽度的公式

时间:2011-10-10 16:52:51

标签: c# openxml

我花了很多时间尝试使用OpenXML格式确定将.NET像素转换为Excel列宽的公式。我正在使用EPPlus生成xmls文档。我正在尝试确定要自动调整大小的列的宽度。我通过测量字符串然后尝试将其转换为OpenXML的列宽来获取像素数,这是用我认为的字符来衡量的。

我已经阅读了微软关于如何转换它的文档,并尝试了他们建议的公式,但它甚至不准确:

http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.column.aspx

这是我的代码使用他们的公式:

    public double GetCharacterWidth(string Text, Font f, Graphics g)
    {
        float MaxDigitWidth = g.MeasureString("0", f).Width;
        float Pixels = g.MeasureString(Text, f).Width;

        return ((Pixels - 5) / MaxDigitWidth * 100 + 0.5) / 100;
    }

有什么想法吗?

3 个答案:

答案 0 :(得分:19)

首先,我们需要确定Excel如何进行转换(因为我们手动更改Excel应用程序中的大小):

//Use 7d to promote to double, otherwise int will truncate.
ExcelWidth = (Pixels - 12) / 7d +  1;//From pixels to inches.

警告:公式不适用于0(零)宽度或像素。
对于这些情况,使用“if”语句检查是否为零并返回零。

它也把我扔了一圈。我没有试图找出每个宽度的像素,而是查看每个宽度整数之间的像素差异,发现它始终为7.异常为0到1宽度;宽度为1.00的12个像素。从那里我能够拿出上面的公式,轻松自如。

现在这些数字在Excel世界中占据了一席之地,但如果您直接在OpenXml文档中设置列宽,那么这个故事就会略有不同。原因如下:在您链接的文档中,这是关于5像素的说明:

  

边距填充有4个像素(每边两个),加上网格线的1个像素填充。

现在所有这些意味着Excel假设您已将这5个像素考虑到您提供的宽度中。当您在Excel中打开文档并调整列的大小时,您将看到宽度比您设置的宽度小5个像素。

要调整此项,您可以按如下方式更新公式:

//Use 7d to promote to double, otherwise int will truncate.
OpenXmlWidth = (Pixels - 12 + 5) / 7d + 1;//From pixels to inches.

这回答了你的问题的标题:
将.NET像素转换为OpenXML格式的Excel宽度的公式

如果您想知道如何根据单个单元格的内容(和字体)计算列宽的近似值来自动拟合列,那么这是一个完全不同的问题。您提供的Microsoft链接提供的公式将不起作用。在一个单元格中键入10个句点,在另一个列中键入10个大写字母。您将看到自动调整分别为您提供41像素和129像素。 ms提供的公式不考虑单个字符的宽度。换一种说法;他们派你去疯狂追逐。

自动调整列的唯一方法是扫描列中的每一行,并根据使用的字符和字体计算文本的宽度。你会使用我发现的here之类的东西。然后取5的最大值并用5填充。我会在Web环境中处理电子表格时避免这种方法,因为你可能导出数十万行数十列 - 你明白了。最好的方法是为列设置最佳猜测宽度,并培训用户如何从excel自动适应。

此致
普通人


修改 - 10/26/2011:

因为我感觉很慷慨,所以这里有一个如何为你的列获得近似宽度的例子。我宁愿避免对列中的所有行执行此操作,因此我们只需将宽度(默认情况下)基于标题单元格中的值。以下是使用我之前链接的示例执行此操作的方法。注意:这些是近似值,但足够接近。

using System.Drawing;
using System.Windows.Forms;//Add Reference.  Test on webserver first.
Font font = new Font("Calibri", 11.0f, FontStyle.Regular);
string header  = "Hello There World!";
int pxBaseline = TextRenderer.MeasureText("__", font).Width;
int pxHeader   = TextRenderer.MeasureText("_" + header + "_"), font).Width;
int pxColumnWidth = pxHeader - pxBaseline + 5;//Pad with 5 for Excel.

警告:如果您在使用OpenXml的同一个地方使用此代码,则可能需要删除System.Drawing的“using”并完全限定“Font”和“FontStyle” “作为System.Drawing.Font和System.Drawing.FontStyle。否则,您的编译器可能会将这些类误认为属于DocumentFormat.OpenXml.Spreadsheet。

答案 1 :(得分:1)

由于我在第3 dp出现差异,因此对MikeTeeVee给出的答案进行了升级。

在根据OpenXml文件宽度计算点宽时,文档说明

列宽,以正常样式的字体中呈现的数字0、1、2,...,9的最大数字宽度的字符数来衡量。边缘填充有4个像素(每侧两个),网格线有1个像素填充。

width =截断([{字符数} * {最大数字宽度} + {5像素填充}] / {最大数字宽度} * 256)/ 256

这使我在黑暗实验中几乎陷入了僵局,并提出了从像素到宽度的转换:

double width = Math.Truncate(px / 7 * 256) / 256

这将返回与OpenXml文档中完全相同的值。

答案 2 :(得分:0)

我想出的将像素宽度转换为Excel宽度的公式是

    private double PixelWidthToExcel(int pixels)
    {
        var tempWidth = pixels * 0.14099;
        var correction = (tempWidth / 100) * -1.30;

        return tempWidth - correction;
    }

对我来说,它总是可以进行精确的值转换。

还有高度公式

    private double PixelHeightToExcel(int pixels)
    {
        return pixels * 0.75;
    }