Paquetes LaTeX externos | Java

Paquetes externos de LaTeX

Hay varios paquetes comunes de LaTeX incluidos en la biblioteca Aspose.TeX para Java. Por lo tanto, no tiene que preocuparse por cómo proporcionar estos paquetes al motor TeX de la biblioteca. Pero a veces (tal vez a menudo) su archivo LaTeX puede requerir un paquete más allá del “paquete” de paquetes admitido “de forma nativa”. En este caso, puede intentar proporcionar la entrada requerida, es decir, los archivos fuente del paquete requerido, utilizando el método setRequiredInputDirectory() de la instancia de clase TeXOptions. Veremos cómo funciona esto con dos ejemplos.

Establezca inputFile en la ruta completa del documento LaTeX correspondiente y outputDirectory en una carpeta de salida existente. Ambos ejemplos de conversión generan PNG a 150 DPI. Importe las clases Aspose.TeX usadas en el ejemplo seleccionado, com.aspose.tex.rendering.ImageDevice, com.aspose.tex.rendering.PngSaveOptions y, para entrada ZIP, java.io.InputStream y java.nio.file.Files. Gestione o declare las excepciones en el método que llama al ejemplo. Aplique una licencia según la guía de licencias.

Entrada requerida desempaquetada (paquete fancybox)

Digamos que tenemos el siguiente archivo LaTeX simple, que es required-input-fs.tex de nuestra solución de ejemplo:

 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}
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}

La tercera línea requiere el paquete externo fancybox. Establezca packagesDirectory en una carpeta local con fancybox.sty y sus dependencias. El ejemplo completo siguiente asigna esta carpeta a RequiredInputDirectory y genera una imagen PNG. El dispositivo y los directorios de trabajo permanecen abiertos hasta que termina el trabajo y después se liberan o cierran.

Documento de salida

Aquí está el código fuente completo del ejemplo:

 1// Render the fancybox document using external package sources from a local folder.
 2// inputFile is the full TeX input path; packagesDirectory contains fancybox.sty.
 3// outputDirectory is an existing output folder.
 4TeXOptions options = TeXOptions.consoleAppOptions(TeXConfig.objectLaTeX());
 5OutputFileSystemDirectory output = new OutputFileSystemDirectory(outputDirectory);
 6InputFileSystemDirectory packages = new InputFileSystemDirectory(packagesDirectory);
 7options.setOutputWorkingDirectory(output);
 8options.setRequiredInputDirectory(packages);
 9PngSaveOptions saving = new PngSaveOptions();
10saving.setResolution(150);
11options.setSaveOptions(saving);
12options.setInteraction(Interaction.NonstopMode);
13options.setTerminalOut(new OutputMemoryTerminal());
14ImageDevice device = new ImageDevice();
15TeXJobResult result;
16int pages;
17try {
18    result = new TeXJob(inputFile, device, options).run();
19    pages = device.getPageCount();
20} finally {
21    device.dispose();
22    output.close();
23    packages.close();
24}

Entrada requerida archivada (paquete pgfplots)

Supongamos ahora que tenemos el siguiente archivo LaTeX también bastante simple, que es required-input-zip.tex de nuestra solución de ejemplo:

 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}

En la tercera línea, vemos que el archivo requiere el paquete pgfplots, que tampoco es compatible de forma “nativa”. Nuevamente, asumimos que tenemos los archivos fuente del paquete pgfplots. Es un conjunto bastante grande de archivos que se dividen en dos ubicaciones si los encuentra en el directorio de instalación de cualquier aplicación de composición tipográfica LaTeX. Puede encontrar la carpeta pgfplots en las carpetas \tex\generic y \tex\latex. Y el contenido de ambas carpetas debe proporcionarse como entrada requerida para la biblioteca Aspose.TeX. Queremos que estos archivos fuente estén empaquetados en un archivo ZIP, así que aquí está el diseño del archivo:

diseño del archivo

Establezca packagesZip en un java.nio.file.Path al archivo que contiene las fuentes genéricas y LaTeX del paquete. El ejemplo Java completo siguiente lo abre con Files.newInputStream(...) y asigna un InputZipDirectory a RequiredInputDirectory. El argumento de ruta base vacío selecciona todo el archivo. Mantenga abiertos el flujo ZIP y el directorio hasta que termine el trabajo TeX y después ciérrelos. El resultado es una imagen PNG con las dos gráficas.

Documento de salida

Aquí está el código fuente completo del ejemplo:

 1// Render the 2D/3D plots using pgfplots package sources from a ZIP archive.
 2// inputFile is the full TeX input path; packagesZip is a java.nio.file.Path.
 3// outputDirectory is an existing output folder; the ZIP includes generic and latex sources.
 4TeXJobResult result;
 5int pages;
 6try (InputStream zipStream = Files.newInputStream(packagesZip)) {
 7    TeXOptions options = TeXOptions.consoleAppOptions(TeXConfig.objectLaTeX());
 8    OutputFileSystemDirectory output = new OutputFileSystemDirectory(outputDirectory);
 9    InputZipDirectory packages = new InputZipDirectory(zipStream, "");
10    options.setOutputWorkingDirectory(output);
11    options.setRequiredInputDirectory(packages);
12    PngSaveOptions saving = new PngSaveOptions();
13    saving.setResolution(150);
14    options.setSaveOptions(saving);
15    options.setInteraction(Interaction.NonstopMode);
16    options.setTerminalOut(new OutputMemoryTerminal());
17    ImageDevice device = new ImageDevice();
18    try {
19        result = new TeXJob(inputFile, device, options).run();
20        pages = device.getPageCount();
21    } finally {
22        device.dispose();
23        output.close();
24        packages.close();
25    }
26}

NOTA: El resultado se verificó utilizando la versión 1.18.1 del paquete pgfplots. Mientras que la versión del paquete pfg incluida en la biblioteca Aspose.TeX es la 3.1.9a.

Usar paquetes de fuentes externos

Normalmente, las distribuciones de LaTeX vienen con una selección de fuentes predeterminadas que se pueden utilizar para la composición tipográfica. Además de estas fuentes, Aspose.TeX ofrece varios paquetes de fuentes no estándar, como amsfonts, eurosym y wasysym. Como se mencionó anteriormente, Aspose.TeX también admite el uso de paquetes externos, aunque nos hemos centrado principalmente en paquetes que no incluyen fuentes. La extensión del motor Object TeX en Aspose.TeX requiere mapas de fuentes, que son archivos de texto con la extensión .map que especifican las fuentes físicas correspondientes al nombre de fuente interna de cada TeX. Estos mapas de fuentes deben cargarse en la memoria de TeX durante la fase de inicialización y deben incluirse en los archivos del paquete. Dado que el motor no conoce los nombres de todos los mapas de fuentes, busca cualquier archivo con la extensión .map. Por lo tanto, la implementación de la interfaz IInputWorkingDirectory utilizada como valor de la opción RequiredInputDirectory debe proporcionar una forma de acceder a colecciones de nombres de archivos según su extensión. Específicamente, esta implementación también debe implementar la interfaz IFileCollector. Las implementaciones estándar, InputFileSystemDirectory e InputZipDirectory, ya cumplen este requisito.

El siguiente RequiredInputDirectory personalizado implementa ambas interfaces y lee archivos locales registrados explícitamente. Guárdelo como RequiredInputDirectory.java con sus importaciones incluidas. Registre cada archivo con storeFileName(...), asigne la instancia con options.setRequiredInputDirectory(...) y ciérrela después del trabajo. Es un registro plano: los nombres de archivo deben ser únicos cuando se solicitan sin ruta completa. Las extensiones no distinguen mayúsculas de minúsculas; la ruta de recopilación opcional selecciona un directorio del sistema de archivos. Registre todos los archivos de paquete, mapas de fuentes, métricas y fuentes físicas necesarios. La recopilación permite encontrar los mapas, pero no proporciona datos de fuentes que falten.

 1import com.aspose.tex.IInputWorkingDirectory;
 2import com.aspose.tex.IFileCollector;
 3import com.aspose.tex.TeXInputStream;
 4import java.io.IOException;
 5import java.io.UncheckedIOException;
 6import java.nio.file.Files;
 7import java.nio.file.Path;
 8import java.nio.file.Paths;
 9import java.util.ArrayList;
10import java.util.LinkedHashSet;
11import java.util.List;
12import java.util.Locale;
13import java.util.Set;
14
15// Register local package files explicitly, including font maps and their dependencies.
16// Save this class as RequiredInputDirectory.java and close it after the TeX job.
17public class RequiredInputDirectory implements IInputWorkingDirectory, IFileCollector {
18    private final Set<Path> files = new LinkedHashSet<Path>();
19    private final List<TeXInputStream> streams = new ArrayList<TeXInputStream>();
20
21    public void storeFileName(String fileName) {
22        Path file = Paths.get(fileName).toAbsolutePath().normalize();
23        if (!Files.isRegularFile(file)) {
24            throw new IllegalArgumentException("Package file does not exist: " + file);
25        }
26        files.add(file);
27    }
28
29    @Override
30    public TeXInputStream getFile(String fileName, boolean searchSubdirectories) {
31        // This registry is a flat virtual directory; only registered files are accessible.
32        for (Path file : files) {
33            if (file.toString().equals(fileName) || file.getFileName().toString().equals(fileName)) {
34                try {
35                    TeXInputStream stream = new TeXInputStream(Files.newInputStream(file), file.toString());
36                    streams.add(stream);
37                    return stream;
38                } catch (IOException exception) {
39                    throw new UncheckedIOException(exception);
40                }
41            }
42        }
43        return new TeXInputStream(null, fileName);
44    }
45
46    @Override
47    public String[] getFileNamesByExtension(String extension) {
48        return getFileNamesByExtension(extension, null);
49    }
50
51    @Override
52    public String[] getFileNamesByExtension(String extension, String path) {
53        String requested = extension.toLowerCase(Locale.ROOT);
54        if (!requested.isEmpty() && !requested.startsWith(".")) {
55            requested = "." + requested;
56        }
57        Path directory = path == null ? null : Paths.get(path).toAbsolutePath().normalize();
58        List<String> matches = new ArrayList<String>();
59        for (Path file : files) {
60            String name = file.getFileName().toString();
61            int dot = name.lastIndexOf('.');
62            String actual = dot < 0 ? "" : name.substring(dot).toLowerCase(Locale.ROOT);
63            if (actual.equals(requested) && (directory == null || file.getParent().equals(directory))) {
64                matches.add(file.toString());
65            }
66        }
67        return matches.toArray(new String[0]);
68    }
69
70    @Override
71    public void close() throws IOException {
72        IOException failure = null;
73        for (TeXInputStream stream : streams) {
74            try {
75                stream.close();
76            } catch (IOException exception) {
77                if (failure == null) { failure = exception; }
78                else { failure.addSuppressed(exception); }
79            }
80        }
81        streams.clear();
82        files.clear();
83        if (failure != null) { throw failure; }
84    }
85}

Restricciones

Un paquete requerido por su archivo LaTeX puede desarrollarse bajo el kernel LaTeX3e. Lo más probable es que un paquete de este tipo no funcione con la biblioteca Aspose.TeX ya que esta última se basa en el kernel LaTeX2e.

Además, un paquete requerido por su archivo LaTeX puede llamar directamente a comandos primitivos dependientes del dispositivo que no son compatibles con el motor Object TeX de la biblioteca Aspose.TeX. Desafortunadamente, un paquete así no funcionará con seguridad.