[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [ktp-text-ui/latex_filter] filters: Latex Filter
From:       Andrea Scarpino <andrea () archlinux ! org>
Date:       2013-03-13 23:18:47
Message-ID: 20130313231847.380BDA604F () git ! kde ! org
[Download RAW message or body]

Git commit 4f893e79adca00e737e1da0068e9ae009232888d by Andrea Scarpino.
Committed on 14/03/2013 at 00:08.
Pushed by scarpino into branch 'latex_filter'.

Latex Filter

M  +1    -0    filters/CMakeLists.txt
A  +54   -0    filters/latex/CMakeLists.txt
A  +9    -0    filters/latex/kcm_ktptextui_message_filter_latex.desktop
A  +18   -0    filters/latex/ktptextui_message_filter_latex.desktop.cmake
A  +40   -0    filters/latex/latex-config.cpp     [License: LGPL (v2.1+)]
A  +38   -0    filters/latex/latex-config.h     [License: LGPL (v2.1+)]
A  +61   -0    filters/latex/latex-config.ui
A  +190  -0    filters/latex/latex-filter.cpp     [License: LGPL (v2.1+)]
A  +44   -0    filters/latex/latex-filter.h     [License: LGPL (v2.1+)]
A  +20   -0    filters/latex/latex.kcfg
A  +4    -0    filters/latex/latexconfig.kcfgc

http://commits.kde.org/telepathy-text-ui/4f893e79adca00e737e1da0068e9ae009232888d

diff --git a/filters/CMakeLists.txt b/filters/CMakeLists.txt
index 62384cb..c66e773 100644
--- a/filters/CMakeLists.txt
+++ b/filters/CMakeLists.txt
@@ -2,6 +2,7 @@ add_subdirectory(bugzilla)
 add_subdirectory(emoticons)
 add_subdirectory(formatting)
 add_subdirectory(images)
+add_subdirectory(latex)
 add_subdirectory(searchexpansion)
 add_subdirectory(youtube)
 add_subdirectory(highlight)
diff --git a/filters/latex/CMakeLists.txt b/filters/latex/CMakeLists.txt
new file mode 100644
index 0000000..89b341b
--- /dev/null
+++ b/filters/latex/CMakeLists.txt
@@ -0,0 +1,54 @@
+set (ktptextui_message_filter_latex_SRCS
+     latex-filter.cpp
+)
+
+kde4_add_kcfg_files(ktptextui_message_filter_latex_SRCS latexconfig.kcfgc)
+
+kde4_add_plugin (ktptextui_message_filter_latex
+                 ${ktptextui_message_filter_latex_SRCS}
+)
+
+target_link_libraries (ktptextui_message_filter_latex
+    ktpchat
+    ${QT_LIBRARIES}
+    ${QT_QTGUI_LIBRARY}
+    ${KDE4_KDECORE_LIBS}
+    ${KDE4_KDEUI_LIBS}
+    ${TELEPATHY_QT4_LIBRARIES}
+    ${KTP_LIBRARIES}
+)
+
+set (kcm_ktptextui_message_filter_latex_SRCS
+     latex-config.cpp
+)
+
+kde4_add_kcfg_files(kcm_ktptextui_message_filter_latex_SRCS latexconfig.kcfgc)
+
+kde4_add_ui_files (kcm_ktptextui_message_filter_latex_SRCS
+    latex-config.ui
+)
+
+kde4_add_plugin (kcm_ktptextui_message_filter_latex
+                 ${kcm_ktptextui_message_filter_latex_SRCS}
+)
+
+target_link_libraries (kcm_ktptextui_message_filter_latex
+    ktpchat
+    ${QT_LIBRARIES}
+    ${KDE4_KDEUI_LIBS}
+)
+
+# Install:
+install (TARGETS ktptextui_message_filter_latex
+                 kcm_ktptextui_message_filter_latex
+         DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ktptextui_message_filter_latex.desktop.cmake
 +               ${CMAKE_CURRENT_BINARY_DIR}/ktptextui_message_filter_latex.desktop
+               @ONLY)
+
+install (FILES ${CMAKE_CURRENT_BINARY_DIR}/ktptextui_message_filter_latex.desktop
+               ${CMAKE_CURRENT_SOURCE_DIR}/kcm_ktptextui_message_filter_latex.desktop
 +         DESTINATION ${SERVICES_INSTALL_DIR}
+)
diff --git a/filters/latex/kcm_ktptextui_message_filter_latex.desktop \
b/filters/latex/kcm_ktptextui_message_filter_latex.desktop new file mode 100644
index 0000000..9644f9e
--- /dev/null
+++ b/filters/latex/kcm_ktptextui_message_filter_latex.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Type=Service
+X-KDE-ServiceTypes=KCModule
+
+X-KDE-Library=kcm_ktptextui_message_filter_latex
+X-KDE-ParentApp=latex
+X-KDE-ParentComponents=latex
+
+Name=Latex
\ No newline at end of file
diff --git a/filters/latex/ktptextui_message_filter_latex.desktop.cmake \
b/filters/latex/ktptextui_message_filter_latex.desktop.cmake new file mode 100644
index 0000000..3903553
--- /dev/null
+++ b/filters/latex/ktptextui_message_filter_latex.desktop.cmake
@@ -0,0 +1,18 @@
+[Desktop Entry]
+Encoding=UTF-8
+Type=Service
+ServiceTypes=KTpTextUi/MessageFilter
+
+X-KDE-Library=ktptextui_message_filter_latex
+X-KDE-PluginInfo-Author=Lasath Fernando
+X-KDE-PluginInfo-Email=kde@lasath.org
+X-KDE-PluginInfo-Name=latex
+X-KDE-PluginInfo-Version=@KTP_TEXT_UI_VERSION@
+X-KDE-PluginInfo-Website=http://community.kde.org/KTp
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=false
+X-KDE-PluginInfo-Weight=10
+X-KTp-PluginInfo-Version=@KTP_MESSAGE_FILTER_FRAMEWORK_VERSION@
+
+Name=Latex Renderer
+Comment=If incomming messages contain latex between $$, it will render it directly \
                into the chat.
diff --git a/filters/latex/latex-config.cpp b/filters/latex/latex-config.cpp
new file mode 100644
index 0000000..1169c59
--- /dev/null
+++ b/filters/latex/latex-config.cpp
@@ -0,0 +1,40 @@
+/*
+ *    Copyright (C) 2013  Andrea Scarpino <andrea@archlinux.org>
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License as published by the Free Software Foundation; either
+ *    version 2.1 of the License, or (at your option) any later version.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ *
+ *    You should have received a copy of the GNU Lesser General Public
+ *    License along with this library; if not, write to the Free Software
+ *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+*/
+
+#include "latex-config.h"
+// KConfigSkeleton
+#include "latexconfig.h"
+
+#include <KPluginFactory>
+
+K_PLUGIN_FACTORY(LatexConfigFactory, registerPlugin<LatexFilterConfig>();)
+K_EXPORT_PLUGIN(LatexConfigFactory( "kcm_ktptextui_message_filter_latex" ))
+
+LatexFilterConfig::LatexFilterConfig(QWidget* parent, const QVariantList& args)
+    : KCModule(LatexConfigFactory::componentData(), parent, args)
+{
+    ui.setupUi(this);
+    addConfig(LatexConfig::self(), this);
+    load();
+}
+
+LatexFilterConfig::~LatexFilterConfig()
+{
+}
+
+#include "latex-config.moc"
\ No newline at end of file
diff --git a/filters/latex/latex-config.h b/filters/latex/latex-config.h
new file mode 100644
index 0000000..a0b7023
--- /dev/null
+++ b/filters/latex/latex-config.h
@@ -0,0 +1,38 @@
+/*
+ *    Copyright (C) 2013  Andrea Scarpino <andrea@archlinux.org>
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License as published by the Free Software Foundation; either
+ *    version 2.1 of the License, or (at your option) any later version.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ *
+ *    You should have received a copy of the GNU Lesser General Public
+ *    License along with this library; if not, write to the Free Software
+ *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+*/
+
+#ifndef LATEX_CONFIG_H
+#define LATEX_CONFIG_H
+
+#include <KCModule>
+
+#include "ui_latex-config.h"
+
+class LatexFilterConfig : public KCModule
+{
+    Q_OBJECT
+
+public:
+    explicit LatexFilterConfig(QWidget* parent = 0, const QVariantList& args = \
QVariantList()); +    virtual ~LatexFilterConfig();
+
+private:
+    Ui::LatexConfig ui;
+};
+
+#endif // LATEX_CONFIG_H
\ No newline at end of file
diff --git a/filters/latex/latex-config.ui b/filters/latex/latex-config.ui
new file mode 100644
index 0000000..d0759c5
--- /dev/null
+++ b/filters/latex/latex-config.ui
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LatexConfig</class>
+ <widget class="QWidget" name="LatexConfig">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>470</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>LatexConfig</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Latex header:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPlainTextEdit" name="kcfg_LatexHeader">
+     <property name="plainText">
+      <string>\documentclass{standalone}
+\usepackage{color}
+\usepackage{amsmath,latexsym,amsfonts,amssymb,ulem}
+\usepackage{graphicx}
+\pagestyle{empty}
+</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>Latex command line:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="KLineEdit" name="kcfg_LatexCmd">
+     <property name="text">
+      <string>latex -interaction=batchmode -halt-on-error</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>klineedit.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/filters/latex/latex-filter.cpp b/filters/latex/latex-filter.cpp
new file mode 100644
index 0000000..a9bcb3f
--- /dev/null
+++ b/filters/latex/latex-filter.cpp
@@ -0,0 +1,190 @@
+/*
+ *    Copyright (C) 2012  Lasath Fernando <kde@lasath.org>
+ *    Copyright (C) 2013  Andrea Scarpino <andrea@archlinux.org>
+ *
+ *    Copyright (c) 2004 by Duncan Mac-Vicar Prett   <duncan@kde.org>
+ *    Copyright (c) 2004-2005 by Olivier Goffart  <ogoffart@kde. org>
+ *    Kopete    (c) 2001-2004 by the Kopete developers  <kopete-devel@kde.org>
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License as published by the Free Software Foundation; either
+ *    version 2.1 of the License, or (at your option) any later version.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ *
+ *    You should have received a copy of the GNU Lesser General Public
+ *    License along with this library; if not, write to the Free Software
+ *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+*/
+
+#include "latex-filter.h"
+// KConfigSkeleton
+#include "latexconfig.h"
+
+#include <QImage>
+
+#include <KPluginFactory>
+#include <KDebug>
+#include <KStandardDirs>
+#include <KProcess>
+#include <X11/Xproto.h>
+
+LatexFilter::LatexFilter(QObject* parent, const QVariantList &)
+    : AbstractMessageFilter(parent)
+{
+}
+
+void LatexFilter::filterMessage(KTp::Message &message, const KTp::MessageContext \
&context) +{
+    Q_UNUSED(context);
+
+    const QString messageText = message.mainMessagePart();
+    if (!messageText.contains(QLatin1String("$$"))) {
+        return;
+    }
+
+    QRegExp rg(QLatin1String("\\$\\$.+\\$\\$"));
+    rg.setMinimal(true);
+
+    QMap<QString, QString> replaceMap;
+    int pos = 0;
+    while (pos >= 0 && pos < messageText.length()) {
+        pos = rg.indexIn(messageText, 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(QLatin1String("$$"));
+            // then trim the result, so we can skip totally empty/whitespace-only \
formulas +            formul = formul.trimmed();
+            if (formul.isEmpty() || !securityCheck(formul)) {
+                continue;
+            }
+
+            // get the image and encode it with base64
+            replaceMap[match] = handleLatex(formul);
+        }
+    }
+
+    if (replaceMap.isEmpty()) {
+        // we haven't found any LaTeX strings
+        return;
+    }
+
+    for (QMap<QString, QString>::ConstIterator it = replaceMap.constBegin(); it != \
replaceMap.constEnd(); ++it) { +        QImage theImage(*it);
+        if (theImage.isNull()) {
+            continue;
+        }
+
+        message.appendMessagePart(
+                QLatin1Literal("<br/>") %
+                QLatin1Literal("<img src=\"") %
+                (*it) %
+                QLatin1Literal("\" style=\"max-width:100%;margin-top:3px\" alt=\"") \
% +                QLatin1Literal("\" />")
+        );
+    }
+}
+
+QString LatexFilter::handleLatex(const QString &latexFormula)
+{
+    QString latexText;
+    latexText.append(LatexConfig::latexHeader());
+    latexText.append(QLatin1String("\\begin{document}\n"));
+    latexText.append(QString(QLatin1String("$%1$\n"))
+                    .arg(latexFormula));
+    latexText.append(QLatin1String("\\end{document}"));
+
+    KTemporaryFile *texFile(new KTemporaryFile);
+    texFile->setPrefix(QLatin1String("ktplatex-"));
+    texFile->setSuffix(QLatin1String(".tex"));
+    if (!texFile->open()) {
+      kError() << "Cannot create the TeX file";
+      return QString();
+    }
+    texFile->write(latexText.toAscii());
+    texFile->close();
+    m_tempFiles << texFile;
+
+    if (LatexConfig::latexCmd().isEmpty()) {
+        kError() << "No TeX compiler set!";
+        return QString();
+    }
+    const QStringList latexCmd = \
LatexConfig::latexCmd().split(QRegExp(QLatin1String("\\s+"))); +
+    QStringList latexArgs;
+    Q_FOREACH(const QString &cmd, latexCmd.mid(1, latexCmd.size())) {
+        latexArgs << cmd;
+    }
+    const KStandardDirs outputDir;
+    latexArgs << QString(QLatin1String("-output-directory=%1")).arg(outputDir.resourceDirs("tmp").first());
 +    latexArgs << texFile->fileName();
+
+    if (KStandardDirs::findExe(latexCmd.first()).isEmpty()) {
+        kError() << "Cannot find the TeX" << latexCmd.first() << " program.\n;"
+                 << "Please get the software from http://tug.org/texlive/"
+                 << "or from your distribution's package manager.";
+        return QString();
+    }
+
+    kDebug() << "Running " << latexCmd.first() << latexArgs;
+
+    KProcess p;
+    p.execute(latexCmd.first(), latexArgs);
+    if (p.exitCode()) {
+        kError() << "Error compiling the TeX text";
+        return QString();
+    }
+
+    if (KStandardDirs::findExe(QLatin1String("dvipng")).isEmpty()) {
+        kError() << "Cannot find the TeX 'dvipng' program.\n;"
+                 << "Please get the software from http://tug.org/texlive/"
+                 << "or from your distribution's package manager.";
+        return QString();
+    }
+
+    const QString dviFile = \
texFile->fileName().replace(QLatin1String(".tex"),QLatin1String(".dvi")); +    const \
QString imageFile = texFile->fileName().replace(QLatin1String(".tex"),QLatin1String(".png"));
 +
+    QStringList dvipngArgs;
+    dvipngArgs << QLatin1String("-D300");
+    dvipngArgs << QLatin1String("-bgTransparent");
+    dvipngArgs << QString(QLatin1String("-o%1")).arg(imageFile);
+    dvipngArgs << dviFile;
+
+    kDebug() << "Rendering dvipng" << dvipngArgs;
+
+    p.execute(QLatin1String("dvipng"), dvipngArgs);
+    if (p.exitCode()){
+        kError() << "Error rendering the image to PNG";
+        return QString();
+    }
+
+    return imageFile;
+}
+
+bool LatexFilter::securityCheck(const QString &latexFormula)
+{
+    return !latexFormula.contains(QRegExp(QLatin1String(
+        "\\\\(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]"
 +    )));
+}
+
+LatexFilter::~LatexFilter()
+{
+    qDeleteAll(m_tempFiles);
+}
+
+K_PLUGIN_FACTORY(MessageFilterFactory, registerPlugin<LatexFilter>();)
+K_EXPORT_PLUGIN(MessageFilterFactory("ktptextui_message_filter_latex"))
\ No newline at end of file
diff --git a/filters/latex/latex-filter.h b/filters/latex/latex-filter.h
new file mode 100644
index 0000000..d2c3dde
--- /dev/null
+++ b/filters/latex/latex-filter.h
@@ -0,0 +1,44 @@
+/*
+ *    Copyright (C) 2012  Lasath Fernando <kde@lasath.org>
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License as published by the Free Software Foundation; either
+ *    version 2.1 of the License, or (at your option) any later version.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ *
+ *    You should have received a copy of the GNU Lesser General Public
+ *    License along with this library; if not, write to the Free Software
+ *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+*/
+
+#ifndef LATEX_FILTER_H
+#define LATEX_FILTER_H
+
+#include <QColor>
+
+#include <KTemporaryFile>
+
+#include <KTp/abstract-message-filter.h>
+
+class LatexFilter : public KTp::AbstractMessageFilter
+{
+Q_OBJECT
+
+public:
+    LatexFilter(QObject* parent = 0, const QVariantList &args = QVariantList());
+    virtual ~LatexFilter();
+    virtual void filterMessage(KTp::Message &message, const KTp::MessageContext \
&context); +
+private:
+    bool securityCheck(const QString &latexFormula);
+    QString handleLatex(const QString &latexFormula);
+    QList<KTemporaryFile *> m_tempFiles;
+
+};
+
+#endif // LATEX_FILTER_H
\ No newline at end of file
diff --git a/filters/latex/latex.kcfg b/filters/latex/latex.kcfg
new file mode 100644
index 0000000..97342a6
--- /dev/null
+++ b/filters/latex/latex.kcfg
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+                          http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+    <kcfgfile name="ktp-text-uirc"/>
+    <group name="Filter-Latex">
+        <entry name="LatexCmd" type="String">
+            <default>latex -interaction=batchmode -halt-on-error</default>
+        </entry>
+        <entry name="LatexHeader" type="String">
+            <default>\documentclass{standalone}
+\usepackage{color}
+\usepackage{amsmath,latexsym,amsfonts,amssymb,ulem}
+\usepackage{graphicx}
+\pagestyle{empty}
+</default>
+        </entry>
+    </group>
+</kcfg>
\ No newline at end of file
diff --git a/filters/latex/latexconfig.kcfgc b/filters/latex/latexconfig.kcfgc
new file mode 100644
index 0000000..f94b6dc
--- /dev/null
+++ b/filters/latex/latexconfig.kcfgc
@@ -0,0 +1,4 @@
+File=latex.kcfg
+ClassName=LatexConfig
+Singleton=true
+Mutators=true


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic