Excel列宽像素值计算方法详解
Posted 沙漠豪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Excel列宽像素值计算方法详解相关的知识,希望对你有一定的参考价值。
字数不多,全是干货;
心血凝结,全网唯一;
如有帮助,请您点赞;
未经许可,禁止转载!
申明:本文是个人原创,目前只发表于CSDN平台。
前两年基于Apache POI做了个Excel转html的程序。为了让HTML中列宽的显示尺寸精确吻合Excel原生显示尺寸,做了大量的研究和试算,不同字号不同字体测试了N多种组合,最终完美还原了Excel列宽像素计算方法。今天有空,为了知识不被遗忘,写个博记录一下,全网独一份哦!
首先,要知道每个Excel文件都有一个缺省字体定义,包含了字体、字号信息。这个缺省字体是在Excel选项中指定的,当新建一个工作簿时就被作为内置属性在文件中固化下来。如下图所示:
该字体的宽度被作为一个基本度量单位用于与列宽相关的计算。POI源码中涉及像素、缺省列宽的计算是大多是错误或者说不完善的,其中最主要的一点就是其对Excel的缺省字体宽度没有正确获取,在3.x版本中(4.x没看过)直接硬编码了一个数字8(好像是)作为字体宽度,且对单元格padding部分的处理不正确,因此后续相关的像素计算都得不到正确结果。我在做Excel转Html的过程中,不得不自行研究计算,最终能生成像素级一致的HTML,效果非常好。
下面开始讲解Excel是如何进行像素计算的。具体来说是这样的:
- 对Excel来说默认字体有一个缺省宽度,其定义是0-9这10个字符中最宽的字符的像素值。以下,我简称该值为DFW(Default Font Width)。
- Excel的列宽总是以DFW为单位,而与当前列或单元格中的实际字体无关。当在Excel中设置列宽时,对话框中输入的数字即是DFW的倍数,其含义是该列能显示多少个缺省字体字符。下图是缺省字体为"宋体,48"时缺省列的宽度。
- 列宽的精确像素值由所能容纳的字符总宽度、两端的空白(padding)和1px的margin(网格线)组成,其中padding是DFW除以4后的向上取整值。整体计算步骤略微复杂,下面通过实例来讲解。
首先,请把Excel的默认字体设置为"宋体,48",然后新建一个文件,查看任意一列的列宽一定为8.22(参见上图)。这个8.22是怎么来的呢,和列的像素宽度有什么关系?敲黑板,Excel是按照下面的步骤计算列宽的:
- 48号的宋体,字符宽度是32像素(别问我是怎么知道的,不信你量一下)。Excel默认列宽要求必须完整显示8个字符,所以字符总宽度为8*32=256px;
- padding = 向上取整(DFW/4) = 8px,两边总共16px,再加上1px的网格线,现在的宽度=256+16+1=273px。
- Excel规定每列的像素宽度必须是8的整数倍(为了在滚动时提高渲染性能),故把273px向上取整为8的整数倍,得到280px,这就是该列最终在屏幕上占据的实际像素宽度,不信拿尺子量。
现在我们已经计算出默认列宽为280像素,再来算一下究竟能显示多少个缺省字符。很简单,去掉第2步中的padding和margin共17px再除以DFW,即(280-17)/32 = 8.22,与Excel中实际看到的完全一致。这就是缺省列宽为8.22的来历。如果给Excel指定不同的默认字体,你会发现缺省列宽无规律地变来变去(但肯定大于8),这都是上述算法造成的结果。
在上述过程中,最核心的数值是DFW。它是怎么得到的呢?换句话说,在Java中如何得到任意一种字体的0-9数字的最大宽度?我试过stackoverflow或apache论坛等各种渠道找到的计算方法,比如用java.awt.font.TextLayout,都无法得到完全准确的结果,有时候正确,有时候会差一两个像素。最终我是用了一个很low很粗暴的方法在有限条件下解决,就是写了个windows小程序通过windows API把系统所有字体所有字号所有格式(下划线、加粗等)循环一遍生成数据集,使用的时候直接查表,系统没有安装的字体就没办法了,只能当成默认字体处理。如果看官有简单准确的办法精确计算字体宽度,请不吝赐教!
以上是关于Excel列宽像素值计算方法详解的主要内容,如果未能解决你的问题,请参考以下文章
C#导出excel表格AutoSizeColumn这个方法是啥意思,以及参数详解,在线等