File indexing completed on 2024-04-21 03:51:05

0001 /*
0002     SPDX-FileCopyrightText: 2010 Daniel Laidig <laidig@kde.org>
0003     SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "latexrenderer.h"
0008 
0009 #include <KLocalizedString>
0010 #include <KProcess>
0011 #include <QColor>
0012 #include <QDebug>
0013 #include <QFileInfo>
0014 #include <QGuiApplication>
0015 #include <QLabel>
0016 #include <QTemporaryDir>
0017 #include <QTemporaryFile>
0018 #include <QtGlobal>
0019 #include <complex>
0020 
0021 using namespace Practice;
0022 
0023 const char *texTemplate =
0024     "\\documentclass[12pt,fleqn]{article}          \n "
0025     "\\usepackage{latexsym,amsfonts,amssymb,ulem}  \n "
0026     "\\usepackage[dvips]{graphicx}                 \n "
0027     "\\setlength\\textwidth{5in}                   \n "
0028     "\\setlength{\\parindent}{0pt}                 \n "
0029     "\\usepackage{amsmath}                         \n "
0030     "\\usepackage{color}                           \n "
0031     "\\pagestyle{empty}                            \n "
0032     "\\begin{document}                             \n "
0033     "{\\definecolor{mycolor}{rgb}{%1}              \n "
0034     "{\\color{mycolor}                             \n "
0035     "%2 }                                          \n "
0036     "\\end{document}\n";
0037 
0038 LatexRenderer::LatexRenderer(QObject *parent)
0039     : QObject(parent)
0040 {
0041 }
0042 
0043 void LatexRenderer::renderLatex(QString tex)
0044 {
0045     if (m_label) {
0046         m_label->setText(i18n("Rendering..."));
0047         m_label->setToolTip(tex);
0048     }
0049 
0050     if (tex.startsWith(QLatin1String("$$"))) {
0051         tex.replace(0, 2, QStringLiteral("\\begin{eqnarray*}")).remove(-2, 2).append("\\end{eqnarray*}");
0052     } else {
0053         tex.remove(0, 2).remove(-2, 2);
0054     }
0055     qDebug() << "rendering as latex";
0056 
0057     // Check if the parley subdir exists, if not, create it
0058     QString dir(QDir::tempPath() + QLatin1Char('/') + QCoreApplication::applicationName());
0059     QTemporaryFile *texFile = new QTemporaryFile(dir + QLatin1Char('/') + QLatin1String("XXXXXX") + ".tex");
0060     if (!texFile->open()) {
0061         return;
0062     }
0063 
0064     QColor color = QGuiApplication::palette().color(QPalette::WindowText);
0065     QString colorString = QString::number(color.redF()) + ',' + QString::number(color.greenF()) + ',' + QString::number(color.blueF());
0066     QString expressionTex = QString(texTemplate).arg(colorString, tex.trimmed());
0067 
0068     texFile->write(expressionTex.toUtf8());
0069     texFile->flush();
0070 
0071     QString fileName = texFile->fileName();
0072     qDebug() << "fileName: " << fileName;
0073     m_latexFilename = fileName;
0074     m_latexFilename.replace(QLatin1String(".tex"), QLatin1String(".eps"));
0075     KProcess *p = new KProcess(this);
0076     p->setWorkingDirectory(dir);
0077 
0078     (*p) << QStringLiteral("latex") << QStringLiteral("-interaction=batchmode") << QStringLiteral("-halt-on-error") << fileName;
0079 
0080     connect(p, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &LatexRenderer::convertToPs);
0081     connect(p, &QProcess::errorOccurred, this, &LatexRenderer::latexRendered);
0082     p->start();
0083 }
0084 
0085 bool LatexRenderer::isLatex(const QString &tex)
0086 {
0087     return tex.length() > 4 && tex.mid(2, tex.length() - 4).simplified().length() > 0
0088         && ((tex.startsWith(QLatin1String("$$")) && tex.endsWith(QLatin1String("$$")))
0089             || (tex.startsWith(QStringLiteral("§§")) && tex.endsWith(QStringLiteral("§§"))));
0090 }
0091 
0092 void LatexRenderer::convertToPs()
0093 {
0094     qDebug() << "converting to ps";
0095     QString dviFile = m_latexFilename;
0096     dviFile.replace(QLatin1String(".eps"), QLatin1String(".dvi"));
0097     KProcess *p = new KProcess(this);
0098     qDebug() << "running: "
0099              << "dvips"
0100              << "-E"
0101              << "-o" << m_latexFilename << dviFile;
0102     (*p) << QStringLiteral("dvips") << QStringLiteral("-E") << QStringLiteral("-o") << m_latexFilename << dviFile;
0103 
0104     connect(p, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &LatexRenderer::convertToImage);
0105     connect(p, &QProcess::errorOccurred, this, &LatexRenderer::latexRendered);
0106     p->start();
0107 }
0108 
0109 void LatexRenderer::convertToImage()
0110 {
0111     qDebug() << "converting to ps";
0112     QString pngFile = m_latexFilename;
0113     pngFile.replace(QLatin1String(".eps"), QLatin1String(".png"));
0114     KProcess *p = new KProcess(this);
0115     qDebug() << "running:"
0116              << "convert" << m_latexFilename << pngFile;
0117     (*p) << QStringLiteral("convert") << QStringLiteral("-density") << QStringLiteral("85") << m_latexFilename << pngFile;
0118 
0119     connect(p, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &LatexRenderer::latexRendered);
0120     connect(p, &QProcess::errorOccurred, this, &LatexRenderer::latexRendered);
0121     p->start();
0122 }
0123 
0124 void LatexRenderer::latexRendered()
0125 {
0126     qDebug() << "rendered file " << m_latexFilename;
0127 
0128     QString pngFile = m_latexFilename;
0129     pngFile.replace(QLatin1String(".eps"), QLatin1String(".png"));
0130     if (QFileInfo::exists(pngFile)) {
0131         QPixmap pixmap(pngFile);
0132         m_label->setPixmap(pixmap);
0133         m_label->setMinimumSize(pixmap.size().boundedTo(QSize(600, 300)));
0134     } else {
0135         m_label->setText(i18n("LaTeX error.")); // TODO: better error handling and error messages
0136     }
0137 
0138     // cleanup the temp directory a bit...
0139     QStringList extensions;
0140     extensions << QStringLiteral(".log") << QStringLiteral(".aux") << QStringLiteral(".tex") << QStringLiteral(".dvi") << QStringLiteral(".eps")
0141                << QStringLiteral(".png");
0142     for (const QString &ext : qAsConst(extensions)) {
0143         QString s = m_latexFilename;
0144         s.replace(QLatin1String(".eps"), ext);
0145         QFile f(s);
0146         f.remove();
0147     }
0148 }
0149 
0150 #include "moc_latexrenderer.cpp"