# TeX rendering in a Java application

I want to render math formulas in my Java GUI application. I am looking for a library made for computer use, not web use, which can render TeX. I have already tried jLatexMath, but it's very slow when I use it in my application.

If there are any other/better, could you point me in the right direction?

(I originally asked this question on StackOverflow)

-
I can think of three libraries that might somehow help or inspire you: JEuclid, SnuggleTeX and JLaTeXMath. –  Paulo Cereda Jan 19 '12 at 16:42
I am using jLatexMath in one of my own projects, and the first time I got it to display equations I also thought it was very slow, until I realized this was only true for the first invocation of jLatexMath. For every start of your application, the first rendering will be slow but subsequent renderings are fast. –  propaganda Jan 20 '12 at 3:33

Friendly note: most of the conversion process involves input parsing, evaluation, font loading, rendering and output, so I wouldn't expect a nearly real-time conversion.

That said, let's go to business. :)

Warning: boring non-TeX technical Java stuff ahead. :)

I had a quick look at both SnuggleTeX and JEuclid in order to come up with this answer. Sorry, I didn't have time to come up with a better example.

The first one, SnuggleTeX, is described as "a free and open-source Java library for converting fragments of LaTeX to XML (usually XHTML + MathML)." The second one, JEuclid, is described as "a complete MathML rendering solution". What I actually did was to redirect one's output to the other's input.

First, with SnuggleTeX, you can obtain the needed code from the minimal example in its own homepage:

/* Create vanilla SnuggleEngine and new SnuggleSession */
SnuggleEngine engine = new SnuggleEngine();
SnuggleSession session = engine.createSession();

/* Parse some very basic Math Mode input */
SnuggleInput input = new SnuggleInput("$$x+2=3$$");
session.parseInput(input);

/* Convert the results to an XML String, which in this case will
* be a single MathML $...$ element. */
String xmlString = session.buildXMLString();


Now you have the MathML representation of your LaTeX input. Let's check JEuclid, from its API, there's the Converter class with the following method:

BufferedImage render(Node node, LayoutContext context)


Then you can use net.sourceforge.jeuclid.MathMLParserSupport to parse your XML string to org.w3c.dom.Document. Calling the render method with the correct parameters will give you a BufferedImage representing your input.

My attempt:

It took around 1.4 secs to render this image.

I didn't like the ouput, but to be honest, I just wrote this app in 2 minutes as a [cough... cough... bad...] proof of concept. :) I'm almost sure the rendering quality can be improved, but I'm quite busy ATM. Anyway, I think you can try something similar and then decide if this approach is worth a shot. :)

Update: It seems JEuclid has a JMathComponent in order to display MathML content in a Component.

-
That's great! Thanks for your time :) –  Hidde Jan 20 '12 at 16:03
What is the minimum library to include to go from the MathML output to a PNG image? I don't require any other conversions and would like to keep the software as light as possible. So for just converting MathML to an image file using JEuclid do I just need to include the core and nothing else? –  user32313 Jun 16 '13 at 6:10
@Ozzy: according to JEuclid's usage page, the minimal distribution covers .png output, so it's certainly safe to use it. :) –  Paulo Cereda Jun 16 '13 at 15:19

Another solution to create a PNG image from LaTeX provided that LaTeX (for instance: MiKTeX) is installed on the computer...

LaTeX standalone package allows the creation of a PNG output file, the size of which exactly corresponds to the size of the formula or of the text.

So, we just have to call LaTeX from Java, and get the PNG output file.

1. Prerequisites

a) LaTeX shall be installed on the computer
... with all packages necessary for the formula (in the below example: amsfonts and amsmath)
... with standalone package

GhostScript shall be installed (necessary for standalone package)
The directory containing gswin32c.exe shall be added to PATH.
On my computer: C:\Program Files (x86)\gs\gs9.10\bin

ImageMagick shall be installed (necessary for standalone package)
convert.exe shall be renamed as imgconvert.exe
The directory containing imgconvert.exe shall be added to PATH.
On my computer: C:\Program Files (x86)\ImageMagick-6.8.8-9

2. Check that LaTeX (with standalone package) succeeds in generating the PNG file (no Java at this stage).

LaTeX file, called New21.tex (for instance):

\documentclass[border=0.50001bp,convert={convertexe={imgconvert},outext=.png}]{standalone}

\usepackage{amsfonts}

\usepackage{amsmath}

\begin{document}

$\begin{array}{l} \forall\varepsilon\in\mathbb{R}_+^*\ \exists\eta>0\ |x-x_0|\leq\eta\Longrightarrow|f(x)-f(x_0)|\leq\varepsilon\\ \det\begin{bmatrix}a_{11}&a_{12}&\cdots&a_{1n}\\a_{21}&\ddots&&\vdots\\\vdots&&\ddots&\vdots\\a_{n1}&\cdots&\cdots&a_{nn}\end{bmatrix}\overset{\mathrm{def}}{=}\sum_{\sigma\in\mathfrak{S}_n}\varepsilon(\sigma)\prod_{k=1}^n a_{k\sigma(k)}\\ {\sideset{_\alpha^\beta}{_\gamma^\delta}{\mathop{\begin{pmatrix}a&b\\c&d\end{pmatrix}}}}\\ \int_0^\infty{x^{2n} e^{-a x^2}\,dx} = \frac{2n-1}{2a} \int_0^\infty{x^{2(n-1)} e^{-a x^2}\,dx} = \frac{(2n-1)!!}{2^{n+1}} \sqrt{\frac{\pi}{a^{2n+1}}}\\ \int_a^b{f(x)\,dx} = (b - a) \sum\limits_{n = 1}^\infty {\sum\limits_{m = 1}^{2^n - 1} {\left( { - 1} \right)^{m + 1} } } 2^{ - n} f(a + m\left( {b - a} \right)2^{-n} )\\ \int_{-\pi}^{\pi} \sin(\alpha x) \sin^n(\beta x) dx = \textstyle{\left \{ \begin{array}{cc} (-1)^{(n+1)/2} (-1)^m \frac{2 \pi}{2^n} \binom{n}{m} & n \mbox{ odd},\ \alpha = \beta (2m-n) \\ 0 & \mbox{otherwise} \\ \end{array} \right .}\\ L = \int_a^b \sqrt{ \left|\sum_{i,j=1}^ng_{ij}(\gamma(t))\left(\frac{d}{dt}x^i\circ\gamma(t)\right)\left(\frac{d}{dt}x^j\circ\gamma(t)\right)\right|}\,dt\\ \begin{array}{rl} s &= \int_a^b\left\|\frac{d}{dt}\vec{r}\,(u(t),v(t))\right\|\,dt \\ &= \int_a^b \sqrt{u'(t)^2\,\vec{r}_u\cdot\vec{r}_u + 2u'(t)v'(t)\, \vec{r}_u\cdot\vec{r}_v+ v'(t)^2\,\vec{r}_v\cdot\vec{r}_v}\,\,\, dt. \end{array}\\ \end{array}$

\end{document}


Command line:

pdflatex -shell-escape New21.tex


This should generate a file New21.png containing the below picture:

3. Generation of the PNG file from Java, through a call to LaTeX

Code:

import java.awt.FlowLayout;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

class StreamPrinter implements Runnable {

// Source: http://labs.excilys.com/2012/06/26/runtime-exec-pour-les-nuls-et-processbuilder/
private final InputStream inputStream;

private boolean print;

StreamPrinter(InputStream inputStream, boolean print) {
this.inputStream = inputStream;
this.print = print;
}

}

@Override
public void run() {
String ligne = "";
try {
while ((ligne = br.readLine()) != null) {
if (print) {
System.out.println(ligne);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

public class Exemple141_LaTeX_to_PNG_using_installed_LaTeX_distribution {

public static void main(String[] args) {

String TEMP_DIRECTORY = "D:\\_tmp";
String TEMP_TEX_FILE_NAME = "New22"; // for New22.tex

// 1. Prepare the .tex file
String newLineWithSeparation = System.getProperty("line.separator")+System.getProperty("line.separator");
String math = "";
math += "\\documentclass[border=0.50001bp,convert={convertexe={imgconvert},outext=.png}]{standalone}" + newLineWithSeparation;
math += "\\usepackage{amsfonts}" + newLineWithSeparation;
math += "\\usepackage{amsmath}" + newLineWithSeparation;
math += "\\begin{document}" + newLineWithSeparation;
math += "$\\begin{array}{l}" + newLineWithSeparation; math += "\\forall\\varepsilon\\in\\mathbb{R}_+^*\\ \\exists\\eta>0\\ |x-x_0|\\leq\\eta\\Longrightarrow|f(x)-f(x_0)|\\leq\\varepsilon\\\\" + newLineWithSeparation; math += "\\det\\begin{bmatrix}a_{11}&a_{12}&\\cdots&a_{1n}\\\\a_{21}&\\ddots&&\\vdots\\\\\\vdots&&\\ddots&\\vdots\\\\a_{n1}&\\cdots&\\cdots&a_{nn}\\end{bmatrix}\\overset{\\mathrm{def}}{=}\\sum_{\\sigma\\in\\mathfrak{S}_n}\\varepsilon(\\sigma)\\prod_{k=1}^n a_{k\\sigma(k)}\\\\" + newLineWithSeparation; math += "{\\sideset{_\\alpha^\\beta}{_\\gamma^\\delta}{\\mathop{\\begin{pmatrix}a&b\\\\c&d\\end{pmatrix}}}}\\\\" + newLineWithSeparation; math += "\\int_0^\\infty{x^{2n} e^{-a x^2}\\,dx} = \\frac{2n-1}{2a} \\int_0^\\infty{x^{2(n-1)} e^{-a x^2}\\,dx} = \\frac{(2n-1)!!}{2^{n+1}} \\sqrt{\\frac{\\pi}{a^{2n+1}}}\\\\" + newLineWithSeparation; math += "\\int_a^b{f(x)\\,dx} = (b - a) \\sum\\limits_{n = 1}^\\infty {\\sum\\limits_{m = 1}^{2^n - 1} {\\left( { - 1} \\right)^{m + 1} } } 2^{ - n} f(a + m\\left( {b - a} \\right)2^{-n} )\\\\" + newLineWithSeparation; math += "\\int_{-\\pi}^{\\pi} \\sin(\\alpha x) \\sin^n(\\beta x) dx = \\textstyle{\\left \\{ \\begin{array}{cc} (-1)^{(n+1)/2} (-1)^m \\frac{2 \\pi}{2^n} \\binom{n}{m} & n \\mbox{ odd},\\ \\alpha = \\beta (2m-n) \\\\ 0 & \\mbox{otherwise} \\\\ \\end{array} \\right .}\\\\" + newLineWithSeparation; math += "L = \\int_a^b \\sqrt{ \\left|\\sum_{i,j=1}^ng_{ij}(\\gamma(t))\\left(\\frac{d}{dt}x^i\\circ\\gamma(t)\\right)\\left(\\frac{d}{dt}x^j\\circ\\gamma(t)\\right)\\right|}\\,dt\\\\" + newLineWithSeparation; math += "\\begin{array}{rl} s &= \\int_a^b\\left\\|\\frac{d}{dt}\\vec{r}\\,(u(t),v(t))\\right\\|\\,dt \\\\ &= \\int_a^b \\sqrt{u'(t)^2\\,\\vec{r}_u\\cdot\\vec{r}_u + 2u'(t)v'(t)\\, \\vec{r}_u\\cdot\\vec{r}_v+ v'(t)^2\\,\\vec{r}_v\\cdot\\vec{r}_v}\\,\\,\\, dt. \\end{array}\\\\" + newLineWithSeparation; math += "\\end{array}$" + newLineWithSeparation;
math += "\\end{document}";

// 2. Create the .tex file
FileWriter writer = null;
try {
writer = new FileWriter(TEMP_DIRECTORY + "\\" + TEMP_TEX_FILE_NAME + ".tex", false);
writer.write(math, 0, math.length());
writer.close();
} catch (IOException ex) {
ex.printStackTrace();
}

// 3. Execute LaTeX from command line  to generate picture
ProcessBuilder pb = new ProcessBuilder("pdflatex", "-shell-escape", TEMP_TEX_FILE_NAME + ".tex");
pb.directory(new File(TEMP_DIRECTORY));
try {
Process p = pb.start();
StreamPrinter fluxSortie = new StreamPrinter(p.getInputStream(), false);
StreamPrinter fluxErreur = new StreamPrinter(p.getErrorStream(), false);
p.waitFor();
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}

// 4. Display picture
JFrame maFrame = new JFrame();
maFrame.setResizable(false);
maFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
maFrame.setSize(400, 400);
maFrame.getContentPane().setLayout(new FlowLayout());
maFrame.getContentPane().add(new JLabel(new ImageIcon(TEMP_DIRECTORY + "\\" + TEMP_TEX_FILE_NAME + ".png")));
maFrame.pack();
maFrame.setVisible(true);

// 5. Delete files
for (File file : (new File(TEMP_DIRECTORY).listFiles())) {
if (file.getName().startsWith(TEMP_TEX_FILE_NAME + ".")) {
file.delete();
}
}
}
}


The above code should create the below frame:

Nicolas

-

Another solution is to call mimetex.cgi (available here: http://www.forkosh.com/mimetex.html) from Java.

I do not pretend that this solution is "better" than the ones previously given. The purpose is just to give alternatives.

Example of result:

import java.awt.*;
import java.io.*;
import java.util.ArrayList;
import javax.swing.*;

public class Exemple106_MimetexInterface {

private static String MIMETEX_EXE = "c:\\Program Files (x86)\\mimetex\\mimetex.cgi";

final private static int BUFFER_SIZE = 1024;

/**
* Convert LaTeX code to GIF
*
* @param latexString LaTeX code
* @return GIF image, under byte[] format
*/
public static byte[] getLaTeXImage(String latexString) {
byte[] imageData = null;
try {
// mimetex is asked (on the command line) to convert
// the LaTeX expression to .gif on standard output:
Process proc = Runtime.getRuntime().exec(MIMETEX_EXE + " -d \"" + latexString + "\"");
// get the output stream of the process:
BufferedInputStream bis = (BufferedInputStream) proc.getInputStream();
// read output process by bytes blocks (size: BUFFER_SIZE)
// and stores the result in a byte[] Arraylist:
byte[] buffer = new byte[BUFFER_SIZE];
ArrayList<byte[]> al = new ArrayList<byte[]>();
}
// convert the Arraylist in an unique array:
int nbOfArrays = al.size();
if (nbOfArrays == 1) {
imageData = buffer;
} else {
imageData = new byte[BUFFER_SIZE * nbOfArrays];
byte[] temp;
for (int k = 0; k < nbOfArrays; k++) {
temp = al.get(k);
for (int i = 0; i < BUFFER_SIZE; i++) {
imageData[BUFFER_SIZE * k + i] = temp[i];
}
}
}
bis.close();
proc.destroy();
} catch (IOException e) {
e.printStackTrace();
}
return imageData;
}

/**
* demonstration main
*
* @param args command line arguments
*/
public static void main(String[] args) {
JFrame jframe = new JFrame();
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setLayout(new BorderLayout());

String LATEX_EXPRESSION_1 = "4$A=\$$\\array{3,c.cccBCCC&1&2&3\\\\\\hdash~1&a_{11}&a_{12}&a_{13}\\\\2&a_{21}&a_{22}&a_{23}\\\\3&a_{31}&a_{32}&a_{33}}\$$ "; byte[] imageData1 = getLaTeXImage(LATEX_EXPRESSION_1); JLabel button1 = new JLabel(new ImageIcon(imageData1)); jframe.add(button1, BorderLayout.NORTH); String LATEX_EXPRESSION_2 = "4$\\array{rccclBCB$&f&\\longr[75]^{\\alpha:{-1$f\\rightar~g}}&g\\\\3$\\gamma&\\longd[50]&&\\longd[50]&3$\\gamma\\\\&u&\\longr[75]_\\beta&v}";
byte[] imageData2 = getLaTeXImage(LATEX_EXPRESSION_2);
JLabel button2 = new JLabel(new ImageIcon(imageData2));

String LATEX_EXPRESSION_3 = "4$\\hspace{5}\\unitlength{1}\\picture(175,100){~(50,50){\\circle(100)}(1,50){\\overbrace{\\line(46)}^{4$\\;\\;a}}(52,50) {\\line(125)}~(50,52;115;2){\\mid}~(52,55){\\longleftar[60]}(130,56){\\longrightar[35]}~(116,58){r}~(c85,50;80;2){\\bullet} (c85,36){3$-q}~(c165,36){3$q}(42,30){\\underbrace{\\line(32)}_{1\$a^2/r\\;\\;\\;}}~}";
byte[] imageData3 = getLaTeXImage(LATEX_EXPRESSION_3);
JLabel button3 = new JLabel(new ImageIcon(imageData3));

jframe.pack();
jframe.setLocationRelativeTo(null);
jframe.setVisible(true);
}
}


Nicolas

-

SnuggleTeX is used by RTextDoc RTextDoc text editor to convert Latex to HTML

-

I know very little about Java programming, but I am pretty sure that there are free applications that use JLaTeXMath to render LaTeX that you can try and look at. I have pretty good experience with Geogebra. The rendering in Geogebra is pretty fast (generally does not seem to slow the application down in any way), and the output is rather nice, I think. It is a free software, so you can download the source code and see how they do it.

-

Using Java's Runtime class you can execute external processes, so you can easily generate some LaTeX input file that contains the LaTeX expressions, execute pdflatex on the input file, possibly use Runrime to convert the pdf output to a different format (with gs) and open the resulting picture.

If you know Java this should be easy to implement. I don't have time to do this myself, but I'm confident this shouldn't take more than an hour or so.

-

Have you seen JavaTeX? If that doesn't solve your problem, can you describe the features you're looking for and other constraints?

-
This is a program, but I am looking for a Java library. I want to give a String, and receive anything I can draw on a JPanel or any other JComponent, preferably a BufferedImage. (This is why I asked this question on SO, they probably know a lot more about this kind of stuff.) –  Hidde Jan 19 '12 at 16:40
The source is available on sourceforge. You should be able to extract the functionality to a library. –  recluze Jan 19 '12 at 16:42
JavaTeX is NTS combined with a dvi viewer. That's nice, but also a 10 year old dead end. –  Martin Schröder Jan 19 '12 at 21:57