Excel列宽像素值计算方法详解

字数不多,全是干货;
心血凝结,全网唯一;
如有帮助,请您点赞;
未经许可,禁止转载!

申明:本文是个人原创,目前只发表于CSDN平台。

前两年基于Apache POI做了个Excel转Html的程序。为了让HTML中列宽的显示尺寸精确吻合Excel原生显示尺寸,做了大量的研究和试算,不同字号不同字体测试了N多种组合,最终完美还原了Excel列宽像素计算方法。今天有空,为了知识不被遗忘,写个博记录一下,全网独一份哦!

首先,要知道每个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是按照下面的步骤计算列宽的:

  1. 48号的宋体,字符宽度是32像素(别问我是怎么知道的,不信你量一下)。Excel默认列宽要求必须完整显示8个字符,所以字符总宽度为8*32=256px;
  2. padding = 向上取整(DFW/4) = 8px,两边总共16px,再加上1px的网格线,现在的宽度=256+16+1=273px。
  3. 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把系统所有字体所有字号所有格式(下划线、加粗等)循环一遍生成数据集,使用的时候直接查表,系统没有安装的字体就没办法了,只能当成默认字体处理。如果看官有简单准确的办法精确计算字体宽度,请不吝赐教!

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值