External LaTeX packages | Java

External LaTeX packages

There is a number of common LaTeX packages included in the Aspose.TeX library for Java. So you don’t have to take care about how to provide these packages to the library’s TeX engine. But sometimes (maybe often) your LaTeX file may require a package beyond the “natively” supported “bundle” of packages. In this case, you can try to provide the required input, i.e. required package’s source files, using the setRequiredInputDirectory() method of the TeXOptions class instance. We will see how this works with two examples.

Unpacked required input (fancybox package)

Let’s say we have the following simple LaTeX file, which is required-input-fs.tex from our example solution:

 1\documentclass{article}
 2\usepackage[a6paper,landscape]{geometry}
 3\usepackage{fancybox}
 4\begin{document}
 5Test: \fbox{
 6  \begin{Bitemize}[b]
 7  \item First item
 8  \item A second one\\ on two lines
 9  \item(2pt) A third with extra space
10  \end{Bitemize}
11}
12\par\bigskip
13Test: \fbox{
14  \begin{Beqnarray}[t]
15  y & = & x^2 \\
16  a^2 + 2ab + b^2 & = & (a + b)^2 \\
17  \int_0^\infty e^{-ax} dx & = & \frac{1}{a}
18  \end{Beqnarray}
19}
20\end{document}

On the 3rd line, we see that the file requires the fancybox package, which is not “natively” supported. We also assume that we have the fancybox package source file. It is a simple package, so it really consists of just one file. We can place this file anywhere in our file system and specify the directory path as simply as follows:

1options.setRequiredInputDirectory(new InputFileSystemDirectory("path-to-directory-where-fancybox.sty-located"));

After running a TeX job with this option (don’t forget to adjust the other options as needed), we get the output document (i.e., a PNG image).

Output Document

Here is the complete source code for the example:

 1// Create conversion options for Object LaTeX format upon Object TeX engine extension.
 2TeXOptions options = TeXOptions.consoleAppOptions(TeXConfig.objectLaTeX());
 3// Specify a file system working directory for the output.
 4options.setOutputWorkingDirectory(new OutputFileSystemDirectory(Utils.getOutputDirectory()));
 5// Specify a file system working directory for the required input.
 6// The directory containing packages may be located anywhere.
 7options.setRequiredInputDirectory(new InputFileSystemDirectory(Utils.getInputDirectory() + "packages"));
 8// Initialize the options for saving in PNG format.
 9options.setSaveOptions(new PngSaveOptions());
10// Run LaTeX to PNG conversion.
11new TeXJob(Utils.getInputDirectory() + "required-input-fs.tex", new ImageDevice(), options).run();

Archived required input (pgfplots package)

Let’s now assume that we have the following also quite simple LaTeX file, which is required-input-zip.tex from our example solution:

 1\documentclass{article}
 2\usepackage[margin=0.25in]{geometry}
 3\usepackage{pgfplots}
 4\pgfplotsset{width=10cm,compat=1.18}
 5\begin{document}
 6
 7First example is 2D and 3D math expressions plotted side-by-side.
 8
 9%Here begins the 2D plot
10\begin{tikzpicture}
11\begin{axis}
12\addplot[color=red]{exp(x)};
13\end{axis}
14\end{tikzpicture}
15%Here ends the 2D plot
16\hskip 5pt
17%Here begins the 3D plot
18\begin{tikzpicture}
19\begin{axis}
20\addplot3[
21    surf,
22]
23{exp(-x^2-y^2)*x};
24\end{axis}
25\end{tikzpicture}
26%Here ends the 3D plot
27
28\end{document}

On the 3rd line, we see that the file requires the pgfplots package, which is also not “natively” supported. Again, we assume that we have the pgfplots package source files. It’s quite a large set of files that are divided between two locations if you find them in the installation directory of any LaTeX typesetting application. You can find pgfplots folder at both \tex\generic and \tex\latex folders. And the contents of both these folders must be provided as required input to the Aspose.TeX library. We want these source file to be packaged in a ZIP archive, so here is the archive’s layout:

archive’s layout

And here is how we specify the access to these source files:

1final Stream zipStream = File.Open("path-to-zip-with-pgfplots-sources"), FileMode.Open))
2try {
3    ...
4    options.setRequiredInputDirectory(new InputZipDirectory(zipStream));
5    ...
6} finally {
7    if (zipStream != null)
8        zipStream.close();
9}

After running a TeX job with this option, we get the output document:

Output document

Here is the complete source code for the example:

 1// Create conversion options for Object LaTeX format upon Object TeX engine extension.
 2TeXOptions options = TeXOptions.consoleAppOptions(TeXConfig.objectLaTeX());
 3// Specify a file system working directory for the output.
 4options.setOutputWorkingDirectory(new OutputFileSystemDirectory(Utils.getOutputDirectory()));
 5// Initialize the options for saving in PNG format.
 6options.setSaveOptions(new PngSaveOptions());
 7// Create a file stream for the ZIP archive containing the required package.
 8// The ZIP archive may be located anywhere.
 9final InputStream stream = new FileInputStream(Utils.getInputDirectory() + "packages\\pgfplots.zip");
10try {
11    // Specify a ZIP working directory for the required input.
12    options.setRequiredInputDirectory(new InputZipDirectory(stream, ""));
13    
14    // Run LaTeX to PNG conversion.
15    new TeXJob(Utils.getInputDirectory() + "required-input-zip.tex", new ImageDevice(), options).run();
16} finally {
17    if (stream != null)
18        stream.close();
19}

NOTE: The result was verified using the pgfplots package version 1.18.1. While the version of the pfg package included in the Aspose.TeX library is 3.1.9a.

Using external font packages

Typically, LaTeX distributions come with a selection of default fonts that can be used for typesetting. In addition to these fonts, Aspose.TeX offers several non-standard font packages, such as amsfonts, eurosym, and wasysym. As mentioned earlier, Aspose.TeX also supports the use of external packages, although our focus has mainly been on packages that do not include fonts.

The Object TeX engine extension in Aspose.TeX requires font maps, which are text files with the .map extension that specify the physical fonts corresponding to each TeX’s internal font name. These font maps need to be loaded into TeX’s memory during the initialization phase and must be included in the package files. Since the engine is not aware of the names of all font maps, it searches for any files with the .map extension. Therefore, the implementation of the IInputWorkingDirectory interface used as the value of the RequiredInputDirectory option must provide a way to access collections of file names based on their extension. Specifically, this implementation must also implement the IFileCollector interface. The standard implementations, InputFileSystemDirectory and InputZipDirectory, already fulfill this requirement.

Below, we present an example of a custom required input directory that also implements the IFileCollector interface. Our main emphasis is on gathering file names based on their extension, and we intentionally omit the details of file storage and retrieval.

 1// This is an implementation of IInputWorkingDirectory that is suitable for the TeX job's RequiredInputDirectory option
 2// in case required input contains fonts provided by external packages.
 3// The class additionally implements IFileCollector, which provides access to file collections by extension.
 4// This is necessary to load external font maps, which are files (outside TeX syntax) that map TeX's
 5public class RequiredInputDirectory implements IInputWorkingDirectory, IFileCollector
 6{
 7    private Map<String, Map<String, String>> _fileNames = new HashMap<String, Map<String, String>>();
 8
 9    public RequiredInputDirectory()
10    { 
11    }
12
13    // This method should preliminarily be called for each file entry that is supposed to be located inside
14    // the required input directory. Inside is an example of how the dictionary of file names could be organized
15    // for easy collection of file names by extension.
16    // Here fileName is a full file name. This can be a file path on a file system, a URL, or whatever else (theoretically).
17    public void storeFileName(String fileName)
18    {
19        String extension = getExtension(fileName);
20        String name = getFileNameWithoutExtension(fileName);
21
22        Map<String, String> files = _fileNames.get(extension);
23        if (files == null)
24            _fileNames.put(extension, files = new HashMap<String, String>());
25
26        files.put(name, fileName);
27    }
28
29    // The IInputWorkingDirectory implementation.
30    public TeXInputStream getFile(String fileName, boolean searchSubdirectories)
31    {
32        return new TeXInputStream(null, fileName); // Here we actually return a stream for the file requested by its name.
33    }
34    
35    // Here is how we gather file collections by extension.
36    public String[] getFileNamesByExtension(String extension)
37    {
38    	return getFileNamesByExtension(extension, null);
39    }
40
41    // Here is how we gather file collections by extension.
42    public String[] getFileNamesByExtension(String extension, String path)
43    {
44        Map<String, String> files = _fileNames.get(extension);
45        if (files == null)
46            return new String[0];
47        
48        return files.values().toArray(new String[0]);
49    }
50    
51    private String getExtension(String fileName)
52    {
53    	int pos = fileName.indexOf('.');
54    	if (pos < 0)
55    		return "";
56    	
57    	return fileName.substring(pos);
58    }
59    
60    private String getFileNameWithoutExtension(String fileName)
61    {
62    	int pos = fileName.lastIndexOf('/');
63    	if (pos >= 0)
64    		fileName = fileName.substring(pos + 1);
65    	
66    	pos = fileName.indexOf('.');
67    	if (pos < 0)
68    		return fileName;
69    	
70    	return fileName.substring(0, pos);
71    }
72
73    public void close()
74    {
75        _fileNames.clear();
76    }
77}

Restrictions

A package required by your LaTeX file may be developed under the LaTeX3e kernel. Such a package will most likely not work with the Aspose.TeX library since the latter is based on the LaTeX2e kernel.

Also, a package required by your LaTeX file may directly call device-dependent primitive commands that are not supported by the Aspose.TeX library’s Object TeX engine. Such a package, unfortunately, will not work for sure.

Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.