据别人介绍,在绘制平面分子式,乃至化学反应式、机理图时,大家使用的基本都是ChemDraw。当然ChemDraw是一款强大的软件,无论是平面的还是立体的分子结构式都能毫不费力地绘制出来。当然这份强大是要钱的,对于平面的分子式或反应式,不要钱而且还可行的方案大致也就LaTeX语言中的Chemfig宏包。
Chemfig是法国学者开发的宏包,εTeX,pdfLaTeX等TeX编译器都能正常使用,并且相对来说开发是比较活跃的。
TeX Live 是 TUG (TeX User Group) 发布并维护的的 TeX 系统,可以称得上是TeX的官方系统。对于任何阶段的TeX用户,都可以使用TeX Live, 以保持在跨操作系统、跨用户的TeX文件一致性。
texlive Docker镜像及服务化改造texlive的安装B站有很多教程,目标是需要提供绘制chemfig化学方程式转换的服务,而texlive软件本身并不提供相关的api服务,需要对其进行服务化改造,因为考虑容器化部署,需要将texlive封装成docker镜像
话不多说,我们选择的基础镜像是 texlive:2020 ,使用Python对外提供服务,关于texlive相关的介绍可以参考博客:chemfig化学式转换为pdf
拉取镜像并运行 docker pull texlive:2020 docker run --name texlive -d texlive:2020 docker ps -a | grep live dda1561ae866 texlive:2020 "tail -f /dev/null" 8 seconds ago Up 2 texlive docker exec -it dda1561ae866 bash 安装python,制作texlive-python镜像 # texlive是基于Alpine Linux,目前主流 cat /etc/issue Welcome to Alpine Linux 3.12 # 修改apk镜像源 vi etc/apk/repositories替换文件内容为阿里源:
至此,我们的拥有python环境texlive镜像就已经制作好了
服务化改造 python脚本 from flask import Flask, abort, request, jsonify import os import subprocess import uuid import base64 app = Flask(__name__) @app.route('/texlive/translate/', methods=['POST']) def translate(): if not request.json or 'chemfig' not in request.json: abort(400) chem_fig = request.json['chemfig'] # 由于不好测算化学方程式图形的大小,这里支持配置纸张大小,我们这里默认a5paper if 'paper' in request.json: paper = request.json['paper'] else: paper = 'a5paper' tempFile = open("template.tex") lines = tempFile.readlines() lines[2] = lines[2].replace("a5paper", paper) lines[15] = chem_fig + "\n" uuidStr = str(uuid.uuid1()) new_file_name = uuidStr + '.tex' newFile = open(new_file_name, "a+") for line in lines: newFile.write(line) newFile.flush() newFile.close() try: # 这里使用subprocess比较稳定,os.system经常会出现莫名问题,至少这个pdflatex命令用os.system会报错 subprocess.run(["pdflatex", "-interaction=nonstopmode", new_file_name]) pdf_string = open(uuidStr + '.pdf', "rb").read() encoded = base64.b64encode(pdf_string) pdf_link = "data:application/pdf;base64,{}".format(encoded) pdf_link = pdf_link.replace("b'", "").replace("'", "") except: remove_file(uuidStr) else: remove_file(uuidStr) return jsonify({"image": pdf_link}) def remove_file(uuid_str): os.system('rm ' + uuid_str + '.tex') os.system('rm ' + uuid_str + '.log') os.system('rm ' + uuid_str + '.pdf') os.system('rm ' + uuid_str + '.aux') if __name__ == '__main__': app.run(host="0.0.0.0", port=8080, debug=False) Latex模板template.tex
\documentclass{minimal} \usepackage{xcolor, mol2chemfig} \usepackage[a5paper, margin=10px, total={6in, 8in}]{geometry} \usepackage[helvet]{sfmath} \setcrambond{2.5pt}{0.4pt}{1.0pt} \setbondoffset{1pt} \setdoublesep{2pt} \setatomsep{%(atomsep)spt} \renewcommand{\printatom}[1]{\fontsize{8pt}{10pt}\selectfont{\ensuremath{\mathsf{#1}}}} \setlength{\parindent}{0pt} \setlength{\fboxsep}{0pt} \begin{document} \chemfig{H_3C-[:30]N**6(-(=O)-(**5(-N(-CH_3)--N-))--N(-CH_3)-(=O)-)} \end{document}mol2chemfig.sty
requirements.txt Flask startup.sh python3 ./main.py DockerFile FROM texlive-python:2020 COPY main.py /home COPY mol2chemfig.sty /home COPY template.tex /home COPY requirements.txt /home COPY startup.sh /home WORKDIR /home EXPOSE 8080 RUN pip3 install -r requirements.txt && ls CMD ["bash", "startup.sh"] 服务镜像制作 构建 texlive-python-api # dockerfile构建 docker build -t texlive-python-api . # 打tag docker tag texlive-python-api xxx.xxx.com/xxx/texlive-python-api:2020 # 推送远程镜像仓库 docker push xxx.xxx.com/xxx/texlive-python-api:2020 跑一个试试 docker run -p 8080:8080 -d --name texlive-python-api texlive-python-api请求body
{"paper":"a6paper", "chemfig":"\\chemfig{CH_3-[:108,,1]N-[:54](-[:180,0.85,,,draw=none]\\mcfcringle{1.03})%\n-[:126]N-[:198]-[:270](-[:342]\\phantom{N})-[:210](=[:270]O)-[:150]N(%\n-[:210,,,2]H_3C)-[:90](=[:150]O)-[:30]N(-[:330])-[:90,,,1]CH_3}\n\n\\bigskip\n\n\\chemfig{CH_3-[:108,,1]N-[:54](-[:180,0.85,,,draw=none]\\mcfcringle{1.03})%\n-[:126]N-[:198]-[:270](-[:342]\\phantom{N})-[:210](=[:270]O)-[:150]N(%\n-[:210,,,2]H_3C)-[:90](=[:150]O)-[:30]N(-[:330])-[:90,,,1]CH_3}"}