External LaTeX packages | .NET

External LaTeX packages

The Aspose.TeX library includes a number of common LaTeX packages. So you don’t have to worry about how to provide these packages to the library’s TeX engine. But sometimes (or quite often) your LaTeX file may require a package beyond the “natively” supported “bundle” of packages. If this is the case, you can try to provide the required input, i.e. required package’s source files, via the RequiredInputDirectory option 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 can see that the file requires the fancybox package, which is not “natively” supported. Let’s also assume that we have the fancybox package source file. It is a simple package, so it really consists of a single file. We can place this file anywhere in our file system and specify the directory path as simply as shown below:

1options.RequiredInputDirectory = 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.OutputWorkingDirectory = new OutputFileSystemDirectory(RunExamples.OutputDirectory);
 5// Specify a file system working directory for the required input.
 6// The directory containing packages may be located anywhere.
 7options.RequiredInputDirectory = new InputFileSystemDirectory(Path.Combine(RunExamples.InputDirectory, "packages"));
 8// Initialize the options for saving in PNG format.
 9options.SaveOptions = new PngSaveOptions();
10// Run LaTeX to PNG conversion.
11new TeXJob(Path.Combine(RunExamples.InputDirectory, "required-input-fs.tex"), new ImageDevice(), options).Run();

Archived required input (pgfplots package)

Let’s now say 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 can 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 number 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 this is how we specify the access to these source files:

1using (Stream zipStream = File.Open("path-to-zip-with-pgfplots-sources"), FileMode.Open))
2{
3    ...
4    options.RequiredInputDirectory = new InputZipDirectory(zipStream);
5    ...
6}

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.OutputWorkingDirectory = new OutputFileSystemDirectory(RunExamples.OutputDirectory);
 5// Initialize the options for saving in PNG format.
 6options.SaveOptions = new PngSaveOptions();
 7// Create a file stream for the ZIP archive containing the required package.
 8// The ZIP archive may be located anywhere.
 9using (Stream zipStream = File.Open(Path.Combine(RunExamples.InputDirectory, "packages\\pgfplots.zip"), FileMode.Open))
10{
11    // Specify a ZIP working directory for the required input.
12    options.RequiredInputDirectory = new InputZipDirectory(zipStream, "");
13    
14    // Run LaTeX to PNG conversion.
15    new TeXJob(Path.Combine(RunExamples.InputDirectory, "required-input-zip.tex"), new ImageDevice(), options).Run();
16}

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.

Employing external font packages

As a rule, LaTeX distributions provide a set of default fonts available for typesetting. Except these fonts, Aspose.TeX includes a number of non-standard font packages. For example, amsfonts, eurosym, and wasysym. As we saw above, Aspose.TeX also allows to employ external packages. But mostly we were talking about packages that don’t contain fonts.

The Aspose.TeX’s Object TeX engine extension needs font maps (which are text files in a certain format with the .map extension by convention) to determine which physical fonts correspond to each TeX’s internal font name. These font maps must be loaded into TeX’s memory during the initialization phase. And, of course, they must be present among the files of the package you are plugging in. Since the engine doesn’t know the names of all font maps, it looks for all files with the .map extension. Therefore, an implementation of the IInputWorkingDirectory interface that is used as a value of the RequiredInputDirectory option must provide a way to access collections of file names by extension. More specifically, this implementation must also implement the IFileCollector interface. The standard implementations - InputFileSystemDirectory and InputZipDirectory - already do it.

Below, we provide an illustrative example of a custom required input directory that also implements the IFileCollector interface. While focusing on collecting file names by extension, 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
 5// internal font names to file names of physical fonts.
 6public class RequiredInputDirectory : IInputWorkingDirectory, IFileCollector
 7{
 8    private Dictionary<string, Dictionary<string, string>> _fileNames =
 9        new Dictionary<string, Dictionary<string, string>>();
10
11    public RequiredInputDirectory()
12    {
13    }
14
15    // This method should preliminarily be called for each file entry that is supposed to be located inside
16    // the required input directory. Inside is an example of how the dictionary of file names could be organized
17    // for easy collection of file names by extension.
18    // Here fileName is a full file name. This can be a file path on a file system, a URL, or whatever else (theoretically).
19    public void StoreFileName(string fileName)
20    {
21        string extension = Path.GetExtension(fileName);
22        string name = Path.GetFileNameWithoutExtension(fileName);
23        
24        Dictionary<string, string> files;
25        if (!_fileNames.TryGetValue(extension, out files))
26            _fileNames.Add(extension, files = new Dictionary<string, string>());
27
28        files[name] = fileName;
29    }
30
31    // The IInputWorkingDirectory implementation.
32    public NamedStream GetFile(string fileName, bool searchSubdirectories = false)
33    {
34        return new NamedStream(null, fileName); // Here we actually return a stream for the file requested by its name.
35    }
36
37    // Here is how we gather file collections by extension.
38    public string[] GetFileNamesByExtension(string extension, string path = null)
39    {
40        Dictionary<string, string> files;
41        if (!_fileNames.TryGetValue(extension, out files))
42            return new string[0];
43
44        return new List<string>(files.Values).ToArray();
45    }
46
47    public void Dispose()
48    {
49        _fileNames.Clear();
50    }
51}

Restrictions

It may happen that a package required by your LaTeX file is 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.

It may also happen that a package required by your LaTeX file directly calls 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.