手动搭建latex公式渲染服务器
2024-10-19 03:29:22
latex公式渲染有两种类型,一种是HTML形式展示公式,另一种是图片形式展示公式。如果是HTML形式展示公式,渲染是在前端完成的,一般会比较缓慢。知乎采取的方式是以图片形式展示公式。codecogs是一个latex公式渲染服务,它根据get请求返回一个svg图片。例如:
- codecogs,这个服务的缺点是比较慢。
- 知乎的公式渲染:
https://www.zhihu.com/equation?tex=\frac{1}{3}
本文介绍ubuntu下搭建类似codecogs的公式渲染服务。
一、安装latex
sudo apt-get install latex
sudo apt-get install latex-cjk-chinese
二、latex命令介绍
latex命令用于把tex文件转换成pdf文件或者dvi文件。dvi是一种设备无关的可打印文件格式。
输入dvi按两次tab可以找到dvisvgm,此命令将dvi文件转为svg。
三、编写服务程序
使用flask编写服务,通过命令行的方式调用latex获取svg。在返回时需要注意两点:
- 设置好content-type,否则客户端不知道你返回的是什么格式的图片
- 跨域访问并不需要设置,因为加载的是静态资源。跨域访问只需要在header中设置:
"Access-Control-Allow-Origin": "*"
使用latex命令时需要注意:
- documentclass必须是minimal,这样能够保证生成的文件尽量小。
dvisvgm --no-fonts --no-styles
,把dvi转为svg时取消导出字体和格式,而只是简单导出一张图片,否则客户端找不到这些字体和格式。- 使用
latex --interaction=nonstopmode
,能够保证即便报错也不会阻塞 - 要引入amsmath,否则许多宏会找不到
- 为了防止用户上传不合法公式造成超时的现象,需要使用subprocess模块,它是非阻塞的,父进程可以对子进程的运行时间进行监听。
TODO:
- 添加缓存功能:对某个公式的请求可能很多,每次不需要调用latex重新生产,直接使用缓存结果。这个优化可能没有必要,因为当查询分布特别分散时,这个优化费力不讨好。
- 添加统计功能:统计不同网站的请求次数,用来查看都有哪些人使用了本服务。其实调用别人服务是一件很危险的事情。调用别人的服务就是信任别人的服务,把别人的服务当做自己的一部分。当别人变得不可信任时,自己也就危险了。比如latex公式服务把返回的svg图片统一替换成某个不合法的图片。
import os
import signal
import subprocess
from flask import Flask, request, Response
app = Flask(__name__)
file_id = 0
latex_dir = os.path.join(os.path.expanduser("~"), "latex-server")
if not os.path.exists(latex_dir):
os.mkdir(latex_dir)
def run_command(s, log_file):
pro = subprocess.Popen(s, shell=True, preexec_fn=os.setsid)
try:
pro.wait(1) # 最多等待1秒钟
except Exception as ex:
print(ex)
# pro.terminate()
os.killpg(os.getpgid(pro.pid), signal.SIGTERM) # 杀死一个进程组
raise ex
def gets(formula):
global file_id
file_id += 1
now = file_id
tex_file, dvi_file, svg_file, log_file = [os.path.join(latex_dir, "{}.{}".format(
now, file_type)) for file_type in "tex dvi svg log".split()]
open(tex_file, mode='w').write(r"""
\documentclass{minimal}
\usepackage{amsmath}
\begin{document}
$$%s$$
\end{document}
""" % formula)
try:
run_command("latex --interaction=nonstopmode --output-directory {} {}".format(
latex_dir, tex_file), log_file)
run_command(
"dvisvgm --no-fonts --no-styles -c2,2 -o {} {}".format(svg_file, dvi_file), log_file)
svg = open(svg_file).read() # 如果不存在,那就直接抛出异常吧
return svg
except Exception as ex:
raise ex
finally:
# 清理文件
for i in "tex dvi log aux svg".split():
filename = os.path.join(latex_dir, "{}.{}".format(now, i))
if os.path.exists(filename):
os.remove(filename)
@app.route("/render")
def render():
formula = request.args['formula']
try:
resp = gets(formula)
return Response(response=resp, headers={
"Content-Type": "image/svg+xml"
})
except Exception as ex:
print(ex)
return Response(status=500)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9988, debug=True)
参考资料
https://cloud.tencent.com/developer/article/1015883
最新文章
- TypeScript 强类型 JavaScript – Rafy Web 框架选型
- VR技术的探索阶段
- Sort Colors [LeetCode]
- NoSQL之【MongoDB】学习(三):配置文件说明
- windows系统调用 遍历进程的虚拟地址
- hdu 4648
- C++专题 - 面向对象总结
- const使用摘要
- javascipt : filter
- DAOFactory复用代码
- 使用vue-cli脚手架搭建简单项目框架
- 【LGR-047】洛谷5月月赛
- python的selenium
- linux 文件压缩与解压缩
- Jmeter常用脚本开发之Java请求
- 并发编程之 CyclicBarrier 源码分析
- LSTM介绍
- linux下挂载磁盘操作
- 【深入理解JAVA虚拟机】第二部分.内存自动管理机制.3.垃圾收集器与内存分配策略
- java使用Redis(六个类型)
热门文章
- C#线程同步方法汇总
- DNS预解析dns-prefetch提升页面载入速度优化前端性能
- MFC剪贴板通信
- 如何导入另一个 Git库到现有的Git库并保留提交记录
- Creating OpenGL 4.3 window fails with GLFW3
- Downloading jQuery 3.2.1
- 来自Vexels的超棒免费商业相关图标资源 #精选设计素材图标
- Android中MVP模式与MVC模式比較(含演示样例)
- Android 之 PackageManager获取的应用程序信息与AndroidManifest文件中设置的信息不一致问题
- 微信小程序 - 3d轮播图组件(基础)