Word转HTML的裁剪图,裁对了的那个反而会挪位

18 阅读6分钟

Word 转网页这件事我之前只盯着文字和表格乱没乱,图片我一直默认不会出事。这回我拿一份带裁剪图的文档挨个试转换工具,最先把我看愣的不是哪个工具没裁,是裁对了的那两个把图上方的标题给盖住了。图映工作台里那行标题只露出「截图:」三个字。我手上这台 Mac 没装 Word,测试用的 docx 是我对着 OOXML 的文件结构一块块手写出来的,没经过 Word 保存。里面放了 7 个图片用例,有只缩放的、四边裁的、旋转 15° 的和不等比拉扁的。另外几个是裁掉截图下方收货信息的、裁完再转 90° 的和四边各裁 15 % 的。图只用了两张。风景照借的是 Dietmar Rabich 放在 Wikimedia Commons 上的一张,许可是 CC BY-SA 4.0。截图那张是我给自己写的订单后台演示页拍的,上面的收货人、手机号、地址和流水号都是编出来的。整份文件有 7,234,550 字节。

裁对了的图会往上挪

盖住标题的是 docx-preview 0.4.1 和图映。前者是前端常见的 docx 预览库,我放在自己写的预览页里跑。后者我用的是图映 ImgIng(imging.cn/)的 DOCX 转 HTML,测的同样是这份 7 个图片用例的样本 docx,浏览器是 Chromium 149 开源构建。这两个其实都把裁剪认对了。被裁掉的收货信息在页面上确实看不到,缩放也是按图框来的。毛病出在位置上。只裁下边的用例 D 在图映导出里整张往上移了 70.4 px,在 docx-preview 里是 69.7 px。这个量差不多是裁掉那块高度的 1/3。图一往上移就压到了它上方那行字,我第一眼还以为是标题本身没写全。

用 docx-preview 转换,裁剪区域对了,但图整体上移,把上方标题盖得只剩几个字

不对称的裁剪才会偏

裁剪在 docx 里是怎么记的得先说两句,不然偏移这事讲不清。文件里存的其实是整张原图。裁剪只是一行 srcRect 记着四条边各裁掉了百分之多少。缩放记在 wp:extent 里面,旋转记在 a:xfrm 的 rot 上。我翻了 docx-preview 输出里的 style,它先用 clip-path 把可见区截出来再用 transform 放大到图框那么大。transform 默认是绕着元素中心放大的。只裁一边的话留下来的那块就会被推向另一边。四边裁得不一样多的用例 B 在图映导出里往右偏了 58 px 又往上偏了 19 px。四边各裁 15 % 的用例 G 倒是一点都没偏。图映导出的偏移数字跟这个算法对得上。它内部到底怎么实现的我没去拆,这里就不瞎猜了。

旋转是另一种毛病。这两个都把方向转对了,可它们都没按旋转后的外接框给图留出位置。转 15° 的用例 C 上下各超出图框约 45 px。裁完再转 90° 的用例 F 直接压住了上下两行字。图映这边还有两件事我顺手记一下。7 个用例从导入到转换的整个过程里界面上没出过一条警告,裁剪和旋转都没有任何提示。整个转换过程里我数到的非 GET 请求是 0 次。

图映工作台里同一张截图,收货信息看不见了,但图同样上移,标题只露出「截图:」

别的工具错在别处

我又拉了三种方式来对照,它们错的地方各不一样。另一个前端常见的库 mammoth.js 1.13.0 同样放在预览页里跑。剩下两个是 Mac 自带的快速查看和 textutil 命令。

方式裁剪缩放旋转
docx-preview 和图映内容对但会偏位认方向对但会压字
mammoth.js显示整张不认不转
快速查看整张压进图框认认
textutil图全丢了无图无图

我一开始以为快速查看会垫底。它说到底只是个用来看缩略图的东西嘛。结果缩放和旋转两样它都做对了。用例 C 和 F 都转了过来。拉扁的那张在它这里宽高比是 3.018,跟应有的 3.0 差不多。可它完全不认裁剪,整张原图被硬压进了图框里。用例 D 那张截图于是被压扁了,收货信息还是照样看得见。mammoth 是三样全都不认。它给图片不写宽高就直接按原图比例铺满容器。在我那页 900 px 宽的容器里拉扁的那张没被拉扁,旋转的那张也没有转。textutil 最干脆,它的输出只有 1,380 字节,连一个 img 标签都没有,7 张图一张不剩。

看着对的也要解一张图

显示对不对还只是好不好看的问题。更要紧的是被裁掉的那块到底去了哪里。mammoth 最直接。它输出里的 7 张图全是整张原图,用例 D 的收货信息就摆在页面上。docx-preview 的图走的是 blob 地址,背后同样是整张原图。图映那份导出一共 9,665,338 字节,里面 7 张内联图片全是整张原图,跟 docx 里存的那几张逐字节相同。图片字节在这份文件里占了 99.7 %。我把用例 D 那张单独解出来是一张 1800×1240 的整张 PNG,收货信息、手机号、地址和流水号都在上面。右键图片另存为拿到的就是这份字节,页面上那块看不见只是没显示出来。docx 本身也一样。把后缀改成 zip 解压开以后 word/media 里放着的就是整张图,拿到这份文档的人不用任何转换工具也能看到。

用 mammoth 转换,裁掉的收货信息原样出现在页面上,红框里就是

发出去之前先烘焙裁剪

CSS 不管怎么写都只能让那块不显示。原图还是会跟着网页一起发出去。真要去掉就得在转换前把裁剪做进图片里。这一步我是拿脚本做的,按 srcRect 把图真裁掉之后再把 srcRect 清空。整份 docx 因此小了 21.0 %。再拿图映转一次导出从 9.22 MB 降到了 7.28 MB。用例 D 的偏移从 70.4 px 降到 0.4 px,那行标题完整露了出来,收货信息在文件里也没了。偏位和泄露是一起消失的。这点我挺意外。mammoth 在烘焙后显示的也是裁好的画面,只是尺寸照旧不管。微软的支持页里有个选项叫「删除图片的剪裁区域」,勾上它才会把裁掉的部分真删掉,应该能做到同样的事。我手上没有 Word 也就没试过。Word 保存时会不会自动删我也测不了。

这次没测到的也记一下。Word、WPS、LibreOffice 和 pandoc 都没有测。WPS 在本机倒是能打开,可这次没拿到它的显示结果。只能算没测。图映导出在 Firefox 和 WebKit 下长什么样我没看。浮动图也没碰,样本也只有两张图。挑工具的话,只要文字的用 mammoth,要版式的用 docx-preview 或图映,转完先翻只裁了一边的图和旋转过的图有没有盖住上下的字。要发给别人的文档我现在会先改成 zip 翻一眼 document.xml,搜到 srcRect 就先烘焙再转换,转完再解一张内联图出来核对尺寸。