28 #include <qapplication.h>
31 #include <qdatetime.h>
32 #include <qtextstream.h>
41 #include "klfqt34common.h"
76 #ifdef KLF_EXTRA_SEARCH_PATHS
77 # define EXTRA_PATHS_PRE KLF_EXTRA_SEARCH_PATHS ,
78 # define EXTRA_PATHS KLF_EXTRA_SEARCH_PATHS
80 # define EXTRA_PATHS_PRE
85 #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64)
90 static const char * standard_extra_paths[] = {
92 "C:\\Program Files\\MiKTeX*\\miktex\\bin",
93 "C:\\Program Files\\gs\\gs*\\bin",
96 #elif defined(Q_WS_MAC)
101 static const char * standard_extra_paths[] = {
103 "/usr/texbin:/usr/local/bin:/sw/bin:/sw/usr/bin",
111 static const char * standard_extra_paths[] = {
121 KLFBackend::KLFBackend()
129 QString stdouthtml = stdoutstr;
130 QString stderrhtml = stderrstr;
131 stdouthtml.
replace(
"&",
"&");
132 stdouthtml.
replace(
"<",
"<");
133 stdouthtml.
replace(
">",
">");
134 stderrhtml.
replace(
"&",
"&");
135 stderrhtml.
replace(
"<",
"<");
136 stderrhtml.
replace(
">",
">");
139 return QObject::tr(
"<p><b>%1</b> reported an error (exit status %2). No Output was generated.</p>",
141 .arg(progname).arg(exitstatus);
144 QObject::tr(
"<p><b>%1</b> reported an error (exit status %2). Here is full stdout output:</p>\n"
145 "<pre>\n%3</pre>",
"KLFBackend")
146 .arg(progname).arg(exitstatus).arg(stdouthtml);
149 QObject::tr(
"<p><b>%1</b> reported an error (exit status %2). Here is full stderr output:</p>\n"
150 "<pre>\n%3</pre>",
"KLFBackend")
151 .arg(progname).arg(exitstatus).arg(stderrhtml);
153 return QObject::tr(
"<p><b>%1</b> reported an error (exit status %2). Here is full stderr output:</p>\n"
154 "<pre>\n%3</pre><p>And here is full stdout output:</p><pre>\n%4</pre>",
"KLFBackend")
155 .arg(progname).arg(exitstatus).arg(stderrhtml).arg(stdouthtml);
161 struct cleanup_caller {
163 cleanup_caller(
QString fn) : tempfname(fn) { }
165 KLFBackend::cleanup(tempfname);
172 QRegExp rx(
"\\$(?:(\\$|(?:[A-Za-z0-9_]+))|\\{([A-Za-z0-9_]+)\\})");
174 while ( (i = rx.rx_indexin_i(s, i)) != -1 ) {
176 QString envvarname = rx.cap(1);
183 const char *svalue = getenv(qPrintable(envvarname));
185 s.
replace(i, rx.matchedLength(), qsvalue);
196 for (k = 0; k < (int)list->size(); ++k) {
197 if (list->operator[](k).startsWith(var+
QString(
"="))) {
198 list->operator[](k) = line;
215 qDebug(
"%s: %s: KLFBackend::getLatexFormula() called. latex=%s",
KLF_FUNC_NAME, KLF_SHORT_TIME,
216 qPrintable(in.
latex));
220 for (k = 0; k < (int)settings.
execenv.size(); ++k) {
223 qWarning(
"%s: badly formed environment definition in `environ': %s",
KLF_FUNC_NAME,
224 qPrintable(settings.
execenv[k]));
229 __klf_append_replace_env_var(&execenv, varname, newenvdef);
232 klfDbg(
"execution environment for sub-processes:\n"+execenv.
join(
"\n")) ;
243 res.settings = settings;
256 QString tempfname = settings.
tempdir +
"/klatexformulatmp" KLF_VERSION_STRING
"-"
259 QString fnTex = tempfname +
".tex";
260 QString fnDvi = tempfname +
".dvi";
261 QString fnRawEps = tempfname +
"-raw.eps";
262 QString fnBBCorrEps = tempfname +
"-bbcorr.eps";
263 QString fnOutlFontsEps = tempfname +
"-outlfonts.eps";
265 QString fnPng = tempfname +
".png";
266 QString fnPdf = tempfname +
".pdf";
270 cleanup_caller cleanupcallerinstance(tempfname);
272 #ifdef KLFBACKEND_QT4
277 if (latexsimplified.
isEmpty()) {
278 res.errorstr =
QObject::tr(
"You must specify a LaTeX formula!",
"KLFBackend");
287 res.errorstr =
QObject::tr(
"The math mode string doesn't contain '...'!",
"KLFBackend");
296 bool r = file.
open(dev_WRITEONLY);
299 res.errorstr =
QObject::tr(
"Can't open file for writing: '%1'!",
"KLFBackend")
305 stream <<
"\\documentclass{article}\n"
306 <<
"\\usepackage[dvips]{color}\n"
308 <<
"\\begin{document}\n"
309 <<
"\\thispagestyle{empty}\n"
314 << ( (qAlpha(in.
bg_color)>0) ?
"\\pagecolor{klfbgcolor}\n" :
"" )
315 <<
"{\\color{klffgcolor} " << latexin <<
" }\n"
316 <<
"\\end{document}\n";
329 args << settings.
latexexec << dir_native_separators(fnTex);
331 qDebug(
"%s: %s: about to exec latex...",
KLF_FUNC_NAME, KLF_SHORT_TIME) ;
333 qDebug(
"%s: %s: latex returned.",
KLF_FUNC_NAME, KLF_SHORT_TIME) ;
337 res.errorstr =
QObject::tr(
"Unable to start Latex program %1!",
"KLFBackend")
343 res.errorstr =
QObject::tr(
"Latex was killed!",
"KLFBackend");
355 res.errorstr =
QObject::tr(
"DVI file didn't appear after having called Latex!",
"KLFBackend");
365 args << settings.
dvipsexec <<
"-E" << dir_native_separators(fnDvi)
366 <<
"-o" << dir_native_separators(fnRawEps);
368 qDebug(
"%s: %s: about to dvips... %s",
KLF_FUNC_NAME, KLF_SHORT_TIME, qPrintable(args.
join(
" "))) ;
370 qDebug(
"%s: %s: dvips returned.",
KLF_FUNC_NAME, KLF_SHORT_TIME) ;
374 res.errorstr =
QObject::tr(
"Unable to start dvips!\n",
"KLFBackend");
379 res.errorstr =
QObject::tr(
"Dvips was mercilessly killed!\n",
"KLFBackend");
390 res.errorstr =
QObject::tr(
"EPS file didn't appear after dvips call!\n",
"KLFBackend");
396 QFile epsfile(fnRawEps);
397 r = epsfile.
open(dev_READONLY);
400 res.errorstr =
QObject::tr(
"Can't read file '%1'!\n",
"KLFBackend").arg(fnRawEps);
406 #ifdef KLFBACKEND_QT4
408 int i = epscontent_s.
indexOf(
"%%BoundingBox: ");
410 QCString epscontent_s(epscontent.
data(), epscontent.
size());
411 int i = epscontent_s.
find(
"%%BoundingBox: ");
416 res.errorstr =
QObject::tr(
"File '%1' does not contain line \"%%BoundingBox: ... \" !",
417 "KLFBackend").arg(fnRawEps);
423 i += strlen(
"%%BoundingBox:");
424 int n = sscanf(epscontent_s.
data()+i,
"%d %d %d %d", &ax, &ay, &bx, &by);
427 res.errorstr =
QObject::tr(
"file %1: Line %%BoundingBox: can't read values!\n",
"KLFBackend")
433 sprintf(temp,
"%%%%BoundingBox: %d %d %d %d",
439 QRegExp rx(
"^%%BoundingBox: [0-9]+ [0-9]+ [0-9]+ [0-9]+");
440 rx.rx_indexin(chunk);
441 int l = rx.matchedLength();
442 epscontent_s.
replace(k, l, temp);
445 QFile epsgoodfile(fnBBCorrEps);
446 r = epsgoodfile.
open(dev_WRITEONLY);
449 res.errorstr =
QObject::tr(
"Can't write to file '%1'!\n",
"KLFBackend")
453 epsgoodfile.dev_write(epscontent_s);
456 res.epsdata.ba_assign(epscontent_s);
460 qDebug(
"%s: %s: eps bbox set.",
KLF_FUNC_NAME, KLF_SHORT_TIME) ;
468 args << settings.
gsexec <<
"-dNOCACHE" <<
"-dNOPAUSE" <<
"-dSAFER" <<
"-dEPSCrop"
469 <<
"-sDEVICE=pswrite" <<
"-sOutputFile="+dir_native_separators(fnOutlFontsEps)
470 <<
"-q" <<
"-dBATCH" << dir_native_separators(fnBBCorrEps);
472 qDebug(
"%s: %s: about to gs (for outline fonts)...\n%s",
KLF_FUNC_NAME, KLF_SHORT_TIME,
473 qPrintable(args.
join(
" ")));
475 qDebug(
"%s: %s: gs returned (for outline fonts).",
KLF_FUNC_NAME, KLF_SHORT_TIME) ;
479 res.errorstr =
QObject::tr(
"Unable to start gs!\n",
"KLFBackend");
484 res.errorstr =
QObject::tr(
"gs died abnormally!\n",
"KLFBackend");
495 res.errorstr =
QObject::tr(
"EPS file (with outlined fonts) didn't appear after call to gs!\n",
501 QFile ofepsfile(fnOutlFontsEps);
502 r = ofepsfile.
open(dev_READONLY);
505 res.errorstr =
QObject::tr(
"Unable to read file %1!\n",
"KLFBackend")
506 .arg(fnOutlFontsEps);
509 res.epsdata = ofepsfile.readAll();
517 args << settings.
gsexec <<
"-dNOPAUSE" <<
"-dSAFER" <<
"-dEPSCrop"
519 <<
"-dGraphicsAlphaBits=4";
521 args <<
"-sDEVICE=png16m";
523 args <<
"-sDEVICE=pngalpha";
525 args <<
"-sOutputFile="+dir_native_separators(fnPng) <<
"-q" <<
"-dBATCH"
526 << dir_native_separators(fnFinalEps);
528 qDebug(
"%s: %s: about to gs... %s",
KLF_FUNC_NAME, KLF_SHORT_TIME, qPrintable(args.
join(
" "))) ;
530 qDebug(
"%s: %s: gs returned.",
KLF_FUNC_NAME, KLF_SHORT_TIME) ;
534 res.errorstr =
QObject::tr(
"Unable to start gs!\n",
"KLFBackend");
539 res.errorstr =
QObject::tr(
"gs died abnormally!\n",
"KLFBackend");
550 res.errorstr =
QObject::tr(
"PNG file didn't appear after call to gs!\n",
"KLFBackend");
555 QFile pngfile(fnPng);
556 r = pngfile.
open(dev_READONLY);
559 res.errorstr =
QObject::tr(
"Unable to read file %1!\n",
"KLFBackend")
563 res.pngdata_raw = pngfile.readAll();
566 res.result.loadFromData(res.pngdata_raw,
"PNG");
569 res.result.img_settext(
"AppVersion",
QString::fromLatin1(
"KLatexFormula " KLF_VERSION_STRING));
570 res.result.img_settext(
"Application",
571 QObject::tr(
"Created with KLatexFormula version %1",
"KLFBackend::saveOutputToFile"));
572 res.result.img_settext(
"Software",
QString::fromLatin1(
"KLatexFormula " KLF_VERSION_STRING));
573 res.result.img_settext(
"InputLatex", in.
latex);
574 res.result.img_settext(
"InputMathMode", in.
mathmode);
575 res.result.img_settext(
"InputPreamble", in.
preamble);
576 res.result.img_settext(
"InputFgColor",
QString(
"rgb(%1, %2, %3)").arg(qRed(in.
fg_color))
578 res.result.img_settext(
"InputBgColor",
QString(
"rgba(%1, %2, %3, %4)").arg(qRed(in.
bg_color))
590 #ifdef KLFBACKEND_QT4
595 buf.open(dev_WRITEONLY);
596 bool r = res.result.save(&buf,
"PNG");
598 qWarning(
"%s: Error: Can't save \"final\" PNG data.",
KLF_FUNC_NAME);
599 res.pngdata.ba_assign(res.pngdata_raw);
607 args << settings.
epstopdfexec << dir_native_separators(fnFinalEps)
608 << (
"--outfile="+dir_native_separators(fnPdf));
610 qDebug(
"%s: %s: about to epstopdf... %s",
KLF_FUNC_NAME, KLF_SHORT_TIME, qPrintable(args.
join(
" "))) ;
612 qDebug(
"%s: %s: epstopdf returned.",
KLF_FUNC_NAME, KLF_SHORT_TIME) ;
616 res.errorstr =
QObject::tr(
"Unable to start epstopdf!\n",
"KLFBackend");
621 res.errorstr =
QObject::tr(
"epstopdf died nastily!\n",
"KLFBackend");
631 qDebug(
"%s: %s: pdf file '%s' didn't appear after epstopdf!",
KLF_FUNC_NAME, KLF_SHORT_TIME,
634 res.errorstr =
QObject::tr(
"PDF file didn't appear after call to epstopdf!\n",
"KLFBackend");
639 QFile pdffile(fnPdf);
640 r = pdffile.
open(dev_READONLY);
643 res.errorstr =
QObject::tr(
"Unable to read file %1!\n",
"KLFBackend").arg(fnPdf);
646 res.pdfdata = pdffile.readAll();
650 qDebug(
"%s: %s: end of function.",
KLF_FUNC_NAME, KLF_SHORT_TIME) ;
656 void KLFBackend::cleanup(
QString tempfname)
658 const char *skipcleanup = getenv(
"KLFBACKEND_LEAVE_TEMP_FILES");
659 if (skipcleanup != NULL && (*skipcleanup ==
'1' || *skipcleanup ==
't' || *skipcleanup ==
'T' ||
660 *skipcleanup ==
'y' || *skipcleanup ==
'Y'))
678 QMutex KLFBackend::__mutex;
694 QString format = fmt.s_trimmed().s_toUpper();
697 if (format ==
"EPS" || format ==
"PS") {
698 device->dev_write(klfoutput.
epsdata);
699 }
else if (format ==
"PNG") {
700 device->dev_write(klfoutput.
pngdata);
701 }
else if (format ==
"PDF") {
704 "KLFBackend::saveOutputToFile");
705 qWarning(
"%s", qPrintable(error));
706 if (errorStringPtr != NULL)
710 device->dev_write(klfoutput.
pdfdata);
712 bool res = klfoutput.
result.
save(device, format.s_toLatin1());
715 "KLFBackend::saveOutputToDevice").arg(format);
716 qWarning(
"%s", qPrintable(errstr));
717 if (errorStringPtr != NULL)
718 *errorStringPtr = errstr;
733 if ( ! fi.fi_suffix().isEmpty() )
734 format = fi.fi_suffix();
738 format = format.s_trimmed().s_toUpper();
741 if (fileName.
isEmpty() || fileName ==
"-") {
742 if ( ! fout.f_open_fp(stdout) ) {
744 "KLFBackend::saveOutputToFile").arg(fout.f_error());
745 qWarning(
"%s", qPrintable(error));
746 if (errorStringPtr != NULL)
747 *errorStringPtr = error;
751 fout.f_setFileName(fileName);
752 if ( ! fout.
open(dev_WRITEONLY) ) {
754 "KLFBackend::saveOutputToFile")
755 .arg(fileName).arg(fout.f_error());
756 qWarning(
"%s", qPrintable(error));
757 if (errorStringPtr != NULL)
758 *errorStringPtr = error;
773 for (k = 0; standard_extra_paths[k] != NULL; ++k) {
774 stdextrapaths.append(standard_extra_paths[k]);
781 #ifdef KLFBACKEND_QT4
784 # if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_MACX)
786 # elif defined(Q_OS_WIN32)
787 settings->
tempdir = getenv(
"TEMP");
803 { & settings->
gsexec, progGS },
808 klfDbg(
klfFmtCC(
"Our base extra paths are: %s", qPrintable(extra_paths))) ;
809 QString ourextrapaths = extra_paths;
810 ourextrapaths.
replace(
"@executable_path", qApp->applicationDirPath());
811 klfDbg(
klfFmtCC(
"Our extra paths are: %s", qPrintable(ourextrapaths))) ;
813 for (k = 0; progs_to_find[k].target_setting != NULL; ++k) {
814 klfDbg(
"Looking for "+progs_to_find[k].prog_names.join(
" or ")) ;
815 for (j = 0; j < (int)progs_to_find[k].prog_names.size(); ++j) {
816 klfDbg(
"Testing `"+progs_to_find[k].prog_names[j]+
"'") ;
817 *progs_to_find[k].target_setting
818 =
klfSearchPath(progs_to_find[k].prog_names[j], ourextrapaths);
819 if (!progs_to_find[k].target_setting->isEmpty()) {
820 klfDbg(
"Found! at `"+ *progs_to_find[k].target_setting+
"'") ;
828 bool result_failure =
832 return !result_failure;
858 + dir_native_separators(gsfi.fi_absolutePath()+
"/../../ghostscript/base")
860 + dir_native_separators(gsfi.fi_absolutePath()+
"/../../fonts");
861 __klf_append_replace_env_var(& settings->
execenv,
"MIKTEX_GS_LIB", mgsenv);
862 klfDbg(
"Adjusting environment for mgs.exe: `"+mgsenv+
"'") ;
870 QString execenvpath =
QString(
"PATH=%1:$PATH").
arg(epstopdf_fi.fi_absolutePath());
871 __klf_append_replace_env_var(& settings->
execenv,
"PATH", execenvpath);
#define KLFERR_PNGREADFAIL
Error while opening .png file for reading.
Defines the KLFBlockProcess class.
#define KLFERR_PROGERR_LATEX
latex exited with a non-zero status
#define KLFERR_EPSREADFAIL
Error while opening .eps file for reading.
fromNativeSeparators(const QString &pathName)
bool KLF_EXPORT klf_detect_execenv(KLFBackend::klfSettings *settings)
detects any additional settings to environment variables
#define KLFERR_TEXWRITEFAIL
Error while opening .tex file for writing.
#define KLFERR_MISSINGMATHMODETHREEDOTS
The "..." is missing in math mode string.
save(const QString &fileName, const char *format=0, int quality=-1)
#define KLFERR_PROGERR_EPSTOPDF
epstopdf exited with non-zero status (if epstopdf is to be used)
arg(const QString &a, int fieldWidth=0, const QChar &fillChar=QLatin1Char( ' ')
#define KLFERR_EPSREADFAIL_OF
Error while opening -outlfonts.eps after outlining fonts with gs.
#define klfDbg(streamableItems)
print debug stream items
#define KLFERR_PDFREADFAIL
Error while opening .pdf file for reading.
bool startProcess(QStringList cmd, QByteArray stdindata, QStringList env=QStringList())
replace(int pos, int len, const QByteArray &after)
#define KLFERR_EPSTOPDFNONORMALEXIT
epstopdf program did not exit properly (program killed) (see also KLFERR_PROGERR_EPSTOPDF) ...
#define KLFERR_NOERROR
No Error.
join(const QString &separator)
#define KLFERR_NOLATEXPROG
Error while launching the given latex program.
static bool saveOutputToDevice(const klfOutput &output, QIODevice *device, const QString &format=QString("PNG"), QString *errorString=NULL)
Saves the given output into the given device.
tr(const char *sourceText, const char *comment=0, int n=-1)
#define KLFERR_NOEPSBBOX
Error while searching file for %BoundingBox instruction in EPS.
replace(int position, int n, const QString &after)
#define KLFERR_NODVIFILE
No .dvi file appeared after runnig latex program.
number(long n, int base=10)
indexOf(const QByteArray &ba, int from=0)
fromLocal8Bit(const char *str, int size=-1)
General settings for KLFBackend::getLatexFormula()
KLF_EXPORT QString klfSearchPath(const QString &prog, const QString &extra_path="")
Smart executable searching in a given path list with wildcards.
#define KLFERR_PROGERR_GS_OF
gs (while outlining fonts) exited with non-zero status
KLFBackend::getLatexFormula() result.
KLF_EXPORT QStringList klf_cur_environ()
The current process environment.
#define KLFERR_NOEPSFILE
no .eps file appeared after running dvips program
#define KLFERR_GSNONORMALEXIT
gs program did not exit properly (program killed) (see also KLFERR_PROGERR_GS)
#define KLFERR_NOEPSTOPDFPROG
Error while launching the given epstopdf program (if given)
#define KLF_DEBUG_TIME_BLOCK(msg)
Utility to time the execution of a block.
#define KLFERR_NOPDFFILE
No .pdf file appeared after running epstopdf program.
QString readStderrString()
contains(const QString &str, Qt::CaseSensitivity cs=Qt::CaseSensitive)
setWorkingDirectory(const QString &dir)
#define KLFERR_PROGERR_DVIPS
dvips exited with a non-zero status
Definition of class KLFBackend.
#define KLFERR_DVIPSNONORMALEXIT
dvips program did not exit properly (program killed) (see also KLFERR_PROGERR_DVIPS) ...
bool processNormalExit() const
#define KLFERR_NOPNGFILE
No .png file appeared after running gs program.
#define KLFERR_NOEPSFILE_OF
No -outlfonts.eps file appeared after calling gs for outlining fonts.
int processExitStatus() const
#define KLFERR_EPSWRITEFAIL
Error while opening ...-good.eps file for writing.
QString readStdoutString()
#define KLFERR_MISSINGLATEXFORMULA
No LaTeX formula is specified (empty string)
#define KLFERR_NODVIPSPROG
Error while launching the given dvips program.
static bool saveOutputToFile(const klfOutput &output, const QString &fileName, const QString &format=QString(), QString *errorString=NULL)
Save the output to image file.
A QProcess subclass for code-blocking process execution.
#define KLFERR_NOGSPROG
Error while launching the given gs program.
fromLatin1(const char *str, int size=-1)
#define KLFERR_LATEXNONORMALEXIT
latex program did not exit properly (program killed) (see also KLFERR_PROGERR_LATEX) ...
#define KLFERR_PROGERR_GS
gs exited with a non-zero status
static bool detectSettings(klfSettings *settings, const QString &extraPath=QString())
Detects the system settings and stores the guessed values in settings.
bool KLF_EXPORT operator==(const KLFBackend::klfInput &a, const KLFBackend::klfInput &b)
static klfOutput getLatexFormula(const klfInput &in, const klfSettings &settings)
The function that processes everything.
#define KLFERR_BADEPSBBOX
Error while parsing value for %BoundingBox instruction in EPS.
int status
A code describing the status of the request.
#define KLF_PATH_SEP
The character used in the $PATH environment variable to separate different locations.