当前位置: 首页 > 科技观察

数学公式转图片:纯Python实现,可以设置字体、字号、颜色和分辨率

时间:2023-03-21 00:27:46 科技观察

来写数学公式,当然最强大的还是LaTex。但是,功能强大并不意味着好用,驾驭LaTex也绝非易事。这不难理解:数学公式毕竟不是孤立存在的,必须作为文档、网页或程序输出的元素。如何将LaTex与文档、网页或程序无缝关联,确实是一个棘手的问题。既然直接使用LaTex比较困难,退而求其次的办法就是使用工具将数学公式转换成图片,然后就可以很容易地应用到文档、网页或程序中。这样的工具,除了网上的,基本都是重量级的,安装使用都极其不方便。曾经花11个C币从CSDN上买了一个数学公式转图片的工具。下载后发现它只封装了一个http请求,图片还是在线生成的!一气之下,自己写了一个离线的,只是功能比较简单,不方便设置输出图片的大小和颜色。最近,我在工作中使用了LaTex。经过几次尝试,终于在matplotlib源码中找到了一个处理LaTex数学公式的好东西。稍作修改,增加了字体、字号、颜色、分辨率的设置,最终完美解决了LaTex数学公式转图片的问题。1、先从最简单的核心代码说起。matplotlib有一个mathtext子模块,它提供math_to_image函数来直接从LaTex数学公式生成图像。下面的代码,仅仅两行,就把质能方程转换成了图片。请注意,LaTex数学公式必须包含在两个$符号之间。>>>frommatplotlibimportmathtext>>>mathtext.math_to_image(r'$E=mc^2$',r'd:\demo_1.png')生成一个图像,宽度为55像素,高度为15像素,a分辨率为100dpi。它很小,看起来很可怜??。虽然指定了png格式,但确实有透明通道,只是它的背景不是透明的。除了png格式,math_to_image函数还支持eps、pdf、pgf、png、ps、raw、rgba、svg、svgz等格式,但不支持jpg格式。2、设置字体、字号、分辨率要设置字号,首先要导入matplotlib的font_manager字体管理模块。该模块的FontProperties类可以实例化一个字体对象,并传递给math_to_image函数来设置family(字体)、size(字体大小)和weight(笔划粗细)等。math_to_image函数的dpi参数用于设置分辨率(每英寸像素数)。如果应用于网页,建议将分辨率设置为72dpi。如果用于打印,请设置dpi为300。>>>importmatplotlib.font_managerasmfm>>>prop=mfm.FontProperties(family='sans-serif',size=64,weight='normal')>>>mathtext.math_to_image(r'$E=mc^2$',r'd:\demo_2.png',prop=prop,dpi=72)输出结果如下。这次生成的图片终于没有那么可怜了,宽250像素,高59像素。如果您不知道可用的字体怎么办?不用担心,下面这行代码会列出当前系统中所有可用的字体。在我的电脑上运行后,我发现了数百种可用的字体(同名字体意味着该字体有多个字体文件)。>>>[item.nameforiteminmfm.fontManager.ttflist]3。设置颜色如果想对图像文件做颜色处理,最好的办法是将math_to_image的输出暂时存放在一个类似文件的对象中,借助PIL和NumPy完成颜色设置后,保存为一份文件。为此,首先导入io模块、pillow模块和numpy模块。在开始写代码之前,同意使用浮点三元组来表示颜色,例如,(0.17,0.63,0.17)表示稍微深一点的绿色。如果您喜欢用其他方式表示颜色,请自行转换。下面的例子使用一个复杂的数学公式(虚构的,无意义的)来演示如何设置颜色。>>>fromioimportBytesIO>>>fromPILimportImage>>>importnumpyasnp>>>text=r'$s(t)=\mathcal{A}\mathrm{sin}(2\omega\sum_{i=0}^\inftyt_i)$'>>>color=(0.17,0.63,0.17)#要使用的颜色>>>bfo=BytesIO()#创建一个类似二进制文件的对象>>>prop=mfm.FontProperties(family='PalatinoLinotype',size=256,weight='normal')>>>mathtext.math_to_image(text,bfo,prop=prop,dpi=72)209.0>>>im=Image.open(bfo)#打开一个类似二进制文件的对象并返回一个PIL图像对象>>>r,g,b,a=im.split()#分离RGBA四个通道>>>r,g,b=255-np.array(r),255-np.array(g),255-np.array(b)#RGB通道反白>>>a=r/3+g/3+b/3#生成新的alpha通道>>>r,g,b=r*color[0],g*color[1],b*color[2]#RGB通道设置为目标颜色>>>im=np.dstack((r,g,b,a)).astype(np.uint8)#RGBA的四个通道合并成一个三维的numpy数组>>>im=Image.fromarray(im)#numpy数组转PIL图像对象>>>im.save(r'd:\demo_3.png')#PILimageobject存成文件看看最后输出的样子?最后生成一张2451x653的大图,公式内容、字体、字号、颜色等都符合预期。你完成了!4.封装成一个函数为了方便使用,将上面的代码封装成一个函数。完整代码如下。#-*-coding:utf-8-*-importosfromioimportBytesIOfromPILimportImageimportnumpyasnpimportmatplotlib.font_managerasmfmfrommatplotlibimportmathtextdeflatex2img(text,size=32,color=(0.1,0.1,0.1),out=None,**kwds):"""LaTex数学公式转图片文字-文本字符串,数学公式必须包含在两个$符号之间支持后缀为.png的文件名。如果为None,则返回PIL图像对象kwds-关键字参数dpi-输出分辨率(每英寸像素数),默认72family-系统支持的字体,None表示当前默认字体粗细-笔划粗细,选项包括:normal(默认),lightandbold"""assertoutisNoneoros.path.splitext(out)[1].lower()=='.png','只支持后缀为.png的文件名'forkeyinkwds:ifkeynotin['dpi','family','weight']:raiseKeyError('Unsupportedkeywordargument:%s'%key)dpi=kwds.get('dpi',72)family=kwds.get('family',None)weight=kwds.get('weight','normal')bfo=BytesIO()#Createabinaryfile-likeobjectprop=mfm.FontProperties(family=family,size=size,weight=weight)mathtext.math_to_image(text,bfo,prop=prop,dpi=dpi)im=Image.open(bfo)r,g,b,a=im.split()r,g,b=255-np.array(r),255-np.array(g),255-np.array(b)a=r/3+g/3+b/3r,g,b=r*color[0],g*color[1],b*color[2]im=np.dstack((r,g,b,a)).astype(np.uint8)im=Image.fromarray(im)ifoutisNone:returnimelse:im.save(out)print('生成的图片已保存为%s'%out)if__name__=='__main__':text=r'$\sum_{i=0}^\inftyx_i$'latex2img(text,size=48,color=(0.1,0.8,0.8),out=r'd:\demo.png')text=r'$\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$'im=latex2img(文本,size=48,color=(0.9,0.1,0.1))im.show()