前言

本文介绍编写MathpixOCR API的Python包装器和简单的Automator workflow, 模拟Mathpix Snip Tool的公式识别体验.

用LaTeX准备文献报告时一个比较头疼的问题是输入文献中包含复杂符号的长公式. Mathpix Snip Tool (MST)提供了方便的光学字符识别功能, 可以将包含公式的截图转化为LaTeX代码. 今年MST从完全免费的1.0版本升级到了2.0, 自此个人用户每月只能免费识别50次, 这对于苦逼PhD显然是不够用的.

好在作为MST底层的MathpixOCR服务, API每月可免费调用1000次, 所得结果和MST相同, 只是没有MST方便的截图和GUI功能. 归根结底, 我们想实现的无非是识别剪贴板中的公式图片, 转化图片到LaTeX代码并复制到剪贴板而已. 这可以通过将OCR与OS命令包装在一起来实现. 官方提供了简单的例子供我们学习OCR API的使用, 而OS API可以通过Python包和CLI命令调用. 这篇文章是学习包装器编写的记录.

最终脚本已上传到GitHub仓库, 欢迎下载使用.

API包装

获取API密钥

首先需要在Mathpix上注册用户并填写信用卡信息, 注册后获得app_keyapp_id作为API密钥.
脚本采用了两种从外部获取密钥的方式, 一种是环境变量, 另一种是从同路径下JSON读取.

从系统剪贴板获取图片

使用pillow包中的ImageGrab.grabclipboard获取剪贴版中的图片, 并产生Image对象.
注意, 此后剪贴板中的临时文件会被删除, 无法再直接通过路径获得.

1
2
3
4
>>> from PIL import ImageGrab
>>> im = ImageGrab.grabclipboard()
>>> os.path.isfile(im.filename)
False

因此需要先把图片保存下来才能在后续继续使用.

1
2
3
im = ImageGrab.grabclipboard()
fn = ".temp_eq.png"
im.save(fn, "PNG")

base64编码

OCR需要把图片编码转化为base64编码格式. 官方例子如下

1
2
3
4
import base64
def image_uri(fn):
image_data = open(fn, "rb").read()
return "data:image/jpg;base64," + base64.b64encode(image_data).decode()

b64encode使用Base64规则将一串类字节字符串进行编码, decode方法返回编码后的普通字符串.

1
2
3
4
5
>>> ec = base64.b64encode(b"abcdefg")
>>> ec
b'YWJjZGVmZw=='
>>> ec.decode()
'YWJjZGVmZw=='

前部附加的字符串是API额外要求的. 我还不太明白jpg的作用, 因为当fn是一个png图片时OCR一样可以正确解析.

调用API

通过requests包与OCR API进行通信. 通信数据要求为JSON, 它至少需要包含srcformat两个键. src值就是base64编码后的图片字符串, format值为一个列表, 成员为所想要转换的格式, 支持的转化格式包括下面几种.

format 转化格式
text 普通文本
wolfram Mathematica
latex_simplified 简化的latex代码, 括号不包含left或right
latex_styled left/right控制的latex代码

利用json包处理JSON文件

1
2
3
4
5
6
7
8
data = json.dump({"src": img_base64, "format": ["latex_simplified",]})
headers = {
'Content-type': 'application/json',
'app_key': your_app_key,
'app_id': your_app_id,
}
r = requests.post('https://api.mathpix.com/v3/latex',
data=data, headers=headers)

通信得到的r.text是一个JSON字符串. 如果OCR识别成功, 则它包含latex_simplified键, 对应值为识别号的简化LaTeX代码.
如果识别失败, 则包含error键, 给出具体错误信息. 更复杂的API调用参考官方文档.

拷贝转化好的LaTeX到系统剪贴板

参考了这个GIST, 使用macOS上的pbcopy将字符串拷贝到系统剪贴板.
另一种办法是直接打印到标准输出, 然后用Automator服务中的功能拷贝到剪贴板.

附加功能

比如每月API调用统计以及历史记录, 都保存在JSON文件中. 实现说起来比较琐碎, 就不赘述了.

Automator服务

把写好的包装器放到~/bin下, 编写简单的工作流Mathpix Snip OCR API

然后在系统设置-键盘-快捷键设置服务的快捷键

如此一来, cmd+shift+4将公式截屏到剪贴板后cmd+shift+M, 等待片刻即可从剪贴板黏贴转换好的公式. 大功告成!

参考资料

使用pillow包来获取剪贴板图片: Mathpix收费了?快使用API吧,一个月免费识别1000次!

Comments