vue3解析数学公式图片,页面展示并转换为Word格式

有这样一个需求:通过数学公式图片,识别书公式展示在页面上,并支持下载word,展示word版本的数学公式,可供复制使用。
之前是通过Pix2Text进行数学公式的识别,然后复制识别的内容,通过 LaTeX公式编辑器进行下载对应的数学公式的Word 文档。但是第一个网站Pix2Text不太稳定,经常性的不可用,所以想自己实现这2个功能。

一、图片OCR解析公式

首先参考第一个的Pix2Textgithub
后端进行部署了相关的服务,可以进行OCR解析图片,然后前端进行调用对应的接口
这块主要有一个是粘贴图片进行上传,并显示在页面上

1、首先需要监听全局paste事件

onMounted(() => {
  window.addEventListener('paste', handlePaste);
});
onUnmounted(() => {
  window.removeEventListener('paste', handlePaste);
});

2、然后再对应的监听方法中就可以获取到file文件

/** 全局页面监听粘贴内容 */
function handlePaste(event) {
  // console.log('全局页面监听粘贴内容000');
  const items = (event.clipboardData || window.clipboardData).items;
  let file = null;

  if (!items || items.length === 0) {
    console.log('当前浏览器不支持本地');
    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('粘贴内容非图片');
    return;
  }
  // 此时file就是我们的剪切板中的图片对象
  // console.log('file==', file);
  showImageToPage(file);
  uploadImage(file);
}

3、然后显示这个图片在页面上,div设置一个id

   <div id="preview" class="div_image">
            <span>将图片按Ctrl+V粘贴至此页面</span>
   </div>

4、把刚才获取到的file文件渲染在div上

// 上传的图片显示到页面右侧
function showImageToPage(file) {
  // 如果需要预览,可以执行下面代码
  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、然后调用后台的上传图片,OCR解析接口

// 上传图片到服务端进行OCR识别
function uploadImage(file) {
  let param = new FormData(); //创建form对象
  param.append('image', file); //为创建的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();
  });
}

二、页面展示数学公式

接口会返回一些解析出来的文本和LaTeX 数学公式
但是接口返回的LaTeX 公式,是一些$$符号的一些标识,具体符号参考见 LaTeX 公式篇 ,无法辨认出具体的公式,所以需要转化显示为可以识别的公式。

所以我们需要借助于 MathJax

mathjax是一个用于latex、mathml和ascimath表示法的开源javascript显示引擎,可在所有现代浏览器中工作,并内置了对诸如屏幕阅读器等辅助技术的支持。

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: [
                ['$', '$'],
                ['\\(', '\\)']
            ], // ⾏内公式选择符
            displayMath: [
                ['$$', '$$'],
                ['\\[', '\\]']
            ] // 段内公式选择符
        },
        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、在刚才上传图片接口,之后调用这个接口,传入接口返回的latex文本即可

 <!-- 展示数学公式 -->
<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公式文本渲染为数学公式显示在右侧虚线框中
function laTexToMath() {
  // MathJax3.0版本
  if (proxy.MathJax.isMathjaxConfig) {
    // 判断是否初始配置,若⽆则配置。
    proxy.MathJax.initMathjaxConfig();
  }
  proxy.MathJax.TypeSet();
}

效果如下图所示


WX20230612-173535@2x.png

三、转化下载Word格式的公式

上面的公式已经可以完整的展示在页面上,但是我们不是通过复制粘贴出来,所以需要把这个转换为Word版本的,可以进行复制粘贴的格式。
参考 LaTeX公式编辑器,通过这个里面的导出Word,有一个接口可以进行实现,接口地址为https://reverse.latexlive.com:5002/api/Common/MathMlToWordBlod,但是通过抓包发现这个接口的入参格式为 MathML格式,入下图所示

MathML格式

上面类似Html的格式,就是MathML格式,
所以我们需要将之前接口返回的laTex转MathML格式,然后再调研下载Word的接口,
1、laTex转MathML格式

// 需要先把laTex转MathML格式,然后通过MathML格式进行下载Word
function exportWord() {
  // console.log('laTex转MathML格式');
  if (!textWords.value) {
    proxy.$modal.msgError('请先粘贴图片识别');
    return;
  }
  // 重置
  window.MathJax.texReset();
  // laTex转MathML格式
  window.MathJax.tex2mmlPromise(textWords.value)
    .then(function (mml) {
      // 转换结果
      // console.log('转换结果mml=====', mml);
      downloadWordFile(mml);
    })
    .catch(function (err) {
      // 发生错误时
    })
    .then(function () {
      // 完成时
    });
}

2、下载Word文件

/ /下载Word文件-通过MathML格式进行下载Word
function downloadWordFile(mathml) {
  // console.log('下载word文件00');
  let param = {
    mathml: mathml
  };
  const config = {
    responseType: 'blob', //这个一定要设置,否则会出现文件下载后打不开的情况,
    '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], {
      //设置数据源
      type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' //设置文件格式
    });

    let objectUrl = URL.createObjectURL(blob); //创建下载的链接
    let a = document.createElement('a');
    a.href = objectUrl;

    let time = parseInt(new Date().getTime() / 1000) + '';
    a.download = `jwwh${time}`; //设置文件名
    //下面这个写法兼容火狐
    a.dispatchEvent(
      new MouseEvent('click', { bubbles: true, cancelable: true, view: window })
    );
    window.URL.revokeObjectURL(blob); //释放bolb对象
  });
}
Word格式展示

参考文档:
vue中使用MathJax 3.0简单步骤
mathjax
基于vue渲染Latex数学公式(simplemde-editor)
LatexToMathML
uniapp使用mathjax解析公式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343