7
$\begingroup$

There have been a couple of questions about incorporating labels and equations that were typeset in $\LaTeX$ into a Mathematica notebook. Ideally, this requires running pdflatex (or latex) from within Mathematica and then importing the generated PDF document.

Unfortunately, importing of PDF is known to be buggy, as discussed in these questions (among others, probably):

The last two also mention ghostscript as the way to solve some of the issues, in particular using the pdfwrite device to re-generate a new PDF from existing ones.

This could be used in a $\LaTeX$ workflow like this (I am assuming Mac OS X here):

Export["words.tex", "\n\\nonstopmode
  \\documentclass[12pt]{article}
  \\begin{document}\n
  here\\qquad we\\qquad go
  \\end{document}\n
  ", "Text"];

Run["pdflatex words"]

(* ==> 0 *)

Import["words.pdf"]

Import::general: Expected cross reference table >>

Import::general: Expected cross reference table >>

Import::general: Could not find document trailer >>

General::stop:

As was to be expected, here we get error messages similar to what the second question referenced above saw. So now try the ghostscript workaround. Since this question aims at using $\LaTeX$, by assumption we have a working $\TeX$ installation which nowadays includes ghostscript, so the following will be able to execute:

Run["gs -sDEVICE=pdfwrite -dNOCACHE \
-sOutputFile=words-nofont.pdf -q -dBatch -dNOPAUSE words.pdf -c quit"]

(* ==> 0 *)

Import["words-nofont.pdf"]

wrong spacing

But the imported PDF has incorrect spacings between the words. It should (as you can tell from the \\qquad in the source) look more like

$\text{Here}\qquad \text{we}\qquad \text{go}$

This is just a somewhat artificial example illustrating the general problem of incorrect lengths and fonts upon import of a PDF.

So the question is, how can one fix this, either by using $\TeX$ and its companion utilities differently, or by relying only on Mathematica's capabilities? If this can be done, then it will be possible to automate the generation of $\LaTeX$ labels etc. from within Mathematica.

I'll post my answer based on ghostscript below, hoping that eventually someone will come up with a fix for PDF import that doesn't require external software.

$\endgroup$
  • $\begingroup$ I can't believe that even after writing MaTeX, I never noticed this thread before! $\endgroup$ – Szabolcs Mar 9 '17 at 21:42
5
$\begingroup$

Only expected to work for Mac OS X and linux (Windows has ghostscript, but calls have different syntax):

The reason why the errors happen in the first place is that pdflatex generates one of the more recent versions of the PDF specification (1.5), whereas Mathematica expects an older version upon import (probably 1.3). Specifying the lower version by adding \pdfminorversion=3 as the first line of the source gets rid of the error messages but doesn't fix the spacings.

A possible work-around is to replace the ghostscript call in the question by a two-step process that first converts the $\LaTeX$ generated to Postscript and then passes it to the ps2pdf command which also comes with the $\TeX$ distribution. This seems to remove the features of the modern PDF that trip up Mathematica's import handling:

Run["gs -sDEVICE=pswrite -dNOCACHE -sOutputFile=- -q \
-dbatch -dNOPAUSE -dQUIET words.pdf -c quit | ps2pdf - wordNew.pdf"]

(* ==> 0 *)

Import["wordNew.pdf"]

Correct spacing

To tie this together into a Mathematica function that typesets a given source string, I'll change the standard preamble of the test file above into something nicer:

latex[str_] := Module[
  {p,
   TeXsource = "\n\\nonstopmode
    \\documentclass[border=1pt]{standalone}
    \\usepackage[usenames]{color} %used for font color
    \\usepackage{amssymb} %maths
    \\usepackage{amsmath} %maths
    \\usepackage[utf8]{inputenc} %useful to type directly diacritic \
characters\n
    \\begin{document}\n
    ***BODY***
    \\end{document}\n
    ",
   sourceFile = 
    FileNameJoin[{$TemporaryDirectory, 
      "MathematicaOutput" <> 
       StringJoin[Map[ToString, DateList[]]]}]},
  Export[sourceFile <> ".tex", 
   StringReplace[TeXsource, "***BODY***" -> str], "Text"];
  SetDirectory["/tmp"];
  Run["pdflatex " <> sourceFile];
  Run["gs -sDEVICE=pswrite -dNOCACHE -sOutputFile=- -q -dbatch \
-dNOPAUSE -dQUIET " <> sourceFile <> ".pdf -c quit | ps2pdf - " <> 
    sourceFile <> "-nofont.pdf"];
  p = First@Import[sourceFile <> "-nofont.pdf"];
  DeleteFile[FileNames[sourceFile <> "*.*"]];
  ResetDirectory[];
  p
  ]

Now you can use this function as follows:

latex[
 "The answer is\\quad 
   $\\displaystyle\\frac{\\alpha}{2}\\int_0^\\infty f(x)\\,dx$"
]

example PDF

This allows transparent $\LaTeX$ typesetting from within Mathematica, and the standalone class makes sure that the output PDF is nicely cropped.

As I said, this is a workaround that will become unnecessary as soon as someone finds a Mathematica-only route to import PDF properly.

$\endgroup$
  • $\begingroup$ If you only want PostScript, not PDF, you could also call latex and then dvips. $\endgroup$ – Reinstate Monica - M. Schröder Dec 26 '12 at 12:49
  • $\begingroup$ Yes, that's true. But then to import it, I'd still need to convert to PDF again (using ps2dpf which I use above as well), so the total number of steps seems to be the same. $\endgroup$ – Jens Dec 26 '12 at 16:59
3
$\begingroup$

It would be helpful if Mathematica could at least say that the error lies in the pdf version mismatch. Thanks @Jens.

Here is another way to fix a pdf generated from pdflatex to be Importable in Mathematica, using Ghostscript (here on windows, but parameters should be similar on other operating systems):

This just converts the pdf to PDF v1.3.

gswin64c.exe -q -sDEVICE=pdfwrite -dNoOutputFonts -dCompatibilityLevel=1.3 -o output.pdf input.pdf

Full example ("true TeXForm", assuming the programs are in your PATH):

$s = StringTemplate["\\documentclass[crop]{standalone}
    \\usepackage{amsmath}
    \\usepackage{amssymb}

    \\begin{document}
    $\\displaystyle ``$
    \\end{document}
    "][
   (
      a x^2 + b x + c == 0
      ) // TeXForm // ToString
   ];
Export["temp.tex", $s, "String"];
RunProcess@{"pdflatex.exe", "temp.tex"};
RunProcess@{"gswin64c.exe", "-q", 
   "-sDEVICE=pdfwrite", "-dNoOutputFonts", "-dCompatibilityLevel=1.3", "-o", 
   "output.pdf", "temp.pdf"};
Import@"output.pdf"//First

Output: $$a x^2+b x+c=0$$

$\endgroup$
  • 1
    $\begingroup$ You need to use the -dNoOutputFonts option, available in Ghostscript 9.15 or later, otherwise Mathematica will mess up many glyphs. This shouldn't be a disadvantage because Mathematica does outline the fonts on import anyway. This is what I use in MaTeX. BTW I've never seen this thread before. $\endgroup$ – Szabolcs Mar 9 '17 at 21:40
  • $\begingroup$ @Szabolcs Ah, thanks for that. I was already beginning to wonder how I could fix Import::general: Unimplemented operator ' encountered which I got for running it on IdentityMatrix@3. I need to check out MaTeX. $\endgroup$ – masterxilo Mar 9 '17 at 21:44
  • $\begingroup$ MaTeX does basically the same thing that you are showing here. Except it has all (well, most of ...) the issues ironed out. There's an incredible amount of stuff that can go wrong unexpectedly. E.g. did you know that if you just switch out that StringTemplate to FileTemplate then things will blow up on Windows? Who would think of that? (FileTemplate has bad CR/LF handling) $\endgroup$ – Szabolcs Mar 9 '17 at 21:53
  • 1
    $\begingroup$ Thanks for making it simpler, and also covering the Windows side which I had no way of testing (+1). @Szabolcs Great work on MaTeX - especially since there's so much insidious stuff going wrong with PDF. $\endgroup$ – Jens Mar 9 '17 at 23:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.