Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Render MathJax into PDF

I've spent days about how to render MathJax into PDF on client-side only (using several libraries like jsPDF, etc.) for the open source project Writing. I have tried many different options, without any success.

Here is a code showing the problem in my latest attempt, based on this answer.

  MathJax.Hub.Config({ tex2jax: {inlineMath: [["$","$"],["\\(","\\)"]]} });

document.getElementById("getPdf").addEventListener("click", getPdf);

function getPdf() {
  var svg = document.getElementById('main').innerHTML;
  if (svg)
    svg = svg.replace(/\r?\n|\r/g, '').trim();

  var canvas = document.createElement('canvas');
  var context = canvas.getContext('2d');

  context.clearRect(0, 0, canvas.width, canvas.height);
  canvg(canvas, svg);

  var imgData = canvas.toDataURL('image/png');

  var doc = new jsPDF('p', 'pt', 'a4');
  doc.addImage(imgData, 'PNG', 40, 40, 75, 75);
  doc.save('test.pdf');
}  
<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML-full"></script>
<script src="https://cdn.rawgit.com/canvg/canvg/master/canvg.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js"></script>

<p id="main">
When $a \ne 0$, there are two solutions to \(ax^2 + bx + c = 0\) and they are
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$
</p>

<button id="getPdf">Get PDF</button>

Question:

How to render HTML + MathJax content into PDF, on client-side only?

like image 938
Basj Avatar asked Nov 08 '22 00:11

Basj


1 Answers

My short answer would be: don't do this.

The long answer is you can make this work but the result will be inferior to providing a print stylesheet and letting users save the output as PDF. For starters, you will create a PDF with a single (potentially huge) PNG in it; that will be terrible for printing.

The main problem with your code is that canvg can only handle SVG content, not arbitrary web content, so you need to use another tool.

But generally there are limitations for injecting HTML content in canvas elements (for security reasons).

Finally, you will need to force MathJax's AssistiveMML extension to be off to avoid duplicate content.

Below is a snippet but it fails on SO for the security reasons mentioned above; you can try it on codepen though.

MathJax.Hub.Queue(function (){
  var canvas = document.getElementById("canvas");
  var main = document.getElementById("main");
  rasterizeHTML.drawHTML(main.outerHTML,canvas);

})
document.getElementById("getPdf").addEventListener("click", getPdf);

function getPdf() {
  var imgData = canvas.toDataURL('image/png');

  var doc = new jsPDF('p', 'pt', 'a4');
  doc.addImage(imgData, 'PNG', 40, 40, 400, 200);
  doc.save('test.pdf');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js"],
  "AssistiveMML": {
    disabled: true
  },
  SVG: {
    addMMLclasses: true,
    useGlobalCache: false
  },
  });
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_SVG-full"></script>
<script   src="https://cdnjs.cloudflare.com/ajax/libs/rasterizehtml/1.2.4/rasterizeHTML.allinone.js"></script>
<p id="main">
When \(a \ne 0\), there are two solutions to \(ax^2 + bx + c = 0\) and they are
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$
</p>
<h1>As canvas</h1>
    <canvas id="canvas" width="400" height="200"></canvas>

<button id="getPdf">Get PDF</button>
like image 182
Peter Krautzberger Avatar answered Nov 14 '22 21:11

Peter Krautzberger