at.ac.tuwien.ims.latex2mobiformulaconv.converter.Converter.java Source code

Java tutorial

Introduction

Here is the source code for at.ac.tuwien.ims.latex2mobiformulaconv.converter.Converter.java

Source

package at.ac.tuwien.ims.latex2mobiformulaconv.converter;

import at.ac.tuwien.ims.latex2mobiformulaconv.converter.html2mobi.HtmlToMobiConverter;
import at.ac.tuwien.ims.latex2mobiformulaconv.converter.latex2html.LatexToHtmlConverter;
import at.ac.tuwien.ims.latex2mobiformulaconv.converter.mathml2html.FormulaConverter;
import at.ac.tuwien.ims.latex2mobiformulaconv.converter.mathml2html.elements.Formula;
import org.apache.commons.io.filefilter.FileFileFilter;
import org.apache.log4j.Logger;
import org.jdom2.Document;
import org.jdom2.output.XMLOutputter;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/*
 * The MIT License (MIT)
 * latex2mobi -- LaTeX Formulas to Mobi Converter
 * Copyright (c) 2014 Michael Au
 * <p/>
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * <p/>
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * <p/>
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * <p/>
 * <p/>
 * For Third Party Software Licenses read LICENSE file in base dir.
 */

/**
 * Converts LaTeX input to Mobi files
 *
 * @author Michael Au
 *         Date: 17.08.14
 *         Time: 17:35
 */
public class Converter {
    private static final Logger logger = Logger.getLogger(Converter.class);
    private static final String MAIN_CSS_FILENAME = "main.css";
    private static final String FILE_EXTENSION = ".mobi";

    private LatexToHtmlConverter latexToHtmlConverter;
    private HtmlToMobiConverter htmlToMobiConverter;
    private FormulaConverter formulaConverter;

    private Path workingDirectory;

    /**
     * ArrayList of input paths, only the first gets read
     */
    private List<Path> inputPaths;

    /**
     * if true, the formulas will get replaced with png pictures
     * else the will be represented with html
     */
    private boolean replaceWithPictures = false;

    /**
     * if true debug markup will be generated including latex, mathml + html
     * Does not affect logging in any way
     */
    private boolean debugMarkupOutput = false;

    /**
     * if this flag is true, the resulting html + css
     * will be saved to an extra folder
     */
    private boolean exportMarkup = false;

    /**
     * if this flag is true, the converter will stop after generating the
     * html markup without generating the mobi result file
     * and this will force exportMarkup to be always true!
     */
    private boolean noMobiConversion = false;

    /**
     * the directory path where the result will be written to
     */
    private Path outputPath;

    /**
     * the filename of the result file, if it already exists, a number will automatically be added to this string
     */
    private String filename;

    /**
     * The eBook's title (i.e. for the Kindle device library),
     * does not affect the filename!
     */
    private String title;

    public Path getWorkingDirectory() {
        return workingDirectory;
    }

    public void setWorkingDirectory(Path workingDirectory) {
        this.workingDirectory = workingDirectory;
    }

    public LatexToHtmlConverter getLatexToHtmlConverter() {
        return latexToHtmlConverter;
    }

    public void setLatexToHtmlConverter(LatexToHtmlConverter latexToHtmlConverter) {
        this.latexToHtmlConverter = latexToHtmlConverter;
    }

    public HtmlToMobiConverter getHtmlToMobiConverter() {
        return htmlToMobiConverter;
    }

    public void setHtmlToMobiConverter(HtmlToMobiConverter htmlToMobiConverter) {
        this.htmlToMobiConverter = htmlToMobiConverter;
    }

    public FormulaConverter getFormulaConverter() {
        return formulaConverter;
    }

    public void setFormulaConverter(FormulaConverter formulaConverter) {
        this.formulaConverter = formulaConverter;
    }

    public boolean isExportMarkup() {
        return exportMarkup;
    }

    public void setExportMarkup(boolean exportMarkup) {
        this.exportMarkup = exportMarkup;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public boolean isReplaceWithPictures() {
        return replaceWithPictures;
    }

    public void setReplaceWithPictures(boolean replaceWithPictures) {
        this.replaceWithPictures = replaceWithPictures;
    }

    public boolean isDebugMarkupOutput() {
        return debugMarkupOutput;
    }

    public void setDebugMarkupOutput(boolean debugMarkupOutput) {
        this.debugMarkupOutput = debugMarkupOutput;
    }

    public Path getOutputPath() {
        return outputPath;
    }

    public void setOutputPath(Path outputPath) {
        this.outputPath = outputPath;
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public List<Path> getInputPaths() {
        return inputPaths;
    }

    public void setInputPaths(List<Path> inputPaths) {
        this.inputPaths = inputPaths;
    }

    public boolean isNoMobiConversion() {
        return noMobiConversion;
    }

    public void setNoMobiConversion(boolean noMobiConversion) {
        this.noMobiConversion = noMobiConversion;
    }

    /**
     * Converts a single input file from LaTeX to Mobi
     *
     * @return Path of the resulting File
     * @throws FileNotFoundException when there's no file at the inputPath location
     */
    public Path convert() throws FileNotFoundException {
        // Currently only the first input path will be evaluated
        File inputFile = inputPaths.get(0).toFile();

        final String fullFilePath = inputFile.toPath().toAbsolutePath().toString();

        if (Files.exists(inputPaths.get(0))) {
            logger.debug("Input file found: " + fullFilePath);

        } else {
            throw new FileNotFoundException("Input file could not be found at: " + fullFilePath);
        }

        // set default title
        if (title == null) {
            title = inputFile.getName();
        }

        // Main Document conversion to HTML, without formulas
        logger.debug("Converting main document to HTML...");
        Document document = latexToHtmlConverter.convert(inputFile, title);

        logger.info("Parsing LaTeX formulas from resulting HTML...");

        Map<Integer, Formula> formulaMap = new HashMap<>();

        formulaConverter.setGenerateDebugMarkup(debugMarkupOutput);

        Map<Integer, String> latexFormulas = formulaConverter.extractFormulas(document);

        if (latexFormulas.isEmpty() == false) {
            Iterator<Integer> it = latexFormulas.keySet().iterator();
            while (it.hasNext()) {
                Integer id = it.next();
                String latexFormula = latexFormulas.get(id);

                Formula formula = formulaConverter.parse(id, latexFormula);

                if (formula != null) {
                    formulaMap.put(id, formula);
                }
            }
            document = formulaConverter.replaceFormulas(document, formulaMap);
        }

        // Persisting markup
        File htmlFile = saveHtmlFile(document);

        Path markupDir = null;

        // markup is requested or implicit output
        if (exportMarkup || noMobiConversion) {
            markupDir = exportMarkup(htmlFile.toPath());
        }

        if (noMobiConversion) {
            // no mobi file will be generated in any way, just the markup
            return markupDir.toAbsolutePath();
        } else {
            // Convert to MOBI format
            logger.info("Converting completed HTML to MOBI format...");
            File mobiFile = htmlToMobiConverter.convertToMobi(htmlFile);

            // Save file
            Path resultFilepath = null;
            try {
                // Don't overwrite files
                Path outputFilepath;
                int i = 1;
                String replaceFilename = filename + FILE_EXTENSION;
                while (true) {
                    outputFilepath = outputPath.resolve(replaceFilename);
                    if (Files.exists(outputFilepath) == false) {
                        break;
                    }
                    replaceFilename = filename + " (" + i + ")" + FILE_EXTENSION;
                    i++;
                }

                resultFilepath = Files.move(mobiFile.toPath(), outputFilepath);
                logger.debug("Mobi file moved to: " + resultFilepath.toAbsolutePath().toString());
                return resultFilepath.toAbsolutePath();

            } catch (IOException e) {
                logger.error("Error writing or moving output file");
                logger.error(e.getMessage(), e);
                return null;
            }
        }
    }

    /**
     * Saves the html document to a file with .html extension
     *
     * @param document JDOM Document representing the HTML
     * @return written HTML File object
     */
    private File saveHtmlFile(Document document) {
        Path tempFilepath = null;

        Path tempDirPath = formulaConverter.getTempDirPath();

        ClassLoader classLoader = getClass().getClassLoader();
        InputStream mainCssIs = classLoader.getResourceAsStream(MAIN_CSS_FILENAME);

        logger.debug("Copying main.css file to temp dir: " + tempDirPath.toAbsolutePath().toString());
        try {
            Files.copy(mainCssIs, tempDirPath.resolve(MAIN_CSS_FILENAME));
        } catch (FileAlreadyExistsException e) {
            // do nothing
        } catch (IOException e) {
            logger.error("could not copy main.css file to temp dir!");
        }

        tempFilepath = tempDirPath.resolve("latex2mobi.html");

        logger.debug("tempFile created at: " + tempFilepath.toAbsolutePath().toString());
        try {
            Files.write(tempFilepath, new XMLOutputter().outputString(document).getBytes(Charset.forName("UTF-8")));

            if (debugMarkupOutput) {
                logger.info("Debug markup will be generated.");
            }

        } catch (IOException e) {
            logger.error("Error writing HTML to temp dir!");
            logger.error(e.getMessage(), e);
        }

        return tempFilepath.toFile();
    }

    /**
     * This will save the HTML markup + css file to a specified folder
     *
     * @param tempFilepath the temp folder where
     * @return
     */
    private Path exportMarkup(Path tempFilepath) {
        Path resultPath;
        if (outputPath != null) {
            resultPath = outputPath;
        } else {
            resultPath = workingDirectory;
        }

        Path markupDir = resultPath.resolve(title + "-markup");
        try {
            try {
                Files.createDirectory(markupDir);
            } catch (FileAlreadyExistsException e) {
                // do nothing
            }

            Path tempDirPath = tempFilepath.getParent();
            File tempDir = tempDirPath.toFile();

            // Copy all files from temp folder to the markup output folder
            String[] files = tempDir.list(FileFileFilter.FILE);
            for (int i = 0; i < files.length; i++) {
                Files.copy(tempDirPath.resolve(files[i]), markupDir.resolve(files[i]),
                        StandardCopyOption.REPLACE_EXISTING);
            }

            logger.info("Exported markup to folder: " + markupDir.toAbsolutePath().toString());
        } catch (IOException e) {
            logger.error("Error saving markup files: " + e.getMessage(), e);
            return null;
        }
        return markupDir;
    }
}