新聞中心
寫數(shù)學(xué)公式,功能最強(qiáng)大的當(dāng)然是LaTex了。不過,強(qiáng)大不代表易用,駕馭LaTex絕不是一件容易的事兒。這也不難理解:畢竟數(shù)學(xué)公式不是孤立存在的,必然要作為文檔、網(wǎng)頁或者程序輸出的元素,如何無縫地讓LaTex關(guān)聯(lián)到文檔、網(wǎng)頁或程序,的確是個(gè)棘手的難題。

創(chuàng)新互聯(lián)建站是一家集網(wǎng)站建設(shè),肥東企業(yè)網(wǎng)站建設(shè),肥東品牌網(wǎng)站建設(shè),網(wǎng)站定制,肥東網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,肥東網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
既然直接使用LaTex有難度,那就退而求其次:借助于工具將數(shù)學(xué)公式轉(zhuǎn)為圖片,然后就可以方便地應(yīng)用到文檔、網(wǎng)頁或者程序中了。這樣的工具,除了在線式的,基本上都是重量級(jí)的,安裝和使用極不方便。我曾經(jīng)花了11個(gè)C幣從CSDN買過一個(gè)數(shù)學(xué)公式轉(zhuǎn)圖片的工具,下載之后發(fā)現(xiàn),竟然只是封裝了一個(gè)http請求,圖片仍然是在線生成的!一氣之下,自己寫了個(gè)離線的,只是功能比較簡單,不能方便地設(shè)置輸出圖像的大小和顏色。
最近工作中又用到了LaTex,幾經(jīng)嘗試,終于在matplotlib源碼中發(fā)現(xiàn)了一個(gè)處理LaTex數(shù)學(xué)公式的好東西。稍加改造,增加了字體、字號(hào)、顏色和分辨率的設(shè)置,最終完美解決了LaTex數(shù)學(xué)公式轉(zhuǎn)圖片的問題。
1. 核心代碼
先從最簡單的開始吧。matplotlib有個(gè)mathtext子模塊,提供了math_to_image函數(shù)可以直接將LaTex數(shù)學(xué)公式生成圖片。下面的代碼,僅僅兩行,就將質(zhì)能方程轉(zhuǎn)成了圖片。請注意,LaTex數(shù)學(xué)公式一定要包含在兩個(gè)$符號(hào)之間。
- >>> from matplotlib import mathtext
- >>> mathtext.math_to_image(r'$E=mc^2$', r'd:\demo_1.png')
生成的圖片寬度55個(gè)像素,高度15個(gè)像素,分辨率為100dpi。這么迷你,看上去可憐巴巴的。
雖然指定了png格式,也確實(shí)存在透明通道,其背景卻是不透明的。除了png格式外,math_to_image函數(shù)還支持eps, pdf, pgf, png, ps, raw, rgba, svg, svgz等格式,但不支持jpg格式。
2. 設(shè)置字體、字號(hào)、分辨率
要設(shè)置字體字號(hào),就得先導(dǎo)入matplotlib的font_manager字體管理模塊。該模塊的FontProperties類可以實(shí)例化一個(gè)字體對象傳給math_to_image函數(shù),用來設(shè)置family(字體)、size(字號(hào))和weight(筆畫輕重)等。
math_to_image函數(shù)的dpi參數(shù)用于設(shè)置分辨率(每英寸像素?cái)?shù))。如果應(yīng)用于網(wǎng)頁的話,建議分辨率設(shè)置為72dpi就可以了,如果用于印刷,請將dpi設(shè)置為300。
- >>> import matplotlib.font_manager as mfm
- >>> 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)
輸出結(jié)果如下。這次生成的圖片終于不那么可憐了,寬度250個(gè)像素,高度59個(gè)像素。
如果不知道有哪些字體可用怎么辦?不要擔(dān)心,下面這一行代碼就可以列出當(dāng)前系統(tǒng)中全部的可用字體。在我的電腦上運(yùn)行之后,找到了幾百種可用的字體(重名的字體表示該字體有多個(gè)字體文件)。
- >>> [item.name for item in mfm.fontManager.ttflist]
3. 設(shè)置顏色
要想對圖片文件做顏色處理,最好的方式是先將math_to_image的輸出暫存到類文件對象中,借助于PIL和NumPy完成顏色設(shè)置后,再保存為文件。為此,要先導(dǎo)入io模塊、pillow模塊和numpy模塊。
在開始寫代碼前,先約定使用浮點(diǎn)型的三元組表示顏色,比如,(0.17, 0.63, 0.17)表示亮度稍暗的綠色。如果喜歡使用其他方式表示顏色,請自行轉(zhuǎn)換。下面的例子換了一個(gè)復(fù)雜的數(shù)學(xué)公式(虛構(gòu)的,并無實(shí)際意義)來演示如何設(shè)置顏色。
- >>> from io import BytesIO
- >>> from PIL import Image
- >>> import numpy as np
- >>> text = r'$s(t) = \mathcal{A}\mathrm{sin}(2 \omega \sum_{i=0}^\infty t_i)$'
- >>> color = (0.17, 0.63, 0.17) # 要使用的顏色
- >>> bfo = BytesIO() # 創(chuàng)建二進(jìn)制的類文件對象
- >>> prop = mfm.FontProperties(family='Palatino Linotype', size=256, weight='normal')
- >>> mathtext.math_to_image(text, bfo, prop=prop, dpi=72)
- 209.0
- >>> im = Image.open(bfo) # 打開二進(jìn)制的類文件對象,返回一個(gè)PIL圖像對象
- >>> r, g, b, a = im.split() # 分離出RGBA四個(gè)通道
- >>> 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通道設(shè)置為目標(biāo)顏色
- >>> im = np.dstack((r,g,b,a)).astype(np.uint8) # RGBA四個(gè)通道合并為三維的numpy數(shù)組
- >>> im = Image.fromarray(im) # numpy數(shù)組轉(zhuǎn)PIL圖像對象
- >>> im.save(r'd:\demo_3.png') # PIL圖像對象保存為文件
來看看最終的輸出結(jié)果是什么樣的呢?最終生成了2451x653的一張大圖,公式內(nèi)容、字體、字號(hào)、顏色等,正如期望的那樣。大功告成!
4. 封裝成函數(shù)
為了方便使用,將上面的代碼封裝成一個(gè)函數(shù),完整代碼如下。
- # -*- coding: utf-8 -*-
- import os
- from io import BytesIO
- from PIL import Image
- import numpy as np
- import matplotlib.font_manager as mfm
- from matplotlib import mathtext
- def latex2img(text, size=32, color=(0.1,0.1,0.1), out=None, **kwds):
- """LaTex數(shù)學(xué)公式轉(zhuǎn)圖片
- text - 文本字符串,其中數(shù)學(xué)公式須包含在兩個(gè)$符號(hào)之間
- size - 字號(hào),整型,默認(rèn)32
- color - 顏色,浮點(diǎn)型三元組,值域范圍[0,1],默認(rèn)深黑色
- out - 文件名,僅支持后綴名為.png的文件名。若為None,則返回PIL圖像對象
- kwds - 關(guān)鍵字參數(shù)
- dpi - 輸出分辨率(每英寸像素?cái)?shù)),默認(rèn)72
- family - 系統(tǒng)支持的字體,None表示當(dāng)前默認(rèn)的字體
- weight - 筆畫輕重,可選項(xiàng)包括:normal(默認(rèn))、light和bold
- """
- assert out is None or os.path.splitext(out)[1].lower() == '.png', '僅支持后綴名為.png的文件名'
- for key in kwds:
- if key not in ['dpi', 'family', 'weight']:
- raise KeyError('不支持的關(guān)鍵字參數(shù):%s'%key)
- dpi = kwds.get('dpi', 72)
- family = kwds.get('family', None)
- weight = kwds.get('weight', 'normal')
- bfo = BytesIO() # 創(chuàng)建二進(jìn)制的類文件對象
- prop = 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/3
- r, 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)
- if out is None:
- return im
- else:
- im.save(out)
- print('生成的圖片已保存為%s'%out)
- if __name__ == '__main__':
- text = r'$\sum_{i=0}^\infty x_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(text, size=48, color=(0.9,0.1,0.1))
- im.show()
分享文章:數(shù)學(xué)公式轉(zhuǎn)圖片:純Python實(shí)現(xiàn),可設(shè)置字體、字號(hào)、顏色和分辨率
URL標(biāo)題:http://fisionsoft.com.cn/article/cceicgg.html


咨詢
建站咨詢
