有這樣一個需求:通過數(shù)學(xué)公式圖片望抽,識別書公式展示在頁面上煤篙,并支持下載word舰蟆,展示word版本的數(shù)學(xué)公式趣惠,可供復(fù)制使用。
之前是通過Pix2Text進行數(shù)學(xué)公式的識別身害,然后復(fù)制識別的內(nèi)容味悄,通過 LaTeX公式編輯器進行下載對應(yīng)的數(shù)學(xué)公式的Word 文檔
。但是第一個網(wǎng)站Pix2Text
不太穩(wěn)定塌鸯,經(jīng)常性的不可用侍瑟,所以想自己實現(xiàn)這2個功能。
一丙猬、圖片OCR解析公式
首先參考第一個的Pix2Text
的github
后端進行部署了相關(guān)的服務(wù)涨颜,可以進行OCR解析圖片,然后前端進行調(diào)用對應(yīng)的接口
這塊主要有一個是粘貼圖片進行上傳茧球,并顯示在頁面上
1庭瑰、首先需要監(jiān)聽全局paste
事件
onMounted(() => {
window.addEventListener('paste', handlePaste);
});
onUnmounted(() => {
window.removeEventListener('paste', handlePaste);
});
2、然后再對應(yīng)的監(jiān)聽方法中就可以獲取到file文件
/** 全局頁面監(jiān)聽粘貼內(nèi)容 */
function handlePaste(event) {
// console.log('全局頁面監(jiān)聽粘貼內(nèi)容000');
const items = (event.clipboardData || window.clipboardData).items;
let file = null;
if (!items || items.length === 0) {
console.log('當(dāng)前瀏覽器不支持本地');
return;
}
// 搜索剪切板items
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
file = items[i].getAsFile();
break;
}
}
if (!file) {
console.log('粘貼內(nèi)容非圖片');
return;
}
// 此時file就是我們的剪切板中的圖片對象
// console.log('file==', file);
showImageToPage(file);
uploadImage(file);
}
3揪垄、然后顯示這個圖片在頁面上捡鱼,div設(shè)置一個id
<div id="preview" class="div_image">
<span>將圖片按Ctrl+V粘貼至此頁面</span>
</div>
4伟墙、把剛才獲取到的file文件渲染在div上
// 上傳的圖片顯示到頁面右側(cè)
function showImageToPage(file) {
// 如果需要預(yù)覽,可以執(zhí)行下面代碼
const reader = new FileReader();
reader.onload = event => {
preview.innerHTML = `<img src="${event.target.result}" style=' max-height: 200px;
max-width: 100%;
min-width: 200px;
object-fit: contain;'>`;
};
// 把粘貼的圖片顯示在頁面上
reader.readAsDataURL(file);
}
5、然后調(diào)用后臺的上傳圖片,OCR解析接口
// 上傳圖片到服務(wù)端進行OCR識別
function uploadImage(file) {
let param = new FormData(); //創(chuàng)建form對象
param.append('image', file); //為創(chuàng)建的form對象增加上傳的文件
// param.append('session_id', ''); //如果需要上傳其他字段,在這里增加
param.append('use_analyzer', 'true');
param.append('resized_shape', '600');
//修改請求頭
let config = { headers: { 'Content-Type': 'multipart/form-data' } };
// console.log('url ==', pix2textUrl);
proxy.$modal.loading('正在解析念脯,請稍候庐橙!');
// 上傳圖片
axios.post(pix2textUrl, param, config).then(res => {
// console.log('res====', res);
proxy.$modal.closeLoading();
if (!res.data || res.data.status_code != 200) {
proxy.$modal.msgError('未成功識別,請稍后再試');
return;
}
// console.log('res====', res);
let textList = res.data.results;
if (!textList || textList.length == 0) {
proxy.$modal.msgError('未成功識別,請稍后再試');
return;
}
let textStr = '';
textList.forEach(element => {
textStr += element.text;
if (element.type == 'text') {
textStr += '\n';
}
});
// console.log('textStr====', textStr);
textWords.value = textStr.replaceAll('$$', '');
mathText.value = textStr;
laTexToMath();
});
}
二、頁面展示數(shù)學(xué)公式
接口會返回一些解析出來的文本和LaTeX 數(shù)學(xué)公式
但是接口返回的LaTeX 公式,是一些$$符號的一些標識测萎,具體符號參考見 LaTeX 公式篇 ,無法辨認出具體的公式,所以需要轉(zhuǎn)化顯示為可以識別的公式。
所以我們需要借助于 MathJax
mathjax是一個用于latex耳鸯、mathml和ascimath表示法的開源javascript顯示引擎煌集,可在所有現(xiàn)代瀏覽器中工作纲缓,并內(nèi)置了對諸如屏幕閱讀器等輔助技術(shù)的支持。
1、首先需要在 index.html
中引入
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
2雷厂、在utils中新建MathJax.js
let isMathjaxConfig = false // ?于標識是否配置
const initMathjaxConfig = () => {
if (!window.MathJax) {
return
}
window.MathJax = {
tex: {
inlineMath: [
['$', '$'],
['\\(', '\\)']
], // ?內(nèi)公式選擇符
displayMath: [
['$$', '$$'],
['\\[', '\\]']
] // 段內(nèi)公式選擇符
},
chtml: {
scale: 1,//縮放比例
},
options: {
skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code',
'a'], // 避開某些標簽
ignoreHtmlClass: 'tex2jax_ignore',
processHtmlClass: 'tex2jax_process'
}
}
isMathjaxConfig = true // 配置完成,改為true
}
const TypeSet = async function (elementId) {
if (!window.MathJax) {
return
}
window.MathJax.startup.promise = window.MathJax.startup.promise
.then(() => {
return window.MathJax.typesetPromise()
})
.catch((err) => console.log('Typeset failed: ' + err.message))
return window.MathJax.startup.promise
}
export default {
isMathjaxConfig,
initMathjaxConfig,
TypeSet
}
3烟零、在main.js中全局引入
import MathJax from './utils/MathJax'
app.config.globalProperties.MathJax = MathJax
4凉逛、在剛才上傳圖片接口书斜,之后調(diào)用這個接口,傳入接口返回的latex文本即可
<!-- 展示數(shù)學(xué)公式 -->
<div class="input_box math_box" style="margin-left: 10px" id="math">
<p style="font-size: 14px; white-space: pre-line">{{ mathText }}</p>
</div>
// 將Latex公式文本渲染為數(shù)學(xué)公式顯示在右側(cè)虛線框中
function laTexToMath() {
// MathJax3.0版本
if (proxy.MathJax.isMathjaxConfig) {
// 判斷是否初始配置,若?則配置痪欲。
proxy.MathJax.initMathjaxConfig();
}
proxy.MathJax.TypeSet();
}
效果如下圖所示
三、轉(zhuǎn)化下載Word格式的公式
上面的公式已經(jīng)可以完整的展示在頁面上知举,但是我們不是通過復(fù)制粘貼出來遮糖,所以需要把這個轉(zhuǎn)換為Word版本的,可以進行復(fù)制粘貼的格式惹苗。
參考 LaTeX公式編輯器洽瞬,通過這個里面的導(dǎo)出Word晦闰,有一個接口可以進行實現(xiàn),接口地址為https://reverse.latexlive.com:5002/api/Common/MathMlToWordBlod
鄙皇,但是通過抓包發(fā)現(xiàn)這個接口的入?yún)⒏袷綖?MathML格式洲愤,入下圖所示
上面類似Html的格式,就是MathML格式,
所以我們需要將之前接口返回的laTex轉(zhuǎn)MathML格式严嗜,然后再調(diào)研下載Word的接口,
1、laTex轉(zhuǎn)MathML格式
// 需要先把laTex轉(zhuǎn)MathML格式癌椿,然后通過MathML格式進行下載Word
function exportWord() {
// console.log('laTex轉(zhuǎn)MathML格式');
if (!textWords.value) {
proxy.$modal.msgError('請先粘貼圖片識別');
return;
}
// 重置
window.MathJax.texReset();
// laTex轉(zhuǎn)MathML格式
window.MathJax.tex2mmlPromise(textWords.value)
.then(function (mml) {
// 轉(zhuǎn)換結(jié)果
// console.log('轉(zhuǎn)換結(jié)果mml=====', mml);
downloadWordFile(mml);
})
.catch(function (err) {
// 發(fā)生錯誤時
})
.then(function () {
// 完成時
});
}
2、下載Word文件
/ /下載Word文件-通過MathML格式進行下載Word
function downloadWordFile(mathml) {
// console.log('下載word文件00');
let param = {
mathml: mathml
};
const config = {
responseType: 'blob', //這個一定要設(shè)置菱阵,否則會出現(xiàn)文件下載后打不開的情況,
'Content-Type': 'application/json'
};
axios.post(mathMlToWordBlodUrl, param, config).then(res => {
// console.log('res====', res);
// console.log('下載word文件11');
let blob = new Blob([res.data], {
//設(shè)置數(shù)據(jù)源
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' //設(shè)置文件格式
});
let objectUrl = URL.createObjectURL(blob); //創(chuàng)建下載的鏈接
let a = document.createElement('a');
a.href = objectUrl;
let time = parseInt(new Date().getTime() / 1000) + '';
a.download = `jwwh${time}`; //設(shè)置文件名
//下面這個寫法兼容火狐
a.dispatchEvent(
new MouseEvent('click', { bubbles: true, cancelable: true, view: window })
);
window.URL.revokeObjectURL(blob); //釋放bolb對象
});
}
參考文檔:
vue中使用MathJax 3.0簡單步驟
mathjax
基于vue渲染Latex數(shù)學(xué)公式(simplemde-editor)
LatexToMathML
uniapp使用mathjax解析公式