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