From 33b9ff1a363bf248082688f8f101a07c11a05e5f Mon Sep 17 00:00:00 2001 From: Niels Ole Salscheider Date: Thu, 22 Sep 2011 19:09:26 +0200 Subject: [PATCH] Add LatexRenderer class --- CMakeLists.txt | 1 + ui/latexrenderer.cpp | 195 +++++++++++++++++++++++++++++++++++++++++++ ui/latexrenderer.h | 51 +++++++++++ 3 files changed, 247 insertions(+) create mode 100644 ui/latexrenderer.cpp create mode 100644 ui/latexrenderer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ac1227333..f8dcba060 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ set(okularpart_SRCS ui/formwidgets.cpp ui/guiutils.cpp ui/ktreeviewsearchline.cpp + ui/latexrenderer.cpp ui/minibar.cpp ui/pageitemdelegate.cpp ui/pagepainter.cpp diff --git a/ui/latexrenderer.cpp b/ui/latexrenderer.cpp new file mode 100644 index 000000000..fc2c64361 --- /dev/null +++ b/ui/latexrenderer.cpp @@ -0,0 +1,195 @@ +/*************************************************************************** + * Copyright (C) 2004 by Duncan Mac-Vicar Prett * + * Copyright (C) 2004-2005 by Olivier Goffart * + * Copyright (C) 2011 by Niels Ole Salscheider * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "latexrenderer.h" + +#include +#include +#include +#include + +namespace GuiUtils +{ + +LatexRenderer::LatexRenderer() +{ + m_filelist = new QVector(); +} + +LatexRenderer::~LatexRenderer() +{ + while (!m_filelist->isEmpty()) + { + QFile::remove(m_filelist->last()); + m_filelist->pop_back(); + } + + delete m_filelist; +} + + +LatexRenderer::Error LatexRenderer::renderLatexInHtml( QString& html, const QColor& textColor, int fontSize, int resolution, QString& latexOutput ) +{ + if( !html.contains("$$")) + return NoError; + + // this searches for $$formula$$ + QRegExp rg("\\$\\$.+\\$\\$"); + rg.setMinimal(true); + + int pos = 0; + + QMap replaceMap; + while (pos >= 0 && pos < html.length()) + { + pos = rg.indexIn(html, pos); + + if (pos >= 0 ) + { + const QString match = rg.cap(0); + pos += rg.matchedLength(); + + QString formul=match; + // first remove the $$ delimiters on start and end + formul.remove("$$"); + // then trim the result, so we can skip totally empty/whitespace-only formulas + formul = formul.trimmed(); + if (formul.isEmpty() || !securityCheck(formul)) + continue; + + QString fileName; + Error returnCode = handleLatex(fileName, formul, textColor, fontSize, resolution, latexOutput); + if (returnCode != NoError) + return returnCode; + + replaceMap[match] = fileName; + } + } + + if(replaceMap.isEmpty()) //we haven't found any LaTeX strings + return NoError; + + int imagePxWidth,imagePxHeight; + for (QMap::ConstIterator it = replaceMap.constBegin(); it != replaceMap.constEnd(); ++it) + { + QImage theImage(*it); + if(theImage.isNull()) + continue; + imagePxWidth = theImage.width(); + imagePxHeight = theImage.height(); + QString escapedLATEX=Qt::escape(it.key()).replace('\"',"""); //we need the escape quotes because that string will be in a title="" argument, but not the \n + html.replace(Qt::escape(it.key()), " \"" "); + } + return NoError; +} + +bool LatexRenderer::mightContainLatex (const QString& text) +{ + if( !text.contains("$$")) + return false; + + // this searches for $$formula$$ + QRegExp rg("\\$\\$.+\\$\\$"); + rg.setMinimal(true); + if( rg.lastIndexIn(text) == -1 ) + return false; + + return true; +} + +LatexRenderer::Error LatexRenderer::handleLatex( QString& fileName, const QString& latexFormula, const QColor& textColor, int fontSize, int resolution, QString& latexOutput ) +{ + KProcess latexProc; + KProcess dvipngProc; + + KTemporaryFile *tempFile = new KTemporaryFile(); + tempFile->setPrefix("kdelatex-"); + tempFile->setSuffix(".tex"); + tempFile->open(); + QString tempFileName = tempFile->fileName(); + QFileInfo *tempFileInfo = new QFileInfo(tempFileName); + QString tempFileNameNS = tempFileInfo->absolutePath() + QDir::separator() + tempFileInfo->baseName(); + QString tempFilePath = tempFileInfo->absolutePath(); + delete tempFileInfo; + QTextStream tempStream(tempFile); + + tempStream << "\ +\\documentclass[" << fontSize << "pt]{article} \ +\\usepackage{color} \ +\\usepackage{amsmath,latexsym,amsfonts,amssymb,ulem} \ +\\pagestyle{empty} \ +\\begin{document} \ +{\\color[rgb]{" << textColor.redF() << "," << textColor.greenF() << "," << textColor.blueF() << "} \ +\\begin{eqnarray*} \ +" << latexFormula << " \ +\\end{eqnarray*}} \ +\\end{document}"; + + tempFile->close(); + QString latexExecutable = KStandardDirs::findExe("latex"); + if (latexExecutable.isEmpty()) + { + qDebug() << "Could not find latex!"; + delete tempFile; + fileName = QString(""); + return LatexNotFound; + } + latexProc << latexExecutable << "-interaction=nonstopmode" << "-halt-on-error" << QString("-output-directory=%1").arg(tempFilePath) << tempFile->fileName(); + latexProc.setOutputChannelMode( KProcess::MergedChannels ); + latexProc.execute(); + latexOutput = latexProc.readAll(); + tempFile->remove(); + + QFile::remove(tempFileNameNS + QString(".log")); + QFile::remove(tempFileNameNS + QString(".aux")); + delete tempFile; + + if (!QFile::exists(tempFileNameNS + QString(".dvi"))) + { + fileName = QString(""); + return LatexFailed; + } + + QString dvipngExecutable = KStandardDirs::findExe("dvipng"); + if (dvipngExecutable.isEmpty()) + { + qDebug() << "Could not find dvipng!"; + fileName = QString(""); + return DvipngNotFound; + } + + dvipngProc << dvipngExecutable << QString("-o%1").arg(tempFileNameNS + QString(".png")) << "-Ttight" << "-bgTransparent" << QString("-D %1").arg(resolution) << QString("%1").arg(tempFileNameNS + QString(".dvi")); + dvipngProc.setOutputChannelMode( KProcess::MergedChannels ); + dvipngProc.execute(); + + QFile::remove(tempFileNameNS + QString(".dvi")); + + if (!QFile::exists(tempFileNameNS + QString(".png"))) + { + fileName = QString(""); + return DvipngFailed; + } + + m_filelist->append(tempFileNameNS + QString(".png")); + fileName = tempFileNameNS + QString(".png"); + return NoError; +} + +bool LatexRenderer::securityCheck( const QString &latexFormula ) +{ + return !latexFormula.contains(QRegExp("\\\\(def|let|futurelet|newcommand|renewcomment|else|fi|write|input|include" + "|chardef|catcode|makeatletter|noexpand|toksdef|every|errhelp|errorstopmode|scrollmode|nonstopmode|batchmode" + "|read|csname|newhelp|relax|afterground|afterassignment|expandafter|noexpand|special|command|loop|repeat|toks" + "|output|line|mathcode|name|item|section|mbox|DeclareRobustCommand)[^a-zA-Z]")); +} + +} \ No newline at end of file diff --git a/ui/latexrenderer.h b/ui/latexrenderer.h new file mode 100644 index 000000000..6fa615ec2 --- /dev/null +++ b/ui/latexrenderer.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2004 by Duncan Mac-Vicar Prett * + * Copyright (C) 2004-2005 by Olivier Goffart * + * Copyright (C) 2011 by Niels Ole Salscheider * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef LATEXRENDERER_H +#define LATEXRENDERER_H +#include "guiutils.h" + +#include +class QString; +class QColor; + +namespace GuiUtils +{ + +class LatexRenderer +{ + +public: + enum Error { + NoError, + LatexNotFound, + DvipngNotFound, + LatexFailed, + DvipngFailed + }; + + LatexRenderer(); + virtual ~LatexRenderer(); + + Error renderLatexInHtml( QString& html, const QColor &textColor, int fontSize, int resolution, QString &latexOutput ); + static bool mightContainLatex ( const QString& text ); + +private: + Error handleLatex( QString &fileName, const QString &latexFormula, const QColor &textColor, int fontSize, int resolution, QString &latexOutput ); + static bool securityCheck( const QString &latexFormula ); + + QVector *m_filelist; +}; + +} + +#endif // LATEXRENDERER_H