Search code examples
javascriptsvgmathjax

Convert Latex/MathML to SVG or Image with mathjax or similar?


I'm building a library that only allows objects render's functionality to to return DOM elements of the representation of themselves, one of those is math, so <img>, <canvas> or <svg> will do it, I'll prefer svg.

Mathjax is known for being very good at this, but I need something more like:

Mathjax.Latex('\frac{2}{1}').toSVG(); //svg DOM node or string
Mathjax.Latex('\frac{2}{1}').toImage(); //Image, img node, or base64

I know it's possible with mathjax-node, but is it with mathjax client side? https://github.com/mathjax/MathJax-node


Solution

  • There is not built-in method for this. But you could obviously build something.

    Here's a quick and dirty example. Note that this example configures MathJax to not use its globalCache for SVG paths; this makes the SVG output easily re-usable. There are also some caveats for rendering detached DOM nodes; MathJax will have to guess the context (CSS, font metrics etc).

    window.MathJax = {
      jax: ["input/TeX", "output/SVG"],
      extensions: ["tex2jax.js", "MathMenu.js", "MathZoom.js"],
      showMathMenu: false,
      showProcessingMessages: false,
      messageStyle: "none",
      SVG: {
        useGlobalCache: false
      },
      TeX: {
        extensions: ["AMSmath.js", "AMSsymbols.js", "autoload-all.js"]
      },
      AuthorInit: function() {
        MathJax.Hub.Register.StartupHook("End", function() {
          var mj2img = function(texstring, callback) {
            var input = texstring;
            var wrapper = document.createElement("div");
            wrapper.innerHTML = input;
            var output = { svg: "", img: ""};
            MathJax.Hub.Queue(["Typeset", MathJax.Hub, wrapper]);
            MathJax.Hub.Queue(function() {
              var mjOut = wrapper.getElementsByTagName("svg")[0];
              mjOut.setAttribute("xmlns", "http://www.w3.org/2000/svg");
              // thanks, https://spin.atomicobject.com/2014/01/21/convert-svg-to-png/
              output.svg = mjOut.outerHTML;
              var image = new Image();
              image.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(output.svg)));
              image.onload = function() {
                var canvas = document.createElement('canvas');
                canvas.width = image.width;
                canvas.height = image.height;
                var context = canvas.getContext('2d');
                context.drawImage(image, 0, 0);
                output.img = canvas.toDataURL('image/png');
                callback(output);
              };
            });
          }
          mj2img("\\[f: X \\to Y\\]", function(output){
            document.getElementById("target").innerText = output.img + '\n' + output.svg;
          });
        });
      }
    };
    
    (function(d, script) {
      script = d.createElement('script');
      script.type = 'text/javascript';
      script.async = true;
      script.onload = function() {
        // remote script has loaded
      };
      script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js';
      d.getElementsByTagName('head')[0].appendChild(script);
    }(document));
    <div id="target"></div>