微信公众号文章中可插入的富文本格式不如一般的博客自由,但目前来说也是中文互联网勉强都能接受的一个平台和事实标准了。然而,在撰写理工相关的文章时不免要用到数学公式,微信公众号不支持数学公式的插入和编辑,用图片(位图)代替又比较麻烦,截图、上传,尤其是行间公式排版相当麻烦。

目前来说,最佳的方案是将公式转换为 SVG 图片格式插入。SVG 是矢量图格式,在不同设备上都能清晰显示,而且可以以 DOM 的形式嵌入到富文本中,还有简单而严格安全的交互功能。

但是就目前可查阅到的资料来看,实现这一功能的仅有 ciaochaos 实现的微信公众号公式编辑插件和部分功能收费的 MdNice。笔者在这近一个月的时间里,结合这两年对数学公式排版的研究经验,对功能实现的一些技术难点一一突破,下面简记之,供自己参考。

分析 tex-svg-full.js

MpMath 插件的核心模块是引用的 MathJax 的tex-svg-full.js 文件,这个文件提供了所有数学符号对应的 SVG 数据,均是以 path 绘制的,如

8715:"96 251Q96 268 119 281H363Q607 281 607 283Q607 295 600 319T576 379T519 451T425 507Q386 521 361 523T233 526L119 527Q96 535 96 557Q96 578 116 585Q121 587 229 587Q238 587 257 587T288 588Q366 588 435 568T568 488Q670 388 670 251Q670 155 621 78T499 -39T345 -85Q336 -86 225 -86L119 -85Q96 -77 96 -55Q96 -38 119 -25H233Q356 -24 371 -21Q373 -21 393 -16Q468 3 523 55T599 177Q607 206 607 218Q607 220 363 220L119 221Q96 229 96 251"

MathJax 的大版本互相不兼容,主要的版本是 MathJax 2.x、3.x 以及最新的 4.x,4.x 不再在原有的 Repository 基础上修改,而是另起炉灶为 MathJax-src Repository。

所以在分析时要分清版本。MathJax 3.x 版本路径如下

https://github.com/mathjax/MathJax/blob/develop/es5/tex-svg-full.js

该文件应该是由 output/svg/fonts/ 文件打包而成的。如下 tex.js 文件中就包含了大部分数学符号的 SVG 数据。

https://github.com/mathjax/MathJax/blob/master/es5/output/svg/fonts/tex.js

ciaochaos 的插件中用的 tex-svg-full.js 如下

https://raw.githubusercontent.com/ciaochaos/mpMath/master/mpMath/assets/js/tex-svg-full.js

文件体积还略大于官方的版本,暂不清楚原因。

更多版本的 tex-svg-full.js 如下

https://www.cdnpkg.com/mathjax/file/tex-svg-full.js/?id=53958#

MathJax 2.x 是没有 tex-svg-full.js 的,而是分成各个字体,各字体又分 AMSVariant 这些目录,目录中的 javascript 文件中定义一部分符号的 SVG 数据。

https://github.com/hemashushu/mathjax-compact/blob/master/jax/output/SVG/fonts/STIX-Web/Alphabets/Bold/Main.js

但不知道为什么,MathJax 3.0 版本开始后,就不再提供其它数学字体了(包括 STIX 字体),至少在 Repository 中看不到了。因此下面的链接是不存在的。

https://github.com/mathjax/MathJax/tree/master/fonts/HTML-CSS

需要切换 branch 到 MathJax 2.x 的版本,如下

https://github.com/mathjax/MathJax/tree/woff2/jax/output/SVG/fonts/STIX-Web

https://github.com/mathjax/MathJax/tree/v2.6-latest/fonts/HTML-CSS/STIX-Web

需要注意的是,MathJax 2/3 在对数学符号编码时可能有不同之处,可能有的 dict key 用的是十进制数字,有的是十六进制数字,无法直接对应。

GitHub 还有对 MathJax 2.x 的散碎文件整体合并的版本:

https://github.com/hemashushu/mathjax-compact/tree/master/jax/output/SVG/fonts/STIX-Web

https://github.com/pkra/MathJax-single-file/blob/master/dist/TeXSVGSTIX-Web/MathJax.js

MdNice 的实现

MdNice 将 Markdown 转换为适合微信公众号排版的样式,数学公式用的是 MathJax。最后将渲染的 DOM 复制粘贴到微信公众号。

粘贴到公众号

复制时格式必须为 text/html,所以要借助 JavaScript 实现。

function copyToClip(str) {function listener(e) {e.clipboardData.setData("text/html", str);e.clipboardData.setData("text/plain", str);e.preventDefault();}document.addEventListener("copy", listener);document.execCommand("copy");document.removeEventListener("copy", listener);
};

代码来自:Copy to clipboard pure JavaScript - JSFiddle - Code Playground,实测可用

或者引入 JavaScript 库:clipboard.js — Copy to clipboard without Flash (clipboardjs.com)

除了 Web 端,在桌面应用多次测试,Python 是无法实现这样的功能的,至少用 win32clipboard 模块是无法实现的(CF_TEXTCF_UNICODETEXTBytesStr 等多种数据类型和剪贴板类型均无效)。

MathJax 渲染为 SVG

MathJax 目前在国内外是事实上的前端数学公式排版标准,但是 MathJax 还是比较重,加载较慢;相对的 KaTeX 的渲染方法更加传统,速度更快。然而 KaTeX 到目前也不支持 SVG 渲染,所以可选的只有 MathJax,将 MathJax 的 LaTeX 数学公式渲染为 SVG。

但是,MathJax 渲染的结果通常使用 cache 技术,用 <use> 标签的引用调用数学字符的数据 path 加快页面显示效率。然而,这样的结果复制到公众号是无法正常显示的,必须要复制完整的 path。

<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="5.21ex" height="2.301ex" viewBox="0 -764.4 2243.1 990.7" role="img" focusable="false" style="vertical-align: -0.525ex;"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xlink:href="#STIXWEBMAINI-61" x="0" y="0"></use><use xlink:href="#STIXWEBMAIN-2260" x="779" y="0"></use><use xlink:href="#STIXWEBMAIN-30" x="1742" y="0"></use></g>
</svg>

相关链接参考:

https://codepen.io/pkra/pen/RwbyKM

http://www.russellcottrell.com/blog/MathJaxEditor.htm

MathJax 官方提供的测试工具

最终还是靠查询官方文档解决问题:The SVG output processor — MathJax 2.7 documentation,更改 useFontCache: true 配置,将其设置为 false

如下 MathJax 4.x 的配置方法,以供参考(MathJax 3.x 配置参数基本相同,更低的版本可能不同,不推荐使用)

MathJax.Hub.Config({jax: ["input/MathML","output/SVG"],extensions: ["mml2jax.js","MathEvents.js"],MathML: {extensions: ["content-mathml.js"]},SVG: {mtextFontInherit: true,blacker: 1,useFontCache: false,       // 禁用 cache, 输出每个字符的 path 数据useGlobalCache: false,linebreaks: { automatic: true }},menuSettings: {zoom: "Click"},MatchWebFonts: {matchFor: {SVG: true},fontCheckDelay: 500,fontCheckTimeout: 15 * 1000},messageStyle: "none"
});

得到的结果:

<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="5.21ex" height="2.301ex" viewBox="0 -764.4 2243.1 990.7" role="img" focusable="false" style="vertical-align: -0.525ex;"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><path stroke-width="1" d="M463 111l13 -11c-75 -91 -99 -110 -139 -110c-28 0 -40 12 -40 41c0 25 2 33 23 115c-75 -113 -133 -157 -203 -157c-56 0 -100 40 -100 116c0 155 153 336 286 336c43 0 72 -21 80 -58l11 48l3 3l61 7l7 -3c-2 -9 -3 -11 -6 -21c-47 -171 -89 -343 -89 -363 c0 -7 6 -13 14 -13c9 0 22 8 52 41zM365 361c0 35 -21 58 -56 58c-45 0 -89 -31 -131 -92c-42 -63 -77 -152 -77 -215c0 -55 24 -74 60 -74c50 0 97 55 127 98c47 68 77 154 77 225Z"></path><g transform="translate(779,0)"><path stroke-width="1" d="M637 120h-326l-120 -276h-54l120 276h-209v66h238l59 134h-297v66h326l120 276h54l-121 -276h210v-66h-238l-59 -134h297v-66Z"></path></g><g transform="translate(1742,0)"><path stroke-width="1" d="M476 330c0 -172 -63 -344 -226 -344c-171 0 -226 186 -226 350c0 177 69 340 230 340c131 0 222 -141 222 -346zM380 325c0 208 -44 325 -132 325c-83 0 -128 -118 -128 -321s44 -317 130 -317c85 0 130 115 130 313Z"></path></g></g>
</svg>

进一步修改其它配置参数,可以更美观:

SVG: {scale: 95,        // 公式大小设置为 95% 在与文本混排时不会显得太突兀font: "STIX-Web"  // Times 风格的 STIX 字体字符丰富,风格上比较符合国内的排版标准
}

参考:https://codepen.io/mowchann/pen/xxPEqgO

最终效果


【笔记】微信公众号插入数学公式(矢量图格式)的若干尝试相关推荐

  1. 微信公众号网页授权时序图

    微信公众号网页授权时序图 公众号网页授权时序图

  2. python微信公众号翻译功能怎么用_Watson使用指南(七)在微信公众号中实现识图作诗功能...

    本文章主要是写一下这个项目开发的过程及之间遇到的问题,作为记录,也希望以此为契机认识志同道合的朋友,一起学习交流. 目录: 概述 环境准备及相关账号申请 部署Python Flask应用到Bluemi ...

  3. 教你如何一键提取微信公众号文章的封面图

    有很多小伙伴问小编,看到一个别人发的公众号文章封面图特别好看,可是在文章里面却没有显示,这要怎么才能把这张图下载下来呢?今天就教你们,如何去抓取公众号文章封面图自己使用,详细步骤请看本文. 第一步 复 ...

  4. python获取藏头诗内容_Watson使用指南(六)在微信公众号中实现识图作诗功能

    本文章主要是写一下这个项目开发的过程及之间遇到的问题,作为记录,也希望以此为契机认识志同道合的朋友,一起学习交流. 目录: 概述 环境准备及相关账号申请 部署Python Flask应用到Bluemi ...

  5. Watson使用指南(六)在微信公众号中实现识图作诗功能

    本文章主要是写一下这个项目开发的过程及之间遇到的问题,作为记录,也希望以此为契机认识志同道合的朋友,一起学习交流. 目录: 概述 环境准备及相关账号申请 部署Python Flask应用到Bluemi ...

  6. [笔记]微信公众号搭建

    申请微信公众号 (订阅号) 主要就是使用一个没注册过微信公众号的邮箱,个人只能创建订阅号,企业创建服务号并且需要企业认证(企业等证明) 服务器配置 配置 内网映射 natapp/花生壳 natapp: ...

  7. 微信公众号插入地图及地图搜索资源的前端处理(坐标系转码,自动定位等业务实现)

    var map;// 地图对象 var ac;// ac自动完成对象 var isReturnNum = false;// 初始未返回微信的经纬度信息 var parkMarkers = [];// ...

  8. 微信公众号插入百度地址导航功能

    一键导航代码示例: http://apis.map.qq.com/tools/poimarker?type=0&marker=coord:嗨,我是坐标;title:嗨,我是导航标题;addr: ...

  9. 微信公众号的缩略图/封面图下载方法详细介绍

    1.使用谷歌浏览器打开公众号链接. 2.在页面中点击右键, 查看网页源代码.ctrl+f 搜索"var msg". 3.其中,var msg_cdn_url 对应的链接就是要找的图 ...

最新文章

  1. linux下qt实现计算器,QT实现计算器
  2. LeetCode:Longest Consecutive Sequence
  3. How is OData selected implemented
  4. C++ 数据结构 线性链表
  5. 利用计算机可产生随机数,一种利用计算机生成随机数的方法
  6. DML和DDL含义和区别-一定要搞明白
  7. [C++] - lambda capture的成员函数 异步调用
  8. Python批量导入Excel文件中的不重复数据到SQLite数据库
  9. sql语言快速入门_C语言快速入门——名称可见性
  10. Python学习记录之----网络通信(二)
  11. ASP.NET MVC和jQuery系列一:入门篇
  12. 恒生电子笔试题数据库及算法整理记录
  13. SPSS——描述性统计分析——描述
  14. 【牛刀小试4】斐波那契数
  15. 世界上云平台有很多,但叫机智云的只有一个。
  16. Android高级控件之ListView的优化以及下拉刷新页面
  17. 什么是多尺度密集网络 - MSDNet ?
  18. 针对安卓app的爬虫路程
  19. Word中插入PDF
  20. IDEA配置连接数据库时报错Server returns invalid timezone. Go to ‘Advanced‘ tab and set ‘serverTimezone‘ propert

热门文章

  1. 咱们看见是水,饿鬼看见是火,天人看见是琉璃
  2. 基于51单片机实现红外循迹
  3. java斐波那切数列_如何用java语言输出斐波那契数列
  4. 解读ACL 2020的一篇paper (Recurrent Chunking Mechanisms for Long-text machine reading comprehension)的源码
  5. 在淘宝我学到了什么?
  6. 【网络安全】浅谈IP溯源的原理及方法
  7. 用html5和css制作信息登记表
  8. apt dpkg 常用命令汇总
  9. c语言创造的文件保存路径_C语言 如何创建文件到指定文件夹
  10. 普通人如何改变自己的命运?