00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <ctype.h>
00027 #include <sys/time.h>
00028 #include <math.h>
00029
00030 #include <QtGlobal>
00031 #include <QByteArray>
00032 #include <QSet>
00033 #include <QCoreApplication>
00034 #include <QRegExp>
00035 #include <QFile>
00036 #include <QDateTime>
00037 #include <QTextStream>
00038 #include <QBuffer>
00039 #include <QDir>
00040 #include <QColor>
00041 #include <QTextDocument>
00042 #include <QImageWriter>
00043 #include <QTextCodec>
00044 #include <QTemporaryDir>
00045
00046 #include <klfutil.h>
00047 #include <klfsysinfo.h>
00048 #include <klfdatautil.h>
00049
00050 #include "klfblockprocess.h"
00051 #include "klffilterprocess.h"
00052 #include "klfuserscript.h"
00053 #include "klfbackend.h"
00054 #include "klfbackend_p.h"
00055
00056
00057
00082
00083
00084 #ifdef KLF_EXTRA_SEARCH_PATHS
00085 # define EXTRA_PATHS_PRE KLF_EXTRA_SEARCH_PATHS ,
00086
00087 #else
00088 # define EXTRA_PATHS_PRE
00089
00090 #endif
00091
00092
00093 #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64)
00094 QStringList progLATEX = QStringList() << "latex.exe";
00095 QStringList progDVIPS = QStringList() << "dvips.exe";
00096 QStringList progGS = QStringList() << "gswin32c.exe" << "gswin64c.exe" << "mgs.exe";
00097
00098 static const char * standard_extra_paths[] = {
00099 EXTRA_PATHS_PRE
00100 "C:\\Program Files*\\MiKTeX*\\miktex\\bin",
00101 "C:\\texlive\\*\\bin\\win*",
00102 "C:\\Program Files*\\gs*\\gs*\\bin",
00103 NULL
00104 };
00105 #elif defined(KLF_WS_MAC)
00106 QStringList progLATEX = QStringList() << "latex";
00107 QStringList progDVIPS = QStringList() << "dvips";
00108 QStringList progGS = QStringList() << "gs";
00109
00110 static const char * standard_extra_paths[] = {
00111 EXTRA_PATHS_PRE
00112 "/usr/texbin:/Library/TeX/texbin:/usr/local/bin:/opt/local/bin:/sw/bin:/sw/usr/bin",
00113 NULL
00114 };
00115 #else
00116 QStringList progLATEX = QStringList() << "latex";
00117 QStringList progDVIPS = QStringList() << "dvips";
00118 QStringList progGS = QStringList() << "gs";
00119
00120 static const char * standard_extra_paths[] = {
00121 EXTRA_PATHS_PRE
00122 NULL
00123 };
00124 #endif
00125
00126
00127
00128
00129
00130 KLFAbstractLatexMetaInfo::KLFAbstractLatexMetaInfo()
00131 {
00132 }
00133 KLFAbstractLatexMetaInfo::~KLFAbstractLatexMetaInfo()
00134 {
00135 }
00136
00137 void KLFAbstractLatexMetaInfo::saveMetaInfo(const KLFBackend::klfInput& in,
00138 const KLFBackend::klfSettings& settings)
00139 {
00140 static QString boolstr[2] = { QLatin1String("true"), QLatin1String("false") } ;
00141
00142 saveField("AppVersion", QString::fromLatin1("KLatexFormula " KLF_VERSION_STRING));
00143 saveField("Application",
00144 QObject::tr("Created with KLatexFormula version %1", "KLFBackend::saveOutputToFile")
00145 .arg(KLF_VERSION_STRING));
00146 saveField("Software", QString::fromLatin1("KLatexFormula " KLF_VERSION_STRING));
00147 saveField("InputLatex", in.latex);
00148 saveField("InputMathMode", in.mathmode);
00149 saveField("InputPreamble", in.preamble);
00150 saveField("InputFontSize", QString::number(in.fontsize, 'g', 2));
00151 saveField("InputFgColor", QString("rgb(%1, %2, %3)").arg(qRed(in.fg_color))
00152 .arg(qGreen(in.fg_color)).arg(qBlue(in.fg_color)));
00153 saveField("InputBgColor", QString("rgba(%1, %2, %3, %4)").arg(qRed(in.bg_color))
00154 .arg(qGreen(in.bg_color)).arg(qBlue(in.bg_color))
00155 .arg(qAlpha(in.bg_color)));
00156 saveField("InputDPI", QString::number(in.dpi));
00157 saveField("InputVectorScale", QString::number(in.vectorscale, 'g', 4));
00158 saveField("InputBypassTemplate", boolstr[(int)in.bypassTemplate]);
00159 saveField("InputUserScript", QFileInfo(in.userScript).fileName());
00160 QString usparams;
00161 klfSaveVariantToText(QVariant(klfMapToVariantMap(in.userScriptParam)), true);
00162 saveField("InputUserScriptParams", usparams);
00163 saveField("SettingsTBorderOffset", QString::number(settings.tborderoffset));
00164 saveField("SettingsRBorderOffset", QString::number(settings.rborderoffset));
00165 saveField("SettingsBBorderOffset", QString::number(settings.bborderoffset));
00166 saveField("SettingsLBorderOffset", QString::number(settings.lborderoffset));
00167 saveField("SettingsOutlineFonts", boolstr[(int)settings.outlineFonts]);
00168 saveField("SettingsCalcEpsBoundingBox", boolstr[(int)settings.calcEpsBoundingBox]);
00169 saveField("SettingsWantRaw", boolstr[(int)settings.wantRaw]);
00170 saveField("SettingsWantPDF", boolstr[(int)settings.wantPDF]);
00171 saveField("SettingsWantSVG", boolstr[(int)settings.wantSVG]);
00172
00173 klfDbg("saved meta-info.") ;
00174 }
00175
00176
00177 KLFImageLatexMetaInfo::KLFImageLatexMetaInfo(QImage *imgwrite) : _w(imgwrite) { }
00178
00179 void KLFImageLatexMetaInfo::saveField(const QString& k, const QString& v)
00180 {
00181
00182
00183 _w->setText(k, klfDataToEscaped(v.toUtf8(), '%'));
00184 }
00185 QString KLFImageLatexMetaInfo::loadField(const QString &k) {
00186 return QString::fromUtf8(klfEscapedToData(_w->text(k).toLatin1(), '%'));
00187 }
00188
00189
00190 KLF_EXPORT QByteArray klf_escape_ps_string(const QString& v)
00191 {
00192
00193 int i;
00194
00195 bool isascii = true;
00196 for (i = 0; i < v.length(); ++i) {
00197 if (v[i] < 0 || v[i] > 126) {
00198 isascii = false;
00199 break;
00200 }
00201 }
00202 QByteArray vdata;
00203 if (isascii) {
00204 vdata = v.toLatin1();
00205
00206 QByteArray escaped;
00207 for (i = 0; i < vdata.size(); ++i) {
00208 char c = vdata[i];
00209 klfDbg("Char: "<<c);
00210 if (QChar(vdata[i]).isLetterOrNumber() || c == ' ' || c == '.' || c == ',' || c == '/')
00211 escaped += c;
00212 else if (c == '\n')
00213 escaped += "\\n";
00214 else if (c == '\r')
00215 escaped += "\\r";
00216 else if (c == '\t')
00217 escaped += "\\t";
00218 else if (c == '\\')
00219 escaped += "\\\\";
00220 else if (c == '(')
00221 escaped += "\\(";
00222 else if (c == ')')
00223 escaped += "\\)";
00224 else {
00225 klfDbg("escaping char: (int)c="<<(int)c<<" (uint)c="<<uint(c)<<", octal="<<klfFmtCC("%03o", (uint)c));
00226 escaped += QString("\\%1").arg((unsigned int)(unsigned char)c, 3, 8, QChar('0')).toLatin1();
00227 }
00228 }
00229
00230 return "("+escaped+")";
00231 }
00232
00233
00234
00235 QTextCodec *codec = QTextCodec::codecForName("UTF-16BE");
00236 vdata = codec->fromUnicode(v);
00237 klfDbg("vdata is "<<klfDataToEscaped(vdata));
00238
00239 QByteArray hex;
00240 for (i = 0; i < (vdata.size()-1); i += 2) {
00241 hex += klfFmt("%02x%02x ", (unsigned int)(unsigned char)vdata[i], (unsigned int)(unsigned char)vdata[i+1]);
00242 }
00243 return "<" + hex + ">";
00244 }
00245
00246
00247
00248 KLFPdfmarksWriteLatexMetaInfo::KLFPdfmarksWriteLatexMetaInfo(QByteArray * string)
00249 : _s(string)
00250 {
00251
00252
00253
00254
00255 _s->append(
00256 "/pdfmark where { pop } { /globaldict where { pop globaldict } { userdict } ifelse "
00257 "/pdfmark /cleartomark load put } ifelse\n"
00258
00259 "[ "
00260 );
00261 }
00262
00263 QString KLFPdfmarksWriteLatexMetaInfo::loadField(const QString& )
00264 {
00265 KLF_ASSERT_CONDITION(false, "N/A.", return QString(); ) ;
00266 }
00267 void KLFPdfmarksWriteLatexMetaInfo::saveField(const QString& k, const QString& v)
00268 {
00269 savePDFField("KLF"+k, v);
00270 }
00271 void KLFPdfmarksWriteLatexMetaInfo::finish()
00272 {
00273 _s->append(" /DOCINFO pdfmark\n");
00274 }
00275 void KLFPdfmarksWriteLatexMetaInfo::savePDFField(const QString& k, const QString& v)
00276 {
00277 QByteArray datavalue = klf_escape_ps_string(v);
00278
00279 _s->append( " /"+k+" " + datavalue + "\n");
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 static QMutex klf_mutex;
00291
00292 struct GsInfo
00293 {
00294 GsInfo() { }
00295
00296 QString version;
00297 int version_maj;
00298 int version_min;
00299 QString help;
00300 QSet<QString> availdevices;
00301 };
00302
00303
00304 static QMap<QString,GsInfo> gsInfo = QMap<QString,GsInfo>();
00305
00306 static void initGsInfo(const KLFBackend::klfSettings *settings, bool isMainThread);
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 KLFBackend::TemplateGenerator::TemplateGenerator()
00318 {
00319 }
00320 KLFBackend::TemplateGenerator::~TemplateGenerator()
00321 {
00322 }
00323
00324 KLFBackend::DefaultTemplateGenerator::DefaultTemplateGenerator()
00325 {
00326 }
00327 KLFBackend::DefaultTemplateGenerator::~DefaultTemplateGenerator()
00328 {
00329 }
00330
00331 QString KLFBackend::DefaultTemplateGenerator::generateTemplate(const klfInput& in,
00332 const klfSettings& )
00333 {
00334 QString latexin;
00335 QString s;
00336
00337 latexin = in.mathmode;
00338 latexin.replace("...", in.latex);
00339
00341 s += "\\documentclass{article}\n"
00342 "\\usepackage[dvips]{color}\n";
00343 s += in.preamble;
00344 s += "\n"
00345 "\\begin{document}\n"
00346 "\\thispagestyle{empty}\n";
00347 if (in.fontsize > 0) {
00348 s += QString("\\fontsize{%1}{%2}\\selectfont\n").arg(in.fontsize, 0, 'f', 2).arg(in.fontsize*1.2, 0, 'f', 2);
00349 }
00350 s += QString("\\definecolor{klffgcolor}{rgb}{%1,%2,%3}\n").arg(qRed(in.fg_color)/255.0)
00351 .arg(qGreen(in.fg_color)/255.0).arg(qBlue(in.fg_color)/255.0);
00352 s += QString("\\definecolor{klfbgcolor}{rgb}{%1,%2,%3}\n").arg(qRed(in.bg_color)/255.0)
00353 .arg(qGreen(in.bg_color)/255.0).arg(qBlue(in.bg_color)/255.0);
00354 if (qAlpha(in.bg_color)>0)
00355 s += "\\pagecolor{klfbgcolor}\n";
00356 s += "{\\color{klffgcolor} ";
00357 s += latexin;
00358 s += "%\n"
00359 "}\n"
00360 "\\end{document}\n";
00361
00362 return s;
00363 }
00364
00365
00366
00367
00368
00369
00370 KLFBackend::KLFBackend()
00371 {
00372 }
00373
00374
00375
00376
00377 #define D_RX "([0-9eE.-]+)"
00378
00379
00380 struct klfbbox {
00381 double x1, x2, y1, y2;
00382 };
00383
00384
00385
00386 static bool calculate_gs_eps_bbox(const QByteArray& epsdata, const QString& epsFile, klfbbox *bbox,
00387 KLFBackend::klfOutput * resError, const KLFBackend::klfSettings& settings,
00388 bool isMainThread);
00389 static bool read_eps_bbox(const QByteArray& epsdata, klfbbox *bbox, KLFBackend::klfOutput * resError);
00390 static void correct_eps_bbox(const QByteArray& epsdata,
00391 const klfbbox& bbox_corrected, const klfbbox& bbox_orig,
00392 double vectorscale, QRgb bgcolor, QByteArray * epsdatacorrected);
00393
00394 static void replace_svg_width_or_height(QByteArray *svgdata, const char * attr, double val);
00395
00396
00397 static inline bool has_userscript_output(const QSet<QString>& fmts, const QString& format)
00398 {
00399 return fmts.contains(format);
00400
00401
00402
00403 }
00404
00405
00406
00407 typedef QSet<QString> KLFStringSet;
00408
00409 KLF_EXPORT KLFStringSet klfbackend_fmts =
00410 KLFStringSet()
00411 << "latex" << "dvi" << "eps-raw" << "eps-bbox" << "eps-processed"
00412 << "png" << "pdf" << "svg-gs" << "svg" ;
00413
00414
00415 KLF_EXPORT KLFStringSet klfbackend_dependencies(const QString& fmt, bool recursive = false)
00416 {
00417 static KLFStringSet fn_lock = KLFStringSet();
00418
00419 if (fn_lock.contains(fmt)) {
00420 klfWarning("Dependency loop detected for format "<<fmt) ;
00421 return KLFStringSet();
00422 }
00423 fn_lock << fmt;
00424
00425 KLFStringSet s;
00426 if (fmt == QLatin1String("tex") || fmt == QLatin1String("latex")) {
00427
00428 } else if (fmt == QLatin1String("dvi")) {
00429 s << "latex";
00430 } else if (fmt == QLatin1String("eps-raw")) {
00431 s << "dvi";
00432 } else if (fmt == QLatin1String("eps-bbox")) {
00433 s << "eps-raw";
00434 } else if (fmt == QLatin1String("eps-processed")) {
00435 s << "eps-bbox";
00436 } else if (fmt == QLatin1String("png")) {
00437 s << "eps-processed";
00438 } else if (fmt == QLatin1String("pdf")) {
00439 s << "eps-processed";
00440 } else if (fmt == QLatin1String("svg-gs")) {
00441 s << "eps-processed";
00442 } else if (fmt == QLatin1String("svg")) {
00443 s << "svg-gs";
00444 } else {
00445 klfWarning("Unknown format : "<<fmt) ;
00446 }
00447 if (!recursive) {
00448 fn_lock.remove(fmt);
00449 return s;
00450 }
00451
00452 KLFStringSet basedeps = s;
00453 foreach (QString str, basedeps) {
00454 KLFStringSet subdeps = klfbackend_dependencies(str, true);
00455 foreach (QString subdep, subdeps) {
00456 s << subdep;
00457 }
00458 }
00459
00460 fn_lock.remove(fmt);
00461 return s;
00462 }
00463
00464 static inline bool assert_have_formats_for(const KLFStringSet& outputs, const KLFStringSet& skipfmts,
00465 const QString& forwhat)
00466 {
00467 KLFStringSet fmtlist = klfbackend_dependencies(forwhat);
00468 foreach (QString s, fmtlist) {
00469 if (skipfmts.contains(s) && !outputs.contains(s)) {
00470 klfWarning("User Script Skipped format "<<s<<" which is necessary for "<<forwhat) ;
00471 return false;
00472 }
00473 }
00474 return true;
00475 }
00476
00477 #define ASSERT_HAVE_FORMATS_FOR(forwhat) \
00478 { if (!assert_have_formats_for(us_outputs, us_skipfmts, forwhat)) { \
00479 res.status = KLFERR_USERSCRIPT_BADSKIPFORMATS; \
00480 res.errorstr = QObject::tr("User Script broke dependencies in skip-formats list", "KLFBackend"); \
00481 return res; \
00482 } \
00483 }
00484
00485
00486
00487
00488 KLFBackend::klfOutput KLFBackend::getLatexFormula(const klfInput& input, const klfSettings& usersettings,
00489 bool isMainThread)
00490 {
00491
00492 QMutexLocker mutexlocker(&klf_mutex);
00493
00494 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00495
00496 klfSettings settings;
00497 settings = usersettings;
00498
00499 klfInput in;
00500 in = input;
00501
00502 bool ok;
00503
00504 klfDbg("called. latex="<<in.latex);
00505
00506 {
00507 QStringList curenv = klfCurrentEnvironment();
00508 klfDbg("current environment is "<<curenv) ;
00509 settings.execenv = klfMergeEnvironment(curenv, settings.execenv,
00510 QStringList() << "PATH" << "TEXINPUTS" << "BIBINPUTS",
00511 KlfEnvPathPrepend|KlfEnvMergeExpandVars);
00512 }
00513
00514 klfDbg("execution environment for sub-processes is "<<settings.execenv) ;
00515
00516
00517 klfOutput res;
00518 res.status = KLFERR_NOERROR;
00519 res.errorstr = QString();
00520 res.result = QImage();
00521 res.pngdata_raw = QByteArray();
00522 res.pngdata = QByteArray();
00523 res.dvidata = QByteArray();
00524 res.epsdata_raw = QByteArray();
00525 res.epsdata = QByteArray();
00526 res.pdfdata = QByteArray();
00527 res.svgdata = QByteArray();
00528 res.input = in;
00529 res.settings = settings;
00530
00531
00532
00533 initGsInfo(&settings, isMainThread);
00534 if (!gsInfo.contains(settings.gsexec)) {
00535 res.status = KLFERR_NOGSVERSION;
00536 res.errorstr = QObject::tr("Can't query version of ghostscript located at `%1'.", "KLFBackend")
00537 .arg(settings.gsexec);
00538 return res;
00539 }
00540
00541 const GsInfo thisGsInfo = gsInfo.value(settings.gsexec);
00542
00543 klfDebugf(("%s: queried ghostscript version: %s", KLF_FUNC_NAME, qPrintable(thisGsInfo.version))) ;
00544
00545
00546
00547
00548 QRgb bgcolor_when_correcting_bbox = qRgba(0,0,0,0);
00549 klfDebugf(("%s: settings.calcEpsBoundingBox=%d, in.bg_color=[RGBA %d,%d,%d,%d]", KLF_FUNC_NAME,
00550 settings.calcEpsBoundingBox, qRed(in.bg_color), qGreen(in.bg_color), qBlue(in.bg_color),
00551 qAlpha(in.bg_color)));
00552
00553 if (settings.calcEpsBoundingBox &&
00554 qAlpha(in.bg_color) != 0 && (in.bg_color & qRgb(255,255,255)) != qRgb(255,255,255)) {
00555 bgcolor_when_correcting_bbox = in.bg_color;
00556 in.bg_color = qRgba(0,0,0,0);
00557 }
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 QString ver = KLF_VERSION_STRING;
00605 ver.replace(".", "x");
00606
00607
00608
00609 QString temptemplate = settings.tempdir + "/klftmp"+ver+"-XXXXXX";
00610
00611
00612 QTemporaryDir tempdir(temptemplate);
00613
00614 if (!tempdir.isValid()) {
00615
00616 res.errorstr = QObject::tr("Failed to create temporary directory inside `%1'",
00617 "KLFBackend").arg(settings.tempdir);
00618 res.status = KLFERR_TEMPDIR_FAIL;
00619 return res;
00620 }
00621
00622 QString tempfname = tempdir.path() + "/klftemp";
00623
00624 klfDbg("Temp location base name is "<<tempfname) ;
00625
00626 QString fnTex = tempfname + ".tex";
00627 QString fnDvi = tempfname + ".dvi";
00628 QString fnRawEps = tempfname + ".eps";
00629 QString fnBBoxEps = tempfname + "-bbox.eps";
00630 QString fnProcessedEps = tempfname + "-processed.eps";
00631 QString fnRawPng = tempfname + "-raw.png";
00632 QString fnPdfMarks = tempfname + ".pdfmarks";
00633 QString fnPdf = tempfname + ".pdf";
00634 QString fnGsSvg = tempfname + "-gs.svg";
00635
00636
00637 QString fnSvg = tempfname + ".svg";
00638
00639
00640 QByteArray rawepsdata;
00641 QByteArray bboxepsdata;
00642 QByteArray gssvgdata;
00643
00644
00645 QString latexsimplified = in.latex.trimmed();
00646 if (latexsimplified.isEmpty()) {
00647 res.errorstr = QObject::tr("You must specify a LaTeX formula!", "KLFBackend");
00648 res.status = KLFERR_MISSINGLATEXFORMULA;
00649 return res;
00650 }
00651
00652 if (!in.bypassTemplate) {
00653 if (in.mathmode.contains("...") == 0) {
00654 res.status = KLFERR_MISSINGMATHMODETHREEDOTS;
00655 res.errorstr = QObject::tr("The math mode string doesn't contain '...'!", "KLFBackend");
00656 return res;
00657 }
00658 }
00659
00660
00661 {
00662 QFile file(fnTex);
00663 bool r = file.open(QIODevice::WriteOnly);
00664 if ( ! r ) {
00665 res.status = KLFERR_TEXWRITEFAIL;
00666 res.errorstr = QObject::tr("Can't open file for writing: '%1'!", "KLFBackend").arg(fnTex);
00667 return res;
00668 }
00669 QTextStream stream(&file);
00670 if (!in.bypassTemplate) {
00671 TemplateGenerator *t = NULL;
00672 DefaultTemplateGenerator deft;
00673 if (settings.templateGenerator != NULL) {
00674 klfDbg("using custom template generator") ;
00675 t = settings.templateGenerator;
00676 KLF_ASSERT_NOT_NULL(t, "Template Generator is NULL! Using default!", t = &deft; ) ;
00677 } else {
00678 t = &deft;
00679 }
00680 stream << t->generateTemplate(in, settings);
00681 } else {
00682 stream << in.latex;
00683 }
00684 }
00685
00686 KLFStringSet us_outputs;
00687 KLFStringSet us_skipfmts;
00688 KLFStringSet our_skipfmts;
00689
00690 if (!in.userScript.isEmpty()) {
00691
00692
00693 KLFBackendEngineUserScriptInfo scriptinfo(in.userScript);
00694
00695 if (scriptinfo.scriptInfoError() != KLFERR_NOERROR) {
00696 res.status = scriptinfo.scriptInfoError();
00697 res.errorstr = scriptinfo.scriptInfoErrorString();
00698 return res;
00699 }
00700
00701 if ( (!scriptinfo.klfMinVersion().isEmpty()
00702 && klfVersionCompare(scriptinfo.klfMinVersion(), KLF_VERSION_STRING) > 0) ||
00703 (!scriptinfo.klfMaxVersion().isEmpty()
00704 && klfVersionCompare(scriptinfo.klfMaxVersion(), KLF_VERSION_STRING) < 0) ) {
00705 res.status = KLFERR_USERSCRIPT_BADKLFVERSION;
00706 res.errorstr = QObject::tr("User Script `%1' is not compatible with current version of KLatexFormula.",
00707 "KLFBackend").arg(scriptinfo.name());
00708 return res;
00709 }
00710
00711 if (scriptinfo.category() != QLatin1String("klf-backend-engine")) {
00712 res.status = KLFERR_USERSCRIPT_BADCATEGORY;
00713 res.errorstr = QObject::tr("User Script `%1' is not usable as backend latex engine!",
00714 "KLFBackend").arg(scriptinfo.name());
00715 return res;
00716 }
00717
00718
00719 QStringList addenv;
00720 addenv
00721
00722 << "KLF_TEMPDIR=" + settings.tempdir
00723 << "KLF_LATEX=" + settings.latexexec
00724 << "KLF_DVIPS=" + settings.dvipsexec
00725 << "KLF_GS=" + settings.gsexec
00726 << "KLF_GS_VERSION=" + thisGsInfo.version
00727 << "KLF_GS_DEVICES=" + QStringList(thisGsInfo.availdevices.toList()).join(",")
00728
00729 << klfInputToEnvironmentForUserScript(in)
00730
00731 << klfSettingsToEnvironmentForUserScript(settings)
00732
00733 << "KLF_TEMPFNAME=" + tempfname
00734 << "KLF_FN_TEX=" + fnTex
00735 << "KLF_FN_LATEX=" + fnTex
00736 << "KLF_FN_DVI=" + fnDvi
00737 << "KLF_FN_EPS_RAW=" + fnRawEps
00738 << "KLF_FN_EPS_BBOX=" + fnBBoxEps
00739 << "KLF_FN_EPS_PROCESSED=" + fnProcessedEps
00740 << "KLF_FN_PNG=" + fnRawPng
00741 << "KLF_FN_PDFMARKS=" + fnPdfMarks
00742 << "KLF_FN_PDF=" + fnPdf
00743 << "KLF_FN_SVG_GS=" + fnGsSvg
00744 << "KLF_FN_SVG=" + fnSvg
00745 ;
00746
00747 {
00748 KLFUserScriptFilterProcess p(scriptinfo.userScriptPath(), &settings);
00749
00750 p.addExecEnviron(addenv);
00751
00752 p.setProcessAppEvents(false);
00753
00754 QByteArray stderrdata;
00755 QByteArray stdoutdata;
00756 p.collectStderrTo(&stderrdata);
00757 p.collectStdoutTo(&stdoutdata);
00758
00759 p.addArgv(QDir::toNativeSeparators(fnTex));
00760
00761 QMap<QString,QByteArray*> outdata;
00762 QStringList outfmts = scriptinfo.spitsOut();
00763 foreach (QString fmt, outfmts) {
00764 us_outputs << fmt;
00765 if (fmt == QLatin1String("latex")) {
00766
00767
00768
00769 } else if (fmt == QLatin1String("dvi")) {
00770 outdata[fnDvi] = &res.dvidata;
00771 } else if (fmt == QLatin1String("eps-raw")) {
00772
00773 outdata[fnRawEps] = &rawepsdata;
00774 } else if (fmt == QLatin1String("eps-bbox")) {
00775 outdata[fnBBoxEps] = &bboxepsdata;
00776 } else if (fmt == QLatin1String("eps-processed")) {
00777 outdata[fnProcessedEps] = &res.epsdata;
00778 } else if (fmt == QLatin1String("png")) {
00779 if (settings.wantRaw) {
00780 outdata[fnRawPng] = &res.pngdata_raw;
00781 }
00782 } else if (fmt == QLatin1String("pdf")) {
00783 if (settings.wantPDF) {
00784 outdata[fnPdf] = &res.pdfdata;
00785 }
00786 } else if (fmt == QLatin1String("svg-gs")) {
00787
00788
00789 outdata[fnGsSvg] = & gssvgdata;
00790 } else if (fmt == QLatin1String("svg")) {
00791 if (settings.wantSVG) {
00792 outdata[fnSvg] = &res.svgdata;
00793 }
00794 } else {
00795 klfWarning("Can't handle output format from user script: "<<fmt) ;
00796 }
00797 }
00798 if (us_outputs.isEmpty()) {
00799 us_outputs << "dvi";
00800 }
00801 if (us_outputs.contains("eps-bbox") && !settings.wantRaw) {
00802
00803 if (outdata.contains("eps-raw"))
00804 outdata.remove(fnRawEps);
00805 }
00806 if (us_outputs.contains("eps-processed") && !settings.wantRaw) {
00807
00808 if (outdata.contains("eps-bbox"))
00809 outdata.remove(fnBBoxEps);
00810 }
00811
00812 QStringList skipfmts = scriptinfo.skipFormats();
00813 bool invert = false;
00814 int tempi;
00815 if ((tempi = skipfmts.indexOf("ALL_EXCEPT")) >= 0) {
00816 invert = true;
00817 skipfmts.removeAt(tempi);
00818 foreach (QString f, klfbackend_fmts) { us_skipfmts << f; }
00819 }
00820 foreach (QString fmt, skipfmts) {
00821 if (!klfbackend_fmts.contains(fmt)) {
00822 klfWarning("User Script Info: Unknown format to skip: "<<fmt) ;
00823 }
00824 if (!invert) {
00825 us_skipfmts << fmt;
00826 } else {
00827 us_skipfmts.remove(fmt);
00828 }
00829 }
00830 our_skipfmts = us_skipfmts;
00831 foreach (QString fmt, outfmts) {
00832 if (our_skipfmts.contains(fmt)) {
00833 klfWarning("User Script Info: format " << fmt << " provided by script is also marked "
00834 "as to be skipped!") ;
00835 }
00836 }
00837
00838 if ((us_outputs.contains("eps-processed") || our_skipfmts.contains("eps-processed")) && !settings.wantRaw) {
00839 our_skipfmts << "eps-bbox";
00840 }
00841 if ((us_outputs.contains("eps-bbox") || our_skipfmts.contains("eps-bbox")) && !settings.wantRaw) {
00842 our_skipfmts << "eps-raw";
00843 }
00844 if (us_outputs.contains("svg") || our_skipfmts.contains("svg")) {
00845 our_skipfmts << "svg-gs";
00846 }
00847
00848 klfDbg("us_skipfmts = " << us_skipfmts) ;
00849
00850 ok = p.run(outdata);
00851
00852 if (!ok) {
00853 res.errorstr = p.resultErrorString();
00854 switch (p.resultStatus()) {
00855 case KLFFP_NOSTART: res.status = KLFERR_USERSCRIPT_NORUN; break;
00856 case KLFFP_NOEXIT: res.status = KLFERR_USERSCRIPT_NONORMALEXIT; break;
00857 case KLFFP_NOSUCCESSEXIT: res.status = KLFERR_PROGERR_USERSCRIPT; break;
00858 case KLFFP_NODATA: res.status = KLFERR_USERSCRIPT_NOOUTPUT; break;
00859 case KLFFP_DATAREADFAIL: res.status = KLFERR_USERSCRIPT_OUTPUTREADFAIL; break;
00860 default:
00861 res.status = p.resultStatus();
00862 }
00863 return res;
00864 }
00865
00866
00867 foreach (QString fmt, outfmts) {
00868 QString corrfname;
00869 if (fmt == QLatin1String("latex")) {
00870 corrfname = fnTex;
00871 } else if (fmt == QLatin1String("dvi")) {
00872 corrfname = fnDvi;
00873 } else if (fmt == QLatin1String("eps-raw")) {
00874 corrfname = fnRawEps;
00875 } else if (fmt == QLatin1String("eps-bbox")) {
00876 corrfname = fnBBoxEps;
00877 } else if (fmt == QLatin1String("eps-processed")) {
00878 corrfname = fnProcessedEps;
00879 } else if (fmt == QLatin1String("png")) {
00880 corrfname = fnRawPng;
00881 } else if (fmt == QLatin1String("pdf")) {
00882 corrfname = fnPdf;
00883 } else if (fmt == QLatin1String("svg-gs")) {
00884 corrfname = fnGsSvg;
00885 } else if (fmt == QLatin1String("svg")) {
00886 corrfname = fnSvg;
00887 } else {
00888 klfWarning("Unknown format: " << fmt) ;
00889 continue;
00890 }
00891 if (!QFile::exists(corrfname)) {
00892 klfWarning("Promised format " << fmt << " did not appear after calling user script.") ;
00893 }
00894 }
00895 }
00896 }
00897
00898 klfDbg("our_skipfmts = " << our_skipfmts) ;
00899
00900
00901 if (!has_userscript_output(us_outputs, "dvi") && !our_skipfmts.contains("dvi")) {
00902
00903 klfDbg("preparing to launch latex.") ;
00904
00905 if (settings.latexexec.isEmpty()) {
00906 res.status = KLFERR_NOLATEXPROG;
00907 res.errorstr = QObject::tr("No latex executable given!\n", "KLFBackend");
00908 return res;
00909 }
00910
00911 KLFBackendFilterProgram p(QLatin1String("LaTeX"), &settings, isMainThread, tempdir.path());
00912 p.resErrCodes[KLFFP_NOSTART] = KLFERR_LATEX_NORUN;
00913 p.resErrCodes[KLFFP_NOEXIT] = KLFERR_LATEX_NONORMALEXIT;
00914 p.resErrCodes[KLFFP_NOSUCCESSEXIT] = KLFERR_PROGERR_LATEX;
00915 p.resErrCodes[KLFFP_NODATA] = KLFERR_LATEX_NOOUTPUT;
00916 p.resErrCodes[KLFFP_DATAREADFAIL] = KLFERR_LATEX_OUTPUTREADFAIL;
00917
00918 p.setArgv(QStringList() << settings.latexexec << QDir::toNativeSeparators(fnTex));
00919
00920 QByteArray userinputforerrors = "h\nr\n";
00921
00922 ok = p.run(userinputforerrors, fnDvi, &res.dvidata);
00923 if (!ok) {
00924 p.errorToOutput(&res);
00925 return res;
00926 }
00927 }
00928
00929 if (!has_userscript_output(us_outputs, "eps-raw") && !our_skipfmts.contains("eps-raw")) {
00930
00931 ASSERT_HAVE_FORMATS_FOR("eps-raw") ;
00932
00933 if (settings.dvipsexec.isEmpty()) {
00934 res.status = KLFERR_NODVIPSPROG;
00935 res.errorstr = QObject::tr("No dvips executable given!\n", "KLFBackend");
00936 return res;
00937 }
00938
00939
00940 KLFBackendFilterProgram p(QLatin1String("dvips"), &settings, isMainThread, tempdir.path());
00941 p.resErrCodes[KLFFP_NOSTART] = KLFERR_DVIPS_NORUN;
00942 p.resErrCodes[KLFFP_NOEXIT] = KLFERR_DVIPS_NONORMALEXIT;
00943 p.resErrCodes[KLFFP_NOSUCCESSEXIT] = KLFERR_PROGERR_DVIPS;
00944 p.resErrCodes[KLFFP_NODATA] = KLFERR_DVIPS_NOOUTPUT;
00945 p.resErrCodes[KLFFP_DATAREADFAIL] = KLFERR_DVIPS_OUTPUTREADFAIL;
00946
00947 QFileInfo dvipsinf(settings.dvipsexec);
00948 if (!dvipsinf.filePath().isEmpty()) {
00949
00950
00951 p.addExecEnviron(QStringList() << (
00952 QLatin1String("PATH=") + dvipsinf.absoluteFilePath() + QLatin1String(":") +
00953 QProcessEnvironment::systemEnvironment().value("PATH")
00954 )) ;
00955 }
00956
00957 p.setArgv(QStringList() << settings.dvipsexec << "-E" << QDir::toNativeSeparators(fnDvi)
00958 << "-o" << QDir::toNativeSeparators(fnRawEps));
00959
00960 ok = p.run(fnRawEps, &rawepsdata);
00961
00962 if (!ok) {
00963 p.errorToOutput(&res);
00964 return res;
00965 }
00966 klfDbg("read raw EPS; rawepsdata/length="<<rawepsdata.size()) ;
00967 }
00968
00969
00970 if (settings.wantRaw)
00971 res.epsdata_raw = rawepsdata;
00972
00973
00974
00975
00976
00977 if (!has_userscript_output(us_outputs, "eps-bbox") && !our_skipfmts.contains("eps-bbox")) {
00978
00979
00980
00981 ASSERT_HAVE_FORMATS_FOR("eps-bbox") ;
00982
00983 klfbbox bbox, bbox_corrected;
00984
00985 if (settings.calcEpsBoundingBox) {
00986 bool ok = calculate_gs_eps_bbox(QByteArray(), fnRawEps, &bbox, &res, settings, isMainThread);
00987 if (!ok)
00988 return res;
00989 } else {
00990 bool ok = read_eps_bbox(rawepsdata, &bbox, &res);
00991 if (!ok)
00992 return res;
00993 }
00994
00995 bbox.x1 -= settings.lborderoffset;
00996 bbox.y1 -= settings.bborderoffset;
00997 bbox.x2 += settings.rborderoffset;
00998 bbox.y2 += settings.tborderoffset;
00999
01000 res.width_pt = bbox.x2 - bbox.x1;
01001 res.height_pt = bbox.y2 - bbox.y1;
01002
01003
01004
01005 bbox_corrected.x1 = 0;
01006 bbox_corrected.y1 = 0;
01007 bbox_corrected.x2 = res.width_pt;
01008 bbox_corrected.y2 = res.height_pt;
01009
01010
01011
01012 correct_eps_bbox(rawepsdata, bbox_corrected, bbox, in.vectorscale,
01013 bgcolor_when_correcting_bbox, &bboxepsdata);
01014
01015 klfDbg("corrected bbox to "<<bbox.x1<<","<<bbox.y1<<","<<bbox.x2<<","<<bbox.y2);
01016 } else if (!our_skipfmts.contains("eps-bbox")) {
01017
01018
01019
01020 klfbbox bb;
01021
01022
01023 QString fn;
01024
01025 if (us_outputs.contains("eps-processed")) {
01026 fn = fnProcessedEps;
01027
01028 } else {
01029 fn = fnBBoxEps;
01030
01031 }
01032
01033 if (settings.calcEpsBoundingBox) {
01034 bool ok = calculate_gs_eps_bbox(QByteArray(), fn, &bb, &res, settings, isMainThread);
01035 if (!ok)
01036 return res;
01037 } else {
01038 bool ok = read_eps_bbox(bboxepsdata, &bb, &res);
01039 if (!ok)
01040 return res;
01041 }
01042
01043 res.width_pt = bb.x2 - bb.x1;
01044 res.height_pt = bb.y2 - bb.y1;
01045 }
01046
01047
01048 if (settings.wantRaw)
01049 res.epsdata_bbox = bboxepsdata;
01050
01051 if (!has_userscript_output(us_outputs, "eps-processed") && !our_skipfmts.contains("eps-processed")) {
01052
01053
01054 ASSERT_HAVE_FORMATS_FOR("eps-processed") ;
01055
01056 if (settings.outlineFonts) {
01057
01058
01059 if (settings.gsexec.isEmpty()) {
01060 res.status = KLFERR_NOGSPROG;
01061 res.errorstr = QObject::tr("No gs executable given!\n", "KLFBackend");
01062 return res;
01063 }
01064
01065 KLFBackendFilterProgram p(QLatin1String("gs (EPS Post-Processing Outline Fonts)"), &settings, isMainThread,
01066 tempdir.path());
01067 p.resErrCodes[KLFFP_NOSTART] = KLFERR_GSPOSTPROC_NORUN;
01068 p.resErrCodes[KLFFP_NOEXIT] = KLFERR_GSPOSTPROC_NONORMALEXIT;
01069 p.resErrCodes[KLFFP_NOSUCCESSEXIT] = KLFERR_PROGERR_GSPOSTPROC;
01070 p.resErrCodes[KLFFP_NODATA] = KLFERR_GSPOSTPROC_NOOUTPUT;
01071 p.resErrCodes[KLFFP_DATAREADFAIL] = KLFERR_GSPOSTPROC_OUTPUTREADFAIL;
01072
01073 QString psdevice;
01074 QStringList gsoptions;
01075 const char *env_gs_device = getenv("KLFBACKEND_GS_PS_DEVICE");
01076 if (env_gs_device != NULL) {
01077 psdevice = QString::fromLatin1(env_gs_device);
01078 gsoptions = QStringList() << "-dNOCACHE -dNoOutputFonts";
01079 } else if (thisGsInfo.version_maj < 9 ||
01080 (thisGsInfo.version_maj == 9 && thisGsInfo.version_min <= 7)) {
01081
01082 psdevice = QLatin1String("pswrite");
01083 gsoptions = QStringList() << "-dNOCACHE";
01084 } else if (thisGsInfo.version_maj > 9 ||
01085 (thisGsInfo.version_maj == 9 && thisGsInfo.version_min >= 15)) {
01086
01087
01088
01089
01090 psdevice = QLatin1String("ps2write");
01091 gsoptions = QStringList() << "-dNoOutputFonts";
01092 } else {
01093 res.status = KLFERR_GSPOSTPROC_NOOUTLINEFONTS;
01094 res.errorstr = QObject::tr("Installed Ghostscript version %1 may not be used to create font outlines."
01095 " Please upgrade to gs >= 9.15 (or downgrade to gs <= 9.07).",
01096 "KLFBackend").arg(thisGsInfo.version);
01097 return res;
01098 }
01099
01100 p.addArgv(settings.gsexec);
01101 p.addArgv(QStringList() << gsoptions
01102 << "-dNOPAUSE" << "-dSAFER" << "-dEPSCrop" << QString::fromLatin1("-sDEVICE=%1").arg(psdevice)
01103 << "-sOutputFile="+QDir::toNativeSeparators(fnProcessedEps)
01104 << "-q" << "-dBATCH" << "-");
01105
01106 ok = p.run(bboxepsdata, fnProcessedEps, &res.epsdata);
01107 if (!ok) {
01108 p.errorToOutput(&res);
01109 return res;
01110 }
01111
01112 klfDebugf(("%s: res.epsdata has length=%d", KLF_FUNC_NAME, res.epsdata.size())) ;
01113
01114 } else {
01115
01116 res.epsdata = bboxepsdata;
01117 }
01118 }
01119
01120 if (!has_userscript_output(us_outputs, "png") && !our_skipfmts.contains("png")) {
01121
01122 ASSERT_HAVE_FORMATS_FOR("png") ;
01123
01124 if (settings.gsexec.isEmpty()) {
01125 res.status = KLFERR_NOGSPROG;
01126 res.errorstr = QObject::tr("No gs executable given!\n", "KLFBackend");
01127 return res;
01128 }
01129
01130
01131 KLFBackendFilterProgram p(QLatin1String("gs (PNG)"), &settings, isMainThread, tempdir.path());
01132 p.resErrCodes[KLFFP_NOSTART] = KLFERR_GSPNG_NORUN;
01133 p.resErrCodes[KLFFP_NOEXIT] = KLFERR_GSPNG_NONORMALEXIT;
01134 p.resErrCodes[KLFFP_NOSUCCESSEXIT] = KLFERR_PROGERR_GSPNG;
01135 p.resErrCodes[KLFFP_NODATA] = KLFERR_GSPNG_NOOUTPUT;
01136 p.resErrCodes[KLFFP_DATAREADFAIL] = KLFERR_GSPNG_OUTPUTREADFAIL;
01137
01142
01143
01144 p.setArgv(QStringList() << settings.gsexec
01145 << "-dNOPAUSE" << "-dSAFER" << "-dTextAlphaBits=4" << "-dGraphicsAlphaBits=4"
01146 << "-r"+QString::number(in.dpi) << "-dEPSCrop" << "-dMaxBitmap=2147483647");
01147 if (qAlpha(in.bg_color) > 0) {
01148 p.addArgv("-sDEVICE=png16m");
01149 } else {
01150 p.addArgv("-sDEVICE=pngalpha");
01151 }
01152 p.addArgv(QStringList() << "-sOutputFile="+QDir::toNativeSeparators(fnRawPng) << "-q" << "-dBATCH" << "-");
01153
01154 ok = p.run(bboxepsdata, fnRawPng, &res.pngdata_raw);
01155 if (!ok) {
01156 p.errorToOutput(&res);
01157 return res;
01158 }
01159
01160 res.result.loadFromData(res.pngdata_raw, "PNG");
01161 }
01162 else {
01163 if (us_skipfmts.contains("png")) {
01164 klfWarning("PNG format was skipped by user script. The QImage object will be invalid.") ;
01165 res.result = QImage();
01166 res.pngdata = QByteArray();
01167 res.pngdata_raw = QByteArray();
01168 }
01169 if (!has_userscript_output(us_outputs, "png") || !QFile::exists(fnRawPng)) {
01170 klfWarning("PNG format is required to initialize the QImage object, but was not generated by user script.") ;
01171 res.result = QImage();
01172 } else {
01173
01174 res.result.load(fnRawPng);
01175 }
01176 }
01177
01178 if (!our_skipfmts.contains("png")) {
01179
01180
01181 KLFImageLatexMetaInfo metainfo(&res.result);
01182 metainfo.saveMetaInfo(in, settings);
01183
01184 {
01185 QBuffer buf(&res.pngdata);
01186 buf.open(QIODevice::WriteOnly);
01187
01188 bool r = res.result.save(&buf, "PNG");
01189 if (!r) {
01190 klfWarning("Can't save \"final\" PNG data.") ;
01191 res.pngdata = res.pngdata_raw;
01192 }
01193 }
01194
01195 klfDbg("prepared final PNG data.") ;
01196 }
01197
01198 if ( settings.wantPDF && !has_userscript_output(us_outputs, "pdf") && !our_skipfmts.contains("pdf") ) {
01199
01200 ASSERT_HAVE_FORMATS_FOR("pdf") ;
01201
01202
01203 { QFile fpdfmarks(fnPdfMarks);
01204 bool r = fpdfmarks.open(QIODevice::WriteOnly);
01205 if ( ! r ) {
01206 res.status = KLFERR_PDFMARKSWRITEFAIL;
01207 res.errorstr = QObject::tr("Can't open file for writing: '%1'!", "KLFBackend").arg(fnPdfMarks);
01208 return res;
01209 }
01210 QByteArray pdfmarkstr;
01211 KLFPdfmarksWriteLatexMetaInfo pdfmetainfo(&pdfmarkstr);
01212 pdfmetainfo.savePDFField("Title", in.latex);
01213 pdfmetainfo.savePDFField("Keywords", "KLatexFormula KLF LaTeX equation formula");
01214 pdfmetainfo.savePDFField("Creator", "KLatexFormula " KLF_VERSION_STRING);
01215 pdfmetainfo.saveMetaInfo(in, settings);
01216 pdfmetainfo.finish();
01217 fpdfmarks.write(pdfmarkstr);
01218
01219 }
01220
01221 if (settings.gsexec.isEmpty()) {
01222 res.status = KLFERR_NOGSPROG;
01223 res.errorstr = QObject::tr("No gs executable given!\n", "KLFBackend");
01224 return res;
01225 }
01226
01227
01228 KLFBackendFilterProgram p(QLatin1String("gs (PDF)"), &settings, isMainThread, tempdir.path());
01229 p.resErrCodes[KLFFP_NOSTART] = KLFERR_GSPDF_NORUN;
01230 p.resErrCodes[KLFFP_NOEXIT] = KLFERR_GSPDF_NONORMALEXIT;
01231 p.resErrCodes[KLFFP_NOSUCCESSEXIT] = KLFERR_PROGERR_GSPDF;
01232 p.resErrCodes[KLFFP_NODATA] = KLFERR_GSPDF_NOOUTPUT;
01233 p.resErrCodes[KLFFP_DATAREADFAIL] = KLFERR_GSPDF_OUTPUTREADFAIL;
01234
01235 p.setArgv(QStringList() << settings.gsexec
01236 << "-dNOPAUSE" << "-dSAFER" << "-sDEVICE=pdfwrite"
01237 << "-sOutputFile="+QDir::toNativeSeparators(fnPdf)
01238 << "-q" << "-dBATCH" << "-" << fnPdfMarks);
01239
01240
01241 ok = p.run(res.epsdata, fnPdf, &res.pdfdata);
01242 if (!ok) {
01243 p.errorToOutput(&res);
01244 return res;
01245 }
01246 }
01247
01248 if (settings.wantSVG) {
01249
01250 if (!has_userscript_output(us_outputs, "svg-gs") &&
01251 !our_skipfmts.contains("svg-gs")) {
01252
01253 ASSERT_HAVE_FORMATS_FOR("svg-gs") ;
01254
01255
01256 if (!thisGsInfo.availdevices.contains("svg")) {
01257
01258 klfWarning("ghostscript cannot create SVG");
01259 res.status = KLFERR_GSSVG_NOSVG;
01260 res.errorstr = QObject::tr("This ghostscript (%1) cannot generate SVG.", "KLFBackend").arg(settings.gsexec);
01261 return res;
01262 }
01263
01264 if (settings.gsexec.isEmpty()) {
01265 res.status = KLFERR_NOGSPROG;
01266 res.errorstr = QObject::tr("No gs executable given!\n", "KLFBackend");
01267 return res;
01268 }
01269
01270 KLFBackendFilterProgram p(QLatin1String("gs (SVG)"), &settings, isMainThread, tempdir.path());
01271 p.resErrCodes[KLFFP_NOSTART] = KLFERR_GSSVG_NORUN;
01272 p.resErrCodes[KLFFP_NOEXIT] = KLFERR_GSSVG_NONORMALEXIT;
01273 p.resErrCodes[KLFFP_NOSUCCESSEXIT] = KLFERR_PROGERR_GSSVG;
01274 p.resErrCodes[KLFFP_NODATA] = KLFERR_GSSVG_NOOUTPUT;
01275 p.resErrCodes[KLFFP_DATAREADFAIL] = KLFERR_GSSVG_OUTPUTREADFAIL;
01276
01277 p.addArgv(settings.gsexec);
01278
01279 p.addArgv(QStringList() << "-dNOCACHE" << "-dNOPAUSE" << "-dSAFER" << "-dEPSCrop" << "-sDEVICE=svg"
01280 << "-sOutputFile="+QDir::toNativeSeparators(fnGsSvg)
01281 << "-q" << "-dBATCH" << "-");
01282
01283
01284 ok = p.run(bboxepsdata, fnGsSvg, &gssvgdata);
01285 if (!ok) {
01286 p.errorToOutput(&res);
01287 return res;
01288 }
01289 }
01290
01291 if (!has_userscript_output(us_outputs, "svg") && !our_skipfmts.contains("svg")) {
01292
01293 ASSERT_HAVE_FORMATS_FOR("svg") ;
01294
01295
01296
01297
01298
01299 klfDebugf(("%s: gssvgdata/length=%d", KLF_FUNC_NAME, gssvgdata.size())) ;
01300
01301 replace_svg_width_or_height(&gssvgdata, "width=", res.width_pt);
01302 replace_svg_width_or_height(&gssvgdata, "height=", res.height_pt);
01303
01304 klfDebugf(("%s: now, gssvgdata/length=%d", KLF_FUNC_NAME, gssvgdata.size())) ;
01305
01306 res.svgdata = gssvgdata;
01307 }
01308 }
01309
01310 klfDbg("end of function.") ;
01311
01312 return res;
01313 }
01314
01315
01316
01317 static bool calculate_gs_eps_bbox(const QByteArray& epsData, const QString& epsFile, klfbbox *bbox,
01318 KLFBackend::klfOutput * resError, const KLFBackend::klfSettings& settings,
01319 bool isMainThread)
01320 {
01321 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01322
01323
01324 int i;
01325
01326 if (settings.gsexec.isEmpty()) {
01327 resError->status = KLFERR_NOGSPROG;
01328 resError->errorstr = QObject::tr("No gs executable given!\n", "KLFBackend");
01329 return false;
01330 }
01331
01332 KLFBackendFilterProgram p(QLatin1String("GhostScript (bbox)"), &settings, isMainThread, settings.tempdir);
01333 p.resErrCodes[KLFFP_NOSTART] = KLFERR_GSBBOX_NORUN;
01334 p.resErrCodes[KLFFP_NOEXIT] = KLFERR_GSBBOX_NONORMALEXIT;
01335 p.resErrCodes[KLFFP_NOSUCCESSEXIT] = KLFERR_PROGERR_GSBBOX;
01336 p.resErrCodes[KLFFP_NODATA] = KLFERR_GSBBOX_NOOUTPUT;
01337
01338
01339 p.setOutputStdout(true);
01340 p.setOutputStderr(true);
01341
01342 QByteArray bboxdata;
01343
01344 p.setArgv(QStringList() << settings.gsexec << "-dNOPAUSE" << "-dSAFER" << "-sDEVICE=bbox" << "-q" << "-dBATCH"
01345 << (epsFile.isEmpty() ? QString::fromLatin1("-") : epsFile));
01346
01347 bool ok = p.run(epsData , QString() , &bboxdata);
01348 if (!ok) {
01349 p.errorToOutput(resError);
01350 return false;
01351 }
01352
01353 klfDbg("gs provided output:\n"<<bboxdata);
01354
01355
01356 QRegExp rx_gsbbox("%%HiResBoundingBox\\s*:\\s+" D_RX "\\s+" D_RX "\\s+" D_RX "\\s+" D_RX "");
01357 i = rx_gsbbox.indexIn(QString::fromLatin1(bboxdata));
01358 if (i < 0) {
01359 resError->status = KLFERR_GSBBOX_NOBBOX;
01360 resError->errorstr = QObject::tr("Ghostscript did not provide parsable BBox output!", "KLFBackend");
01361 return false;
01362 }
01363 bbox->x1 = rx_gsbbox.cap(1).toDouble();
01364 bbox->y1 = rx_gsbbox.cap(2).toDouble();
01365 bbox->x2 = rx_gsbbox.cap(3).toDouble();
01366 bbox->y2 = rx_gsbbox.cap(4).toDouble();
01367
01368 return true;
01369 }
01370
01371
01372 static bool parse_bbox_values(const QString& str, klfbbox *bbox)
01373 {
01374
01375 QRegExp rx_bbvalues("" D_RX "\\s+" D_RX "\\s+" D_RX "\\s+" D_RX "");
01376 int i = rx_bbvalues.indexIn(str);
01377 if (i < 0) {
01378 return false;
01379 }
01380 bbox->x1 = rx_bbvalues.cap(1).toDouble();
01381 bbox->y1 = rx_bbvalues.cap(2).toDouble();
01382 bbox->x2 = rx_bbvalues.cap(3).toDouble();
01383 bbox->y2 = rx_bbvalues.cap(4).toDouble();
01384 return true;
01385 }
01386
01387 static bool s_starts_with(const char * x, int len_x, const char *test, int len_test)
01388 {
01389 if (len_x < len_test)
01390 return false;
01391 return !strncmp(x, test, len_test);
01392 }
01393
01394 static bool read_eps_bbox(const QByteArray& epsdata, klfbbox *bbox, KLFBackend::klfOutput * resError)
01395 {
01396 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01397
01398 static const char * hibboxtag = "%%HiResBoundingBox:";
01399 static const char * bboxtag = "%%BoundingBox:";
01400 static const int hibboxtaglen = strlen(hibboxtag);
01401 static const int bboxtaglen = strlen(bboxtag);
01402
01403
01404 QBuffer buf;
01405 buf.setData(epsdata);
01406 bool r = buf.open(QIODevice::ReadOnly | QIODevice::Text);
01407 if (!r) {
01408 klfWarning("What's going on!!?! can't open buffer for reading? Will Fail!!!") ;
01409 }
01410
01411 QString nobboxerrstr =
01412 QObject::tr("DVIPS did not provide parsable %%BoundingBox: in its output!", "KLFBackend");
01413
01414 char linebuffer[512];
01415 int n;
01416 bool gotepsbbox = false;
01417 int still_look_for_hiresbbox_lines = 5;
01418 while ((n = buf.readLine(linebuffer, sizeof(linebuffer)-1)) > 0) {
01419 if (gotepsbbox && still_look_for_hiresbbox_lines-- < 0) {
01420
01421
01422 klfDbg("stopped looking for hires-bbox.") ;
01423 break;
01424 }
01425 if (s_starts_with(linebuffer, n, hibboxtag, hibboxtaglen)) {
01426
01427 bool ok = parse_bbox_values(QString::fromLatin1(linebuffer+hibboxtaglen), bbox);
01428 if (!ok) {
01429 if (resError) {
01430 resError->status = KLFERR_DVIPS_OUTPUTNOBBOX;
01431 resError->errorstr = nobboxerrstr;
01432 }
01433 return false;
01434 }
01435 klfDbg("got hires-bbox.") ;
01436
01437 return true;
01438 }
01439 if (s_starts_with(linebuffer, n, bboxtag, bboxtaglen)) {
01440
01441 bool ok = parse_bbox_values(QString::fromLatin1(linebuffer+bboxtaglen), bbox);
01442 if (!ok) {
01443 continue;
01444 }
01445
01446 gotepsbbox = true;
01447 klfDbg("got normal bbox.") ;
01448 continue;
01449 }
01450 }
01451
01452
01453 if (gotepsbbox) {
01454
01455 return true;
01456 }
01457
01458 if (resError) {
01459 resError->status = KLFERR_DVIPS_OUTPUTNOBBOX;
01460 resError->errorstr = nobboxerrstr;
01461 }
01462 return false;
01463 }
01464
01470 static void correct_eps_bbox(const QByteArray& rawepsdata, const klfbbox& bbox_corrected,
01471 const klfbbox& bbox_orig, double vectorscale, QRgb bgcolor,
01472 QByteArray * epsdatacorrected)
01473 {
01474 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01475
01476 static const char * bboxdecl = "%%BoundingBox:";
01477 static int bboxdecl_len = strlen(bboxdecl);
01478
01479 double offx = bbox_corrected.x1 - bbox_orig.x1;
01480 double offy = bbox_corrected.y1 - bbox_orig.y1;
01481
01482
01483 int i, len;
01484 char nl[] = "\0\0\0";
01485 i = rawepsdata.indexOf(bboxdecl);
01486 if (i < 0) {
01487 i = 0;
01488 len = 0;
01489 } else {
01490 int j = i+bboxdecl_len;
01491 while (j < (int)rawepsdata.size() && rawepsdata[j] != '\r' && rawepsdata[j] != '\n')
01492 ++j;
01493 len = j-i;
01494 if (rawepsdata[j] == '\r' && j < (int)rawepsdata.size()-1 && rawepsdata[j+1] == '\n') {
01495 nl[0] = '\r', nl[1] = '\n';
01496 } else {
01497 nl[0] = rawepsdata[j];
01498 }
01499 }
01500
01501 double dwi = bbox_corrected.x2 * vectorscale;
01502 double dhi = bbox_corrected.y2 * vectorscale;
01503 int wi = (int)(dwi + 0.99999) ;
01504 int hi = (int)(dhi + 0.99999) ;
01505 char buffer[1024];
01506 int buffer_len;
01507
01508 snprintf(buffer, sizeof(buffer)-1,
01509 "%%%%BoundingBox: 0 0 %d %d%s"
01510 "%%%%HiResBoundingBox: 0 0 %s %s%s",
01511 wi, hi, nl,
01512 klfFmtDoubleCC(dwi, 'g', 6), klfFmtDoubleCC(dhi, 'g', 6), nl);
01513 buffer_len = strlen(buffer);
01514
01515 char backgroundfillps[1024] = "";
01516 if (qAlpha(bgcolor) > 0) {
01517 klfDbg("we have a bg color, so draw the background. bgcolor="<<klfFmt("%#10x", (uint)bgcolor));
01518 snprintf(backgroundfillps, sizeof(backgroundfillps)-1,
01519
01520 "newpath "
01521 "-2 -2 moveto "
01522 "%s -2 lineto "
01523 "%s %s lineto "
01524 "-2 %s lineto "
01525 "closepath "
01526 "gsave "
01527 "%s %s %s setrgbcolor "
01528 "fill "
01529 "grestore %s",
01530 klfFmtDoubleCC(dwi+1, 'g', 6),
01531 klfFmtDoubleCC(dwi+1, 'g', 6), klfFmtDoubleCC(dhi+1, 'g', 6),
01532 klfFmtDoubleCC(dhi+1, 'g', 6),
01533
01534 klfFmtDoubleCC(qRed(bgcolor)/255.0, 'f', 6),
01535 klfFmtDoubleCC(qGreen(bgcolor)/255.0, 'f', 6),
01536 klfFmtDoubleCC(qBlue(bgcolor)/255.0, 'f', 6),
01537 nl
01538 );
01539 }
01540
01541 char buffer2[1024];
01542
01543 snprintf(buffer2, sizeof(buffer2)-1,
01544 "%s"
01545 "%%%%Page 1 1%s"
01546 "%%%%PageBoundingBox 0 0 %d %d%s"
01547 "<< /PageSize [%d %d] >> setpagedevice%s"
01548 "%s"
01549 "%s %s scale%s"
01550 "%s %s translate%s"
01551 ,
01552 nl,
01553 nl,
01554 wi, hi, nl,
01555 wi, hi, nl,
01556 backgroundfillps,
01557 klfFmtDoubleCC(vectorscale, 'f'), klfFmtDoubleCC(vectorscale, 'f'), nl,
01558 klfFmtDoubleCC(offx, 'f'), klfFmtDoubleCC(offy, 'f'), nl);
01559
01560
01561
01562
01563
01564 klfDbg("buffer is `"<<buffer<<"', length="<<buffer_len) ;
01565 klfDbg("rawepsdata has length="<<rawepsdata.size()) ;
01566
01567
01568 QByteArray neweps;
01569 neweps = rawepsdata;
01570 neweps.replace(i, len, buffer);
01571
01572 const char * endsetupstr = "%%EndSetup";
01573 int i2 = neweps.indexOf(endsetupstr);
01574 if (i2 < 0)
01575 i2 = i + buffer_len;
01576 else
01577 i2 += strlen(endsetupstr);
01578
01579 neweps.replace(i2, 0, buffer2);
01580
01581 klfDbg("neweps has now length="<<neweps.size());
01582 klfDebugf(("New eps bbox is [0 0 %.6g %.6g] with translate [%.6g %.6g] and scale %.6g.",
01583 dwi, dhi, offx, offy, vectorscale));
01584
01585 *epsdatacorrected = neweps;
01586 }
01587
01588
01589 static void replace_svg_width_or_height(QByteArray *svgdata, const char * attreq, double val)
01590 {
01591 QByteArray & svgdataref = * svgdata;
01592
01593 int i = svgdataref.indexOf(attreq);
01594 int j = i;
01595 while (j < (int)svgdataref.size() && (!isspace(svgdataref[j]) && svgdataref[j] != '>'))
01596 ++j;
01597
01598 char buffer[1024];
01599 snprintf(buffer, sizeof(buffer)-1, "%s'%s'", attreq, klfFmtDoubleCC(val, 'f', 3));
01600
01601 svgdata->replace(i, j-i, buffer);
01602 }
01603
01604
01605
01606
01607
01608 KLF_EXPORT bool operator==(const KLFBackend::klfInput& a, const KLFBackend::klfInput& b)
01609 {
01610 return a.latex == b.latex &&
01611 a.mathmode == b.mathmode &&
01612 a.preamble == b.preamble &&
01613 fabs(a.fontsize - b.fontsize) < 0.001 &&
01614 a.fg_color == b.fg_color &&
01615 a.bg_color == b.bg_color &&
01616 a.dpi == b.dpi &&
01617 fabs(a.vectorscale - b.vectorscale) < 0.001 &&
01618 a.bypassTemplate == b.bypassTemplate &&
01619 a.userScript == b.userScript;
01620 }
01621
01622 KLF_EXPORT bool operator==(const KLFBackend::klfSettings& a, const KLFBackend::klfSettings& b)
01623 {
01624 return
01625 a.tempdir == b.tempdir &&
01626 a.latexexec == b.latexexec &&
01627 a.dvipsexec == b.dvipsexec &&
01628 a.gsexec == b.gsexec &&
01629 a.epstopdfexec == b.epstopdfexec &&
01630 a.tborderoffset == b.tborderoffset &&
01631 a.rborderoffset == b.rborderoffset &&
01632 a.bborderoffset == b.bborderoffset &&
01633 a.lborderoffset == b.lborderoffset &&
01634 a.calcEpsBoundingBox == b.calcEpsBoundingBox &&
01635 a.outlineFonts == b.outlineFonts &&
01636 a.wantRaw == b.wantRaw &&
01637 a.wantPDF == b.wantPDF &&
01638 a.wantSVG == b.wantSVG &&
01639 a.execenv == b.execenv &&
01640 a.templateGenerator == b.templateGenerator ;
01641 }
01642
01643
01644 QStringList KLFBackend::availableSaveFormats(const klfOutput * output)
01645 {
01646 if (output != NULL)
01647 return availableSaveFormats(*output);
01648
01649 QStringList fmts;
01650 fmts << "PNG" << "PS" << "EPS" << "DVI" << "PDF" << "SVG";
01651
01652 QList<QByteArray> imgfmts = QImageWriter::supportedImageFormats();
01653 foreach (QByteArray f, imgfmts) {
01654 f = f.trimmed().toUpper();
01655 if (f == "JPG")
01656 f = "JPEG";
01657 if (fmts.contains(f))
01658 continue;
01659 fmts << QString::fromLatin1(f);
01660 }
01661 return fmts;
01662 }
01663
01664 QStringList KLFBackend::availableSaveFormats(const klfOutput& klfoutput)
01665 {
01666 QStringList formats;
01667
01668 if (!klfoutput.pdfdata.isEmpty())
01669 formats << "PDF";
01670 if (!klfoutput.pngdata.isEmpty())
01671 formats << "PNG";
01672 if (!klfoutput.svgdata.isEmpty())
01673 formats << "SVG";
01674 if (!klfoutput.epsdata.isEmpty())
01675 formats << "PS" << "EPS";
01676 if (!klfoutput.dvidata.isEmpty())
01677 formats << "DVI";
01678
01679 QList<QByteArray> imgfmts = QImageWriter::supportedImageFormats();
01680 foreach (QByteArray f, imgfmts) {
01681 f = f.trimmed().toUpper();
01682 if (f == "JPG")
01683 f = "JPEG";
01684 if (formats.contains(f))
01685 continue;
01686 formats << QString::fromLatin1(f);
01687 }
01688 return formats;
01689 }
01690
01691 bool KLFBackend::saveOutputToDevice(const klfOutput& klfoutput, QIODevice *device,
01692 const QString& fmt, QString *errorStringPtr)
01693 {
01694 QString format = fmt.trimmed().toUpper();
01695
01696
01697 if (format == "PNG") {
01698 device->write(klfoutput.pngdata);
01699 } else if (format == "EPS" || format == "PS") {
01700 device->write(klfoutput.epsdata);
01701 } else if (format == "DVI") {
01702 device->write(klfoutput.dvidata);
01703 } else if (format == "PDF") {
01704 if (klfoutput.pdfdata.isEmpty()) {
01705 QString error = QObject::tr("PDF format is not available!",
01706 "KLFBackend::saveOutputToFile");
01707 qWarning("%s", qPrintable(error));
01708 if (errorStringPtr != NULL)
01709 errorStringPtr->operator=(error);
01710 return false;
01711 }
01712 device->write(klfoutput.pdfdata);
01713 } else if (format == "SVG") {
01714 if (klfoutput.svgdata.isEmpty()) {
01715 QString error = QObject::tr("SVG format is not available!",
01716 "KLFBackend::saveOutputToFile");
01717 qWarning("%s", qPrintable(error));
01718 if (errorStringPtr != NULL)
01719 errorStringPtr->operator=(error);
01720 return false;
01721 }
01722 device->write(klfoutput.svgdata);
01723 } else {
01724 bool res = klfoutput.result.save(device, format.toLatin1());
01725 if ( ! res ) {
01726 QString errstr = QObject::tr("Unable to save image in format `%1'!",
01727 "KLFBackend::saveOutputToDevice").arg(format);
01728 qWarning("%s", qPrintable(errstr));
01729 if (errorStringPtr != NULL)
01730 *errorStringPtr = errstr;
01731 return false;
01732 }
01733 }
01734
01735 return true;
01736 }
01737
01738 bool KLFBackend::saveOutputToFile(const klfOutput& klfoutput, const QString& fileName,
01739 const QString& fmt, QString *errorStringPtr)
01740 {
01741 QString format = fmt;
01742
01743 if (format.isEmpty() && !fileName.isEmpty()) {
01744 QFileInfo fi(fileName);
01745 if ( ! fi.suffix().isEmpty() )
01746 format = fi.suffix();
01747 }
01748 if (format.isEmpty())
01749 format = QLatin1String("PNG");
01750 format = format.trimmed().toUpper();
01751
01752 QFile fout;
01753 if (fileName.isEmpty() || fileName == "-") {
01754 if ( ! fout.open(stdout, QIODevice::WriteOnly) ) {
01755 QString error = QObject::tr("Unable to open stdout for write! Error: %1",
01756 "KLFBackend::saveOutputToFile").arg(fout.error());
01757 qWarning("%s", qPrintable(error));
01758 if (errorStringPtr != NULL)
01759 *errorStringPtr = error;
01760 return false;
01761 }
01762 } else {
01763 fout.setFileName(fileName);
01764 if ( ! fout.open(QIODevice::WriteOnly) ) {
01765 QString error = QObject::tr("Unable to write to file `%1'! Error: %2",
01766 "KLFBackend::saveOutputToFile")
01767 .arg(fileName).arg(fout.error());
01768 qWarning("%s", qPrintable(error));
01769 if (errorStringPtr != NULL)
01770 *errorStringPtr = error;
01771 return false;
01772 }
01773 }
01774
01775 return saveOutputToDevice(klfoutput, &fout, format, errorStringPtr);
01776 }
01777
01778
01779 bool KLFBackend::detectSettings(klfSettings *settings, const QString& extraPath, bool isMainThread)
01780 {
01781 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01782
01783 QStringList stdextrapaths;
01784 int k, j;
01785 for (k = 0; standard_extra_paths[k] != NULL; ++k) {
01786 stdextrapaths.append(standard_extra_paths[k]);
01787 }
01788 QString extra_paths = stdextrapaths.join(QString("")+KLF_PATH_SEP);
01789 if (!extraPath.isEmpty())
01790 extra_paths += KLF_PATH_SEP + extraPath;
01791
01792
01793 settings->tempdir = QDir::fromNativeSeparators(QDir::tempPath());
01794
01795
01796 settings->lborderoffset = 1;
01797 settings->tborderoffset = 1;
01798 settings->rborderoffset = 1;
01799 settings->bborderoffset = 1;
01800
01801 settings->epstopdfexec = QString();
01802
01803
01804 settings->wantPDF = true;
01805
01806 settings->wantSVG = false;
01807
01808
01809 struct { QString * target_setting; QStringList prog_names; } progs_to_find[] = {
01810 { & settings->latexexec, progLATEX },
01811 { & settings->dvipsexec, progDVIPS },
01812 { & settings->gsexec, progGS },
01813
01814 { NULL, QStringList() }
01815 };
01816
01817 klfDbg(klfFmtCC("Our base extra paths are: %s", qPrintable(extra_paths))) ;
01818 QString ourextrapaths = extra_paths;
01819 ourextrapaths.replace("@executable_path", qApp->applicationDirPath());
01820 klfDbg(klfFmtCC("Our extra paths are: %s", qPrintable(ourextrapaths))) ;
01821
01822 for (k = 0; progs_to_find[k].target_setting != NULL; ++k) {
01823 klfDbg("Looking for "+progs_to_find[k].prog_names.join(" or ")) ;
01824 for (j = 0; j < (int)progs_to_find[k].prog_names.size(); ++j) {
01825 klfDbg("Testing `"+progs_to_find[k].prog_names[j]+"'") ;
01826 *progs_to_find[k].target_setting
01827 = klfSearchPath(progs_to_find[k].prog_names[j], ourextrapaths);
01828 if (!progs_to_find[k].target_setting->isEmpty()) {
01829 klfDbg("Found! at `"+ *progs_to_find[k].target_setting+"'") ;
01830 break;
01831 }
01832 }
01833 }
01834
01835 bool r1 = detectOptionSettings(settings, isMainThread);
01836
01837 bool result_failure =
01838 settings->tempdir.isEmpty() || settings->latexexec.isEmpty() || settings->dvipsexec.isEmpty() ||
01839 settings->gsexec.isEmpty() || !r1;
01840
01841 return !result_failure;
01842 }
01843
01844 KLF_EXPORT bool KLFBackend::detectOptionSettings(klfSettings * settings, bool isMainThread)
01845 {
01846 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01847
01848 bool r0 = klf_detect_execenv(settings);
01849 if (!r0) {
01850 return false;
01851 }
01852
01853 settings->wantSVG = false;
01854
01855 bool ok = true;
01856 if (settings->gsexec.length()) {
01857 initGsInfo(settings, isMainThread);
01858 if (!gsInfo.contains(settings->gsexec)) {
01859 klfWarning("Cannot get 'gs' devices information with "<<(settings->gsexec+" --version/--help"));
01860 ok = false;
01861 } else if (gsInfo[settings->gsexec].availdevices.contains("svg")) {
01862 settings->wantSVG = true;
01863 }
01864 }
01865
01866 return ok;
01867 }
01868
01869
01870 KLF_EXPORT bool klf_detect_execenv(KLFBackend::klfSettings *settings)
01871 {
01872 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01873
01874
01875 QFileInfo gsfi(settings->gsexec);
01876 if (gsfi.fileName() == "mgs.exe") {
01877 QString mgsenv = QString("")
01878 + QDir::toNativeSeparators(gsfi.absolutePath()+"/../../ghostscript/base")
01879 + QString(KLF_PATH_SEP)
01880 + QDir::toNativeSeparators(gsfi.absolutePath()+"/../../fonts");
01881 settings->execenv = klfSetEnvironmentVariable(settings->execenv, "MIKTEX_GS_LIB", mgsenv);
01882 klfDbg("Adjusting environment for mgs.exe: `MIKTEX_GS_LIB="+mgsenv+"'") ;
01883 }
01884
01885 return true;
01886 }
01887
01888
01889
01890
01891
01892 void initGsInfo(const KLFBackend::klfSettings *settings, bool isMainThread)
01893 {
01894 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01895
01896 if (gsInfo.contains(settings->gsexec))
01897 return;
01898
01899 if (settings->gsexec.isEmpty()) {
01900
01901 return;
01902 }
01903
01904 QString gsver;
01905 {
01906 KLFBackendFilterProgram p(QLatin1String("gs (test version)"), settings, isMainThread, settings->tempdir);
01907
01908
01909
01910
01911
01912
01913 p.setExecEnviron(settings->execenv);
01914
01915
01916 p.setProcessAppEvents(false);
01917
01918 p.setArgv(QStringList() << settings->gsexec << "--version");
01919
01920 QByteArray ba_gsver;
01921 bool ok = p.run(QString(), &ba_gsver);
01922 if (ok) {
01923 gsver = QString::fromLatin1(ba_gsver);
01924 klfDbg("gs version text (untrimmed): "<<gsver) ;
01925
01926 gsver = gsver.trimmed();
01927 }
01928 }
01929
01930 QString gshelp;
01931 KLFStringSet availdevices;
01932 {
01933 KLFBackendFilterProgram p(QLatin1String("gs (query help)"), settings, isMainThread, settings->tempdir);
01934
01935
01936
01937
01938
01939
01940 QStringList ee = settings->execenv;
01941
01942 ee = klfSetEnvironmentVariable(ee, QLatin1String("LANG"), QLatin1String("en_US.UTF-8"));
01943 p.setExecEnviron(ee);
01944
01945
01946 p.setProcessAppEvents(false);
01947
01948 p.setArgv(QStringList() << settings->gsexec << "--help");
01949
01950 QByteArray ba_gshelp;
01951 bool ok = p.run(QString(), &ba_gshelp);
01952 if (ok) {
01953 gshelp = QString::fromLatin1(ba_gshelp);
01954
01955 klfDbg("gs help text: "<<gshelp) ;
01956
01957 const char * availdevstr = "Available devices:";
01958 int k = gshelp.indexOf(availdevstr, 0, Qt::CaseInsensitive) ;
01959 if (k == -1) {
01960 klfWarning("Unable to parse gs' available devices.") ;
01961 } else {
01962 k += strlen(availdevstr);
01963
01964 int kend = gshelp.indexOf(QRegExp("\\n\\S"), k);
01965 if (kend == -1)
01966 kend = gshelp.length();
01967
01968 QStringList devlist = gshelp.mid(k, kend-k).split(QRegExp("(\\s|[\r\n])+"), QString::SkipEmptyParts);
01969 availdevices = KLFStringSet::fromList(devlist);
01970 klfDbg("Detected devices: "<<availdevices) ;
01971 }
01972 }
01973 }
01974
01975 int gsvermaj = -1;
01976 int gsvermin = -1;
01977 QRegExp rx_version("^(\\d+)\\.(\\d+)");
01978 int foundver = rx_version.indexIn(gsver);
01979 if (foundver >= 0) {
01980 gsvermaj = rx_version.cap(1).toInt();
01981 gsvermin = rx_version.cap(2).toInt();
01982 }
01983
01984 klfDbg("GS Version: "<<gsver<<" = "<<gsvermaj<<"."<<gsvermin);
01985
01986 GsInfo i;
01987 i.version = gsver;
01988 i.version_maj = gsvermaj;
01989 i.version_min = gsvermin;
01990 i.help = gshelp;
01991 i.availdevices = availdevices;
01992
01993 gsInfo[settings->gsexec] = i;
01994 }
01995
01996
01997
01998
01999
02000 KLF_EXPORT QStringList klfSettingsToEnvironmentForUserScript(const KLFBackend::klfSettings& settings)
02001 {
02002 QStringList env;
02003 env << "KLF_SETTINGS_BORDEROFFSET=" + klfFmt("%.3g,%.3g,%.3g,%.3g pt", settings.tborderoffset,
02004 settings.rborderoffset, settings.bborderoffset, settings.lborderoffset)
02005 << "KLF_SETTINGS_OUTLINEFONTS=" + QString::fromLatin1(settings.outlineFonts ? "1" : "0")
02006 << "KLF_SETTINGS_CALCEPSBOUNDINGBOX=" + QString::fromLatin1(settings.calcEpsBoundingBox ? "1" : "0")
02007 << "KLF_SETTINGS_WANT_RAW=" + QString::fromLatin1(settings.wantRaw ? "1" : "0")
02008 << "KLF_SETTINGS_WANT_PDF=" + QString::fromLatin1(settings.wantPDF ? "1" : "0")
02009 << "KLF_SETTINGS_WANT_SVG=" + QString::fromLatin1(settings.wantSVG ? "1" : "0");
02010 return env;
02011 }
02012
02013 KLF_EXPORT QStringList klfInputToEnvironmentForUserScript(const KLFBackend::klfInput& in)
02014 {
02015 QStringList env;
02016 QString fgcol = QString("rgba(%1,%2,%3,%4)").arg(qRed(in.fg_color))
02017 .arg(qGreen(in.fg_color)).arg(qBlue(in.fg_color)).arg(qAlpha(in.fg_color));
02018 QString bgcol = QString("rgba(%1,%2,%3,%4)").arg(qRed(in.bg_color))
02019 .arg(qGreen(in.bg_color)).arg(qBlue(in.bg_color)).arg(qAlpha(in.bg_color));
02020 env << "KLF_INPUT_LATEX=" + in.latex
02021 << "KLF_INPUT_MATHMODE=" + in.mathmode
02022 << "KLF_INPUT_PREAMBLE=" + in.preamble
02023 << "KLF_INPUT_FONTSIZE=" + QString::number(in.fontsize)
02024 << "KLF_INPUT_FG_COLOR_WEB=" + QColor(in.fg_color).name()
02025 << "KLF_INPUT_FG_COLOR_RGBA=" + fgcol
02026 << "KLF_INPUT_BG_COLOR_TRANSPARENT=" + QString::fromLatin1(qAlpha(in.bg_color) > 50 ? "0" : "1")
02027 << "KLF_INPUT_BG_COLOR_WEB=" + QColor(in.bg_color).name()
02028 << "KLF_INPUT_BG_COLOR_RGBA=" + bgcol
02029 << "KLF_INPUT_DPI=" + QString::number(in.dpi)
02030 << "KLF_INPUT_VECTORSCALE=" + klfFmt("%.6g", in.vectorscale)
02031 << "KLF_INPUT_USERSCRIPT=" + in.userScript
02032 << "KLF_INPUT_BYPASS_TEMPLATE=" + QString::number(in.bypassTemplate)
02033 ;
02034
02035
02036 QMap<QString,QString>::const_iterator cit;
02037 for (cit = in.userScriptParam.constBegin(); cit != in.userScriptParam.constEnd(); ++cit) {
02038 env << "KLF_ARG_"+cit.key() + "=" + cit.value();
02039 }
02040
02041 return env;
02042 }