联动 关于解决问题的套路。
1. 概述
笔者之前的文章关于解决问题的套路中从理论层面阐述了笔者对于解决问题套路的个人理解和总结,但并没有附上一个相应的示例进行对比验证,正好笔者最近在部门内部一个需求比较典型,本文就以这个需求为范例,复盘笔者在整个问题解决过程的思路。
2. 背景
在这段解决问题的经历中,笔者是作为救火队员介入的。初次接触到问题时候,得到的问题描述是"在进行附件打印时,附件格式由HTML转换到PDF时,下图所示的特殊繁体字无法显示"。 pin - 繁体字3. 获取更为详尽的问题上下文
在知晓问题的大致情况后,经过与一线人员的进一步沟通,获得如下额外信息:
- 上面这个繁体字只有在一种情况下(安装Sogo输入法)能够在文本编辑器和IE浏览器中显示出来,但转换到的PDF中依然无法正常显示这个字。
- 在安装Sogo输入法之后,IE浏览器可以正常显示该文字,但在Chrome下却依然无法正常显示。一旦卸载,则IE和Chrome均无法正常显示该文字。
4. 初步分析
- 首先根据需求,我们要求一线人员将包含该繁体字的HTML页面直接保存到本地并发送过来,搭建快速测试环境。
- 对上面保存在本地的HTML页面,分别用多个不同类型的浏览器打开,排除浏览器的影响。最终结果:各个浏览器上均无法正常显示。
- 直接使用Notepad++ / Notepad编辑器打开本地HTML页面,观察其是否存在差异(查看是否在某一端无法显示,而其他端正常),排除编辑器的影响。最终结果:在不安装Sogo输入法的前提下,各端均无法正常显示。
- 将本地HTML在其他研发人员电脑上打开测试,排除电脑环境的影响。最终结果:相关人员上也无法显示。
- 安装Sogo输入法,观察繁体字是否正常显示。最终结果:正常显示。
- 在上一步的基础上,不断删减Sogo安装包中的内容,直到只剩下"强力删除"功能都无法根除的文件。最终结果:字体依然正常显示。
- 上一步的基础上,直接卸载Sogo输入法。最终结果:字体不能正常显示。
- 对比安装Sogo输入法前后Windows字体库(C:/Windows/Fonts文件夹下)字体数量的变化。在接到这个需求的第一时间,笔者就感觉问题应该出在字体上,但这个字体是哪一种?笔者在安装Sogo输入法之前就在Windows的默认字体库下汇总了现有字体库的数量,但是在Sogo输入法安装完毕之后,发现数量没有变化。证明这条路是死胡同。
- 在以上多次尝试均告失败之后,不得不祭出人类解决问题的常见套路之一 —— "小步前进,频繁测试"。 通过查找资料,找到使用Total Uninstall监控软件安装了什么文件,修改了哪些注册表,然后暂停手上的一切其他事情,关闭其他所有非必要应用,只开启打开着本地HTML的Notepad++和Total Uninstall软件,按照操作步骤将Sogo安装前后的操作系统变化汇总出来,然后通过"按名称猜测"+"折半删除"来不断缩小范围,辅助以每一小步操作之后直接重启电脑的方式确保操作影响的真实反馈,并且在每次删除操作之前记录删除的项,并记录操作带来的影响。最终笔者定位到一个名为 EUDC 的注册表项。
- 通过网上搜索EUDC的名称定义(End-User-Defined-Characters),大幅增加了对其导致问题的怀疑,然后从注册表中删除该键值对并重启电脑,通过往复尝试最终确定Sogo引入的EUDC能够修复该繁体字无法显示的问题。
- 在确定了EUDC的作用之后,再次查找资料,确定在Java语言的第三方Office类库Aspose下如何实现对于EUDC的引用,最终实现对于繁体字在PDF下的正常显示。
5. 优化
在上一步中,我们采取Java代码方式转换出来的PDF布局方面都存在比较大的缺陷,而相比较之下采用 wkhtmltopdf 工具转换出来的PDF不论在转换效率还是保真度方面都着非常大的优势。
因此现在我们有了两种选择:
- 使用Java第三方库进行的PDF转换。优点是繁体字可以正常显示,缺点是需要进行PDF美观度调整,但我们对该第三方库的掌握并不熟练,调整耗时上不好评估。
- 使用wkhtmltopdf进行转换。优点是转换效率和保真度方面都着非常大的优势;缺点则是无法正常显示繁体字,而我们经过查看该EXE工具的可配置参数发现其并没有提供直接的字体配置选项。
通过以上清单我们可以看出两个方案各有千秋,这里就存在我们在解决问题时候经常会陷入的一种情况:在多个可行性方法之间犹豫,而这些方法彼此之间都会对问题本身的某个方面有自己独到的优势,这种情况随着我们在挑选出其中一个方法进行深入研究过程中遇到困难无法前进时候,我们会更加怀疑自己正在进行的决策,以及强烈的切换方案的冲动。在已选方案的沉没成本和未知前景,以及另外一个同样未知前景的方法之间反复纠结,这会导致大量时间被浪费在踌躇之中。
这里不得不说,笔者在上面两种方法之间,其实并不是在一开始就认准了一种方法然后一条路走到黑的:
- 笔者一开始是打算按照Java第三库的方式进行样式调整,但发现该第三方库天朝局域网内相关资料稀少不说,即使是官方文档也是很难找到相应的范例,而源码方面也是被混淆过,难以阅读。而且笔者一开始是在Aspose.PDF相关的文档中寻找解决方案,后来查找资料的过程中又接触到可能需要使用他家的Aspose.HTML,在这些方案细节之间的来回切换也是耗费了笔者不少时间的。
- 而对于wkhtmltopdf工具,笔者一开始并未选择它,毕竟在笔者看来,其作为一个EXE,封装度远高于JAVA第三方库,找到突破口的可能性相较于前者应该低不少。
事情的转机来自于笔者在搜索EUDC的过程中发现的[Font]使用者自造字(EUDC)成功转到 PDF 的方式 和 [Font]让浏览器显示使用者自造字(EUDC)的方式两篇文章。这里需要介绍下笔者发现这两篇文章的经历:
-
笔者首先找到的是第一篇"[Font]使用者自造字(EUDC)成功转到 PDF 的方式",但读者如果查看过这篇文章就会发现,文章中的图片和指示性链接都无法正常展示,最终结果是笔者在阅读其中内容时候虽然大致认同其说明的问题与笔者面临的问题关联性较高,但文章本身的信息缺失度过高,导致无法重建出文章作者的解决过程。而且这个时候笔者并没有意识到第一篇文章中的“选取'让浏览器显示使用者自造字(EUDC)的方式'中产生出来的 自造字 TTF 档”这一句其实是指向上面第二个参考连接的。
-
机缘巧合之下,笔者在搜索引擎上找到了[Font]让浏览器显示使用者自造字(EUDC)的方式,看到此文的时候,笔者并没有第一时间将其和前一篇博文联系起来,但在此文中笔者注意到一句非常有意思的文字:“可以发现在 IE 上完全没有问题,但是在 Chrome 及 Edge 就挂了,完全出不来”。结合最开始我们提到的问题场景,再结合文章的标题,让笔者萌生出了参考该篇博文,将该繁体字在Chrome中展示出来的念头。到此其实笔者并没有想过"将该繁体字在Chrome浏览器中显示出来能对问题的推进有什么帮助?"的进一步考虑,只是潜意识地认为如果能够在Chrome中正常显示该繁体字,那是不是能够在使用wkhtmltopdf工具进行转化时候也能正常显示了。(注意此念头在当时的笔者看来还只是一个潜意识的怀疑,并不能被落在计划清单里)。
-
参照[Font]让浏览器显示使用者自造字(EUDC)的方式,笔者主要做了两件事:
a. 下载 FontForge,使用其 File > Execute Script 功能执行上述博文中给出的脚本,将TTE转换为 TTF。(笔者原本使用FontForge是为了将EUDC合并到Windows常用字体中[参考[Font]使用者自造字(EUDC)成功转到 PDF 的方式 ],而且一开始笔者是按照博文建议的采用命令行进行的合并操作,但因为在合并之后导出来的TTF在放入Fonts时无法被Windows识别,导致一直对该TTF的正确性存在怀疑。而FontForge的 Execute Script 正是在笔者挨个查看FontForge的菜单过程中发现的,毕竟笔者直到今天才知道这个软件的存在)。
b. 下载 Chrome-Stylish插件执行上述博文中提供的CSS脚本。(注意该脚本有个坑....我们之后再说)。关于这一步笔者也不是一开始就找到的这个插件,而是在参考了博文之后,发现作者就"透过 Chrome 来执行CSS脚本,就可以正常显示自造字了"的截图喜闻乐见地404了,迫不得已笔者通过搜索“Chrome修改样式”找到了知乎答案 - Chrome 如何修改字体?,不得不说多亏了这篇答案。 -
上一步的举措并不顺利,首先是插件安装时候一开始的版本有问题,经过一些风波之后很快解决,然后就是上面提供的CSS脚本一开始是不生效的,这个时候笔者通过Chrome中多个Table页对比,以及简化CSS脚本的方式,最终确定必须采用web服务器的方式访问页面才能让Chrome-Stylish插件生效。于是笔者又在本机上启动了一个Nginx代码服务器。
-
结合第三步获得的TTF文件(注意此时笔者并不能确定其是否有效)以及上面提供的CSS脚本进行本地化适配——主要是修改woff和ttf文件的所在路径(此时笔者并不了解CSS脚本中的@font-face的确切含义),最终在Chrome中将繁体字正常显示出来了。(至此笔者终于能够肯定之前转换出来的TTF是有效的)
-
其实到了这一步,笔者有些迷茫了 —— 接下来呢? 迷茫之下笔者再次拾起wkhtmltopdf工具,心怀幻想着"现在Chrome下能够正常显示了,那你应该能够正常转换了吧?",最终果然是外甥打灯笼——照旧。期间笔者还不死心地多试了几次。
-
笔者在上一步的尝试中,再次查看了wkhtmltopdf工具的详细参数,注意到其有一个
--user-style-sheet
参数,而我们在第三步中提到的CSS样式不正好可以用吗? -
上一步经过笔者的反复验证,最终宣告失败。笔者接下来的想法是既然外部引入CSS样式不行,那我直接把这段CSS写死在HTML文件里呢?
-
上一步的猜想最终还是失败了。笔者再次查看wkhtmltopdf工具的详细参数,猜测使用
--allow
参数来告知wkhtmltopdf工具可以访问哪些目录,依然失败。 -
笔者回想起第五步中必须使用静态访问服务器地址的方式让字体在Chrome下正常显示,难道wkhtmltopdf工具也需要这样?反正也没有路了,直接上吧。
-
上一步依然失败。笔者灰心之下,再次回到wkhtmltopdf工具GitHub的ISSUE区,通过关键字"font chinese"定位到GitHub-wkhtmltopdf-ISSUE-chinese,从中找到了一篇引导性链接 @font-face 解决wkhtmltopdf的中文显示问题,正是这篇2013年发表的文章奠定了成功的基石。
-
在上一步找到的文章基础上,笔者再次回顾第三步中的CSS脚本:既然GitHub ISSUE中当事人说明自己解决了,而且他的解决方案与我们找到的如此相似,而且我们使用该方法使繁体字在Chrome下也正常展示出来了,那么为什么我们会卡住? 基于以上疑问,笔者在参考上一步找到的链接中的CSS脚本,对第三步引入的脚本进行不断删减,并在此期间对CSS3的
@font-face
含义进行了初步的了解。 -
最终在将第三步引入的CSS脚本删减到第十一步中的CSS雷同,并且将TTF地址由本地文件地址切换为WEB静态文件地址之后,PDF正常展示了繁体字效果。(这就是上面说的第三步CSS脚本的坑点,它定义的 font-family 属性配置了太多的值,导致我们自定义的EDUC无法发挥作用)
/* 导致失败的原CSS脚本 */
@font-face {
font-family: EUDC;
src:url('http://localhost/SGPYEUDC_1.woff?v=1.0.0');
src:url('http://localhost/SGPYEUDC_1.woff?v=1.0.0') format('woff'), url('http://localhost/SGPYEUDC_1.ttf?v=1.0.0') format('truetype');
}
body {
font-family:"Microsoft JhengHei", "新细明体", "细明体", Arial, "EUDC";
}
/* 最终成功的CSS脚本 */
@font-face {
font-family: EUDC;
url('http://localhost/SGPYEUDC_1.ttf?v=1.0.0');
}
body {
font-family: EUDC;
}
6. 回头看
事情解决之后回头看,我们发现如果:
- 知道EUDC的定义,及其生效方式(注册表)。
- 知道 topdf.exe设置字体的方式(通过CSS样式在HTML中设置)。
- 一开始就能在wkhtmltopdf工具的GitHub ISSUE区多找一会,如果能够对wkhtmltopdf工具多一些信心。
我们将能省却很多弯路的时间,这就是所谓的基础不牢,地动山摇;联想到不少研发人员宣称的"等用到的时候,我自然会去学了",execuse me?
7. 最后
7.1 问题解决之后的收尾操作
正如OOP中对象的创建,使用和销毁一样,我们在解决问题的时候也要参考这个思路,问题解决之后我们还要进行现场的清理工作:
- 删除中间数据。例如在进行wkhtmltopdf工具转换时候的中间文件和文件夹,下载的一些工具软件等等。
- 对解决问题过程中找到的资料进行汇总入档,为下一个问题积累工具集和思路。
7.2 唯心论
这一小节笔者想谈一些与理性思考比较远的内容。例如"信心",也就是对于眼前问题一定能够被你解决这事情的把握。对此笔者个人观点是:一定要对此抱着120%的信心,信心可以来源于对自己过去多年的刻意沉淀,也可以来自对于眼前问题的深刻理解,但这里笔者要补充的是:哪怕你是毫无根据的信心,只要你真的能够让自己打心底去认可,这也是非常值得鼓励的行为。很多时候支撑人们熬过成功前最为艰难的那段岁月的,除了无路可退外,剩下的绝大部分归因可以交付给"信心"。
网友评论