00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <stdlib.h>
00024
00025
00026
00027 #include <qregexp.h>
00028 #include <qfile.h>
00029 #include <qdatetime.h>
00030 #include <qtextstream.h>
00031
00032 #include "klfblockprocess.h"
00033 #include "klfbackend.h"
00034
00036 #define TRANSLATE(x) QString(x)
00037
00038
00039 KLFBackend::KLFBackend()
00040 {
00041 }
00042
00043
00044
00045 QString progErrorMsg(QString progname, int exitstatus, QString stderr, QString stdout)
00046 {
00047 if (stderr.isEmpty())
00048 return TRANSLATE("<p><b>%1</b> reported an error (exit status %2). Here is full stdout output:</p>\n"
00049 "<pre>\n%3</pre>")
00050 .arg(progname).arg(exitstatus).arg(stdout);
00051 if (stdout.isEmpty())
00052 return TRANSLATE("<p><b>%1</b> reported an error (exit status %2). Here is full stderr output:</p>\n"
00053 "<pre>\n%3</pre>")
00054 .arg(progname).arg(exitstatus).arg(stderr);
00055
00056 return TRANSLATE("<p><b>%1</b> reported an error (exit status %2). Here is full stderr output:</p>\n"
00057 "<pre>\n%3</pre><p>And here is full stdout output:</p><pre>\n%4</pre>")
00058 .arg(progname).arg(exitstatus).arg(stderr).arg(stdout);
00059 }
00060
00061
00062 KLFBackend::klfOutput KLFBackend::getLatexFormula(const klfInput& in, const klfSettings& settings)
00063 {
00064 klfOutput res;
00065 res.status = 0;
00066 res.errorstr = QString();
00067 res.result = QImage();
00068 res.pngdata = QByteArray();
00069 res.epsdata = QByteArray();
00070 res.pdfdata = QByteArray();
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 QString tempfname = settings.tempdir + "/klatexformulatmp2-"
00081 + QDateTime::currentDateTime().toString("hh-mm-ss");
00082
00083
00084 #ifdef KLFBACKEND_QT4
00085 QString latexsimplified = in.latex.trimmed();
00086 #else
00087 QString latexsimplified = in.latex.stripWhiteSpace();
00088 #endif
00089 if (latexsimplified.isEmpty()) {
00090 res.errorstr = TRANSLATE("You must specify a LaTeX formula!");
00091 res.status = -1;
00092 return res;
00093 }
00094
00095 QString latexin;
00096 if (in.mathmode.contains("...") == 0) {
00097 res.status = -2;
00098 res.errorstr = TRANSLATE("The math mode string doesn't contain '...'!");
00099 return res;
00100 }
00101 latexin = in.mathmode;
00102 latexin.replace("...", in.latex);
00103
00104 {
00105 QFile file(tempfname+".tex");
00106 #ifdef KLFBACKEND_QT4
00107 bool r = file.open(QIODevice::WriteOnly);
00108 #else
00109 bool r = file.open(IO_WriteOnly);
00110 #endif
00111 if ( ! r ) {
00112 res.status = -3;
00113 res.errorstr = TRANSLATE("Can't open file for writing: '%1'!").arg(tempfname+".tex");
00114 return res;
00115 }
00116 QTextStream stream(&file);
00117 stream << "\\documentclass{klatexformula}\n"
00118 << "\\usepackage[usenames]{color}\n"
00119 << in.preamble << "\n"
00120 << "\\begin{document}\n"
00121 << QString("\\definecolor{klffgcolor}{rgb}{%1,%2,%3}\n").arg(qRed(in.fg_color)/255.0)
00122 .arg(qGreen(in.fg_color)/255.0).arg(qBlue(in.fg_color)/255.0)
00123 << QString("\\definecolor{klfbgcolor}{rgb}{%1,%2,%3}\n").arg(qRed(in.bg_color)/255.0)
00124 .arg(qGreen(in.bg_color)/255.0).arg(qBlue(in.bg_color)/255.0)
00125 << ( (qAlpha(in.bg_color)>0) ? "\\pagecolor{klfbgcolor}\n" : "" )
00126 << "{\\color{klffgcolor} " << latexin << " }\n"
00127 << "\\end{document}\n";
00128 }
00129
00130 {
00131
00132
00133 KLFBlockProcess proc;
00134 QStringList args;
00135 QStringList env;
00136 extern char **environ;
00137
00138 proc.setWorkingDirectory(settings.tempdir);
00139 bool texinputsset = false;
00140 for (int i = 0; environ && environ[i] != NULL; ++i) {
00141 if (!strncmp(environ[i], "TEXINPUTS=", strlen("TEXINPUTS="))) {
00142 QString s = environ[i];
00143 s.insert(strlen("TEXINPUTS="), settings.klfclspath+":");
00144 texinputsset = true;
00145 env << s;
00146 } else {
00147 env << environ[i];
00148 }
00149 }
00150 if (!texinputsset) {
00151 env << "TEXINPUTS="+settings.klfclspath+":.";
00152 }
00153 args << settings.latexexec << tempfname+".tex";
00154
00155 bool r = proc.startProcess(args, env);
00156
00157
00158 if (!r) {
00159 res.status = -4;
00160 res.errorstr = TRANSLATE("Unable to start Latex!");
00161 return res;
00162 }
00163 if (!proc.normalExit()) {
00164 res.status = -5;
00165 res.errorstr = TRANSLATE("Latex was killed!");
00166 return res;
00167 }
00168 if (proc.exitStatus() != 0) {
00169 cleanup(tempfname);
00170 res.status = 1;
00171 res.errorstr = progErrorMsg("LaTeX", proc.exitStatus(), proc.readStderrString(), proc.readStdoutString());
00172 return res;
00173 }
00174
00175 if (!QFile::exists(tempfname + ".dvi")) {
00176 res.status = -6;
00177 res.errorstr = TRANSLATE("DVI file didn't appear after having called Latex!");
00178 return res;
00179 }
00180
00181 }
00182
00183 {
00184
00185 KLFBlockProcess proc;
00186 QStringList args;
00187 args << settings.dvipsexec << "-E" << (tempfname+".dvi") << "-o" << (tempfname+".eps");
00188
00189 bool r = proc.startProcess(args);
00190
00191 if ( ! r ) {
00192 res.status = -7;
00193 res.errorstr = TRANSLATE("Unable to start dvips!\n");
00194 return res;
00195 }
00196 if ( !proc.normalExit() ) {
00197 res.status = -8;
00198 res.errorstr = TRANSLATE("Dvips was mercilessly killed!\n");
00199 return res;
00200 }
00201 if ( proc.exitStatus() != 0) {
00202 res.status = 2;
00203 res.errorstr = progErrorMsg("dvips", proc.exitStatus(), proc.readStderrString(), proc.readStdoutString());
00204 return res;
00205 }
00206 if (!QFile::exists(tempfname + ".eps")) {
00207 res.status = -9;
00208 res.errorstr = TRANSLATE("EPS file didn't appear after dvips call!\n");
00209 return res;
00210 }
00211
00212
00213
00214 QFile epsfile(tempfname+".eps");
00215 #ifdef KLFBACKEND_QT4
00216 r = epsfile.open(QIODevice::ReadOnly);
00217 #else
00218 r = epsfile.open(IO_ReadOnly);
00219 #endif
00220 if ( ! r ) {
00221 res.status = -10;
00222 res.errorstr = TRANSLATE("Can't read file '%1'!\n").arg(tempfname+".eps");
00223 return res;
00224 }
00225 QByteArray epscontent = epsfile.readAll();
00226 #ifdef KLFBACKEND_QT4
00227 int i = epscontent.indexOf("%%BoundingBox: ");
00228 if ( i == -1 ) {
00229 res.status = -11;
00230 res.errorstr = TRANSLATE("File '%1' does not contain line \"%%BoundingBox: ... \" !").arg(tempfname+".eps");
00231 }
00232 int ax, ay, bx, by;
00233 char temp[250];
00234 int k = i;
00235 i += strlen("%%BoundingBox:");
00236 int n = sscanf(epscontent.constData()+i, "%d %d %d %d", &ax, &ay, &bx, &by);
00237 if ( n != 4 ) {
00238 res.status = -12;
00239 res.errorstr = TRANSLATE("file %1: Line %%BoundingBox: can't read values!\n").arg(tempfname+".eps");
00240 return res;
00241 }
00242 sprintf(temp, "%%%%BoundingBox: %d %d %d %d", ax-settings.lborderoffset, ay-settings.bborderoffset,
00243 bx+settings.rborderoffset, by+settings.tborderoffset);
00244 QString chunk = QString::fromLocal8Bit(epscontent.constData()+k);
00245 QRegExp rx("^%%BoundingBox: [0-9]+ [0-9]+ [0-9]+ [0-9]+");
00246 (void) rx.indexIn(chunk);
00247 int l = rx.matchedLength();
00248 epscontent.replace(k, l, temp);
00249 res.epsdata = epscontent;
00250 #else
00251 QCString epscontent_s(epscontent.data(), epscontent.size());
00252
00253 int i = epscontent_s.find("%%BoundingBox: ");
00254 if ( i == -1 ) {
00255 res.status = -11;
00256 res.errorstr = TRANSLATE("File '%1' does not contain line \"%%BoundingBox: ... \" !").arg(tempfname+".eps");
00257 return res;
00258 }
00259 int ax, ay, bx, by;
00260 char temp[250];
00261 i += strlen("%%BoundingBox:");
00262 int n = sscanf((const char*)epscontent_s+i, "%d %d %d %d", &ax, &ay, &bx, &by);
00263 if ( n != 4 ) {
00264 res.status = -12;
00265 res.errorstr = TRANSLATE("file %1: Line %%BoundingBox: can't read values!\n").arg(tempfname+".eps");
00266 return res;
00267 }
00268 sprintf(temp, "%%%%BoundingBox: %d %d %d %d", ax-settings.lborderoffset, ay-settings.bborderoffset,
00269 bx+settings.rborderoffset, by+settings.tborderoffset);
00270 epscontent_s.replace(QRegExp("%%BoundingBox: [0-9]+ [0-9]+ [0-9]+ [0-9]+"), temp);
00271 res.epsdata.duplicate(epscontent_s.data(), epscontent_s.length());
00272 #endif
00273
00274 QFile epsgoodfile(tempfname+"-good.eps");
00275 #ifdef KLFBACKEND_QT4
00276 r = epsgoodfile.open(QIODevice::WriteOnly);
00277 #else
00278 r = epsgoodfile.open(IO_WriteOnly);
00279 #endif
00280 if ( ! r ) {
00281 res.status = -13;
00282 res.errorstr = TRANSLATE("Can't write to file '%1'!\n").arg(tempfname+"-good.eps");
00283 return res;
00284 }
00285 #ifdef KLFBACKEND_QT4
00286 epsgoodfile.write(res.epsdata);
00287 #else
00288 epsgoodfile.writeBlock(res.epsdata);
00289 #endif
00290
00291
00292 }
00293
00294 {
00295 KLFBlockProcess proc;
00296 QStringList args;
00297 args << settings.gsexec << "-dNOPAUSE" << "-dSAFER" << "-dEPSCrop" << "-r"+QString::number(in.dpi)
00298 << "-dTextAlphaBits=4" << "-dGraphicsAlphaBits=4";
00299 if (qAlpha(in.bg_color) > 0) {
00300 args << "-sDEVICE=png16m";
00301 } else {
00302 args << "-sDEVICE=pngalpha";
00303 }
00304 args << "-sOutputFile="+tempfname+".png" << "-q" << "-dBATCH" << (tempfname+"-good.eps");
00305
00306 bool r = proc.startProcess(args);
00307
00308 if ( ! r ) {
00309 res.status = -7;
00310 res.errorstr = TRANSLATE("Unable to start gs!\n");
00311 return res;
00312 }
00313 if ( !proc.normalExit() ) {
00314 res.status = -8;
00315 res.errorstr = TRANSLATE("gs died abnormally!\n");
00316 return res;
00317 }
00318 if ( proc.exitStatus() != 0) {
00319 res.status = 3;
00320 res.errorstr = progErrorMsg("gs", proc.exitStatus(), proc.readStderrString(), proc.readStdoutString());
00321 return res;
00322 }
00323 if (!QFile::exists(tempfname + ".png")) {
00324 res.status = -9;
00325 res.errorstr = TRANSLATE("PNG file didn't appear after call to gs!\n");
00326 return res;
00327 }
00328
00329
00330 QFile pngfile(tempfname+".png");
00331 #ifdef KLFBACKEND_QT4
00332 r = pngfile.open(QIODevice::ReadOnly);
00333 #else
00334 r = pngfile.open(IO_ReadOnly);
00335 #endif
00336 if ( ! r ) {
00337 res.status = -10;
00338 res.errorstr = TRANSLATE("Unable to read file %1!\n").arg(tempfname+".png");
00339 return res;
00340 }
00341 res.pngdata = pngfile.readAll();
00342 pngfile.close();
00343
00344 res.result.loadFromData(res.pngdata, "PNG");
00345
00346 }
00347
00348 if (!settings.epstopdfexec.isEmpty()) {
00349
00350 KLFBlockProcess proc;
00351 QStringList args;
00352 args << settings.epstopdfexec << (tempfname+"-good.eps") << "-o" << (tempfname+".pdf");
00353
00354 bool r = proc.startProcess(args);
00355
00356 if ( ! r ) {
00357 res.status = -11;
00358 res.errorstr = TRANSLATE("Unable to start epstopdf!\n");
00359 return res;
00360 }
00361 if ( !proc.normalExit() ) {
00362 res.status = -12;
00363 res.errorstr = TRANSLATE("epstopdf died nastily!\n");
00364 return res;
00365 }
00366 if ( proc.exitStatus() != 0) {
00367 res.status = 4;
00368 res.errorstr = progErrorMsg("epstopdf", proc.exitStatus(), proc.readStderrString(), proc.readStdoutString());
00369 return res;
00370 }
00371 if (!QFile::exists(tempfname + ".pdf")) {
00372 res.status = -13;
00373 res.errorstr = TRANSLATE("PDF file didn't appear after call to epstopdf!\n");
00374 return res;
00375 }
00376
00377
00378 QFile pdffile(tempfname+".pdf");
00379 #ifdef KLFBACKEND_QT4
00380 r = pdffile.open(QIODevice::ReadOnly);
00381 #else
00382 r = pdffile.open(IO_ReadOnly);
00383 #endif
00384 if ( ! r ) {
00385 res.status = -14;
00386 res.errorstr = TRANSLATE("Unable to read file %1!\n").arg(tempfname+".pdf");
00387 return res;
00388 }
00389 res.pdfdata = pdffile.readAll();
00390
00391 }
00392
00393
00394 cleanup(tempfname);
00395
00396
00397 return res;
00398 }
00399
00400
00401 void KLFBackend::cleanup(QString tempfname)
00402 {
00403 if (QFile::exists(tempfname+".tex")) QFile::remove(tempfname+".tex");
00404 if (QFile::exists(tempfname+".dvi")) QFile::remove(tempfname+".dvi");
00405 if (QFile::exists(tempfname+".aux")) QFile::remove(tempfname+".aux");
00406 if (QFile::exists(tempfname+".log")) QFile::remove(tempfname+".log");
00407 if (QFile::exists(tempfname+".toc")) QFile::remove(tempfname+".toc");
00408 if (QFile::exists(tempfname+".eps")) QFile::remove(tempfname+".eps");
00409 if (QFile::exists(tempfname+"-good.eps")) QFile::remove(tempfname+"-good.eps");
00410 if (QFile::exists(tempfname+".png")) QFile::remove(tempfname+".png");
00411 if (QFile::exists(tempfname+".pdf")) QFile::remove(tempfname+".pdf");
00412 }
00413