33 #include <QCoreApplication> 37 #include <QTextStream> 41 #include <QTextDocument> 42 #include <QImageWriter> 44 #include <QTemporaryDir> 51 #include "klffilterprocess.h" 52 #include "klfuserscript.h" 54 #include "klfbackend_p.h" 84 #ifdef KLF_EXTRA_SEARCH_PATHS 85 # define EXTRA_PATHS_PRE KLF_EXTRA_SEARCH_PATHS , 88 # define EXTRA_PATHS_PRE 93 #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) 98 static const char * standard_extra_paths[] = {
100 "C:\\Program Files*\\MiKTeX*\\miktex\\bin",
101 "C:\\Program Files*\\gs\\gs*\\bin",
104 #elif defined(KLF_WS_MAC) 109 static const char * standard_extra_paths[] = {
111 "/usr/texbin:/Library/TeX/texbin:/usr/local/bin:/opt/local/bin:/sw/bin:/sw/usr/bin",
119 static const char * standard_extra_paths[] = {
129 KLFAbstractLatexMetaInfo::KLFAbstractLatexMetaInfo()
132 KLFAbstractLatexMetaInfo::~KLFAbstractLatexMetaInfo()
142 saveField(
"Application",
143 QObject::tr(
"Created with KLatexFormula version %1",
"KLFBackend::saveOutputToFile")
144 .arg(KLF_VERSION_STRING));
146 saveField(
"InputLatex", in.
latex);
147 saveField(
"InputMathMode", in.
mathmode);
148 saveField(
"InputPreamble", in.
preamble);
150 saveField(
"InputFgColor",
QString(
"rgb(%1, %2, %3)").arg(qRed(in.fg_color))
151 .
arg(qGreen(in.fg_color)).
arg(qBlue(in.fg_color)));
152 saveField(
"InputBgColor",
QString(
"rgba(%1, %2, %3, %4)").arg(qRed(in.
bg_color))
157 saveField(
"InputBypassTemplate", boolstr[(
int)in.
bypassTemplate]);
161 saveField(
"InputUserScriptParams", usparams);
166 saveField(
"SettingsOutlineFonts", boolstr[(
int)settings.
outlineFonts]);
168 saveField(
"SettingsWantRaw", boolstr[(
int)settings.
wantRaw]);
169 saveField(
"SettingsWantPDF", boolstr[(
int)settings.
wantPDF]);
170 saveField(
"SettingsWantSVG", boolstr[(
int)settings.
wantSVG]);
172 klfDbg(
"saved meta-info.") ;
176 KLFImageLatexMetaInfo::KLFImageLatexMetaInfo(
QImage *imgwrite) : _w(imgwrite) { }
178 void KLFImageLatexMetaInfo::saveField(
const QString& k,
const QString& v)
195 for (i = 0; i < v.
length(); ++i) {
196 if (v[i] < 0 || v[i] > 126) {
206 for (i = 0; i < vdata.
size(); ++i) {
209 if (
QChar(vdata[i]).isLetterOrNumber() || c ==
' ' || c ==
'.' || c ==
',' || c ==
'/')
224 klfDbg(
"escaping char: (int)c="<<(
int)c<<
" (uint)c="<<uint(c)<<
", octal="<<
klfFmtCC(
"%03o", (uint)c));
229 return "("+escaped+
")";
239 for (i = 0; i < (vdata.
size()-1); i += 2) {
240 hex +=
klfFmt(
"%02x%02x ", (
unsigned int)(
unsigned char)vdata[i], (
unsigned int)(
unsigned char)vdata[i+1]);
242 return "<" + hex +
">";
247 KLFPdfmarksWriteLatexMetaInfo::KLFPdfmarksWriteLatexMetaInfo(
QByteArray *
string)
255 "/pdfmark where { pop } { /globaldict where { pop globaldict } { userdict } ifelse " 256 "/pdfmark /cleartomark load put } ifelse\n" 266 void KLFPdfmarksWriteLatexMetaInfo::saveField(
const QString& k,
const QString& v)
270 void KLFPdfmarksWriteLatexMetaInfo::finish()
272 _s->
append(
" /DOCINFO pdfmark\n");
276 QByteArray datavalue = klf_escape_ps_string(v);
278 _s->
append(
" /"+k+
" " + datavalue +
"\n");
316 KLFBackend::TemplateGenerator::TemplateGenerator()
319 KLFBackend::TemplateGenerator::~TemplateGenerator()
323 KLFBackend::DefaultTemplateGenerator::DefaultTemplateGenerator()
326 KLFBackend::DefaultTemplateGenerator::~DefaultTemplateGenerator()
340 s +=
"\\documentclass{article}\n" 341 "\\usepackage[dvips]{color}\n";
344 "\\begin{document}\n" 345 "\\thispagestyle{empty}\n";
349 s +=
QString(
"\\definecolor{klffgcolor}{rgb}{%1,%2,%3}\n").
arg(qRed(in.fg_color)/255.0)
350 .
arg(qGreen(in.fg_color)/255.0).
arg(qBlue(in.fg_color)/255.0);
351 s +=
QString(
"\\definecolor{klfbgcolor}{rgb}{%1,%2,%3}\n").
arg(qRed(in.
bg_color)/255.0)
354 s +=
"\\pagecolor{klfbgcolor}\n";
355 s +=
"{\\color{klffgcolor} ";
369 KLFBackend::KLFBackend()
376 #define D_RX "([0-9eE.-]+)" 380 double x1, x2, y1, y2;
385 static bool calculate_gs_eps_bbox(
const QByteArray& epsdata,
const QString& epsFile, klfbbox *bbox,
389 static void correct_eps_bbox(
const QByteArray& epsdata,
390 const klfbbox& bbox_corrected,
const klfbbox& bbox_orig,
391 double vectorscale, QRgb bgcolor,
QByteArray * epsdatacorrected);
393 static void replace_svg_width_or_height(
QByteArray *svgdata,
const char * attr,
double val);
410 <<
"latex" <<
"dvi" <<
"eps-raw" <<
"eps-bbox" <<
"eps-processed" 411 <<
"png" <<
"pdf" <<
"svg-gs" <<
"svg" ;
414 KLF_EXPORT KLFStringSet klfbackend_dependencies(
const QString& fmt,
bool recursive =
false)
416 static KLFStringSet fn_lock = KLFStringSet();
419 klfWarning(
"Dependency loop detected for format "<<fmt) ;
420 return KLFStringSet();
436 s <<
"eps-processed";
438 s <<
"eps-processed";
440 s <<
"eps-processed";
451 KLFStringSet basedeps = s;
452 foreach (
QString str, basedeps) {
453 KLFStringSet subdeps = klfbackend_dependencies(str,
true);
454 foreach (
QString subdep, subdeps) {
463 static inline bool assert_have_formats_for(
const KLFStringSet& outputs,
const KLFStringSet& skipfmts,
466 KLFStringSet fmtlist = klfbackend_dependencies(forwhat);
469 klfWarning(
"User Script Skipped format "<<s<<
" which is necessary for "<<forwhat) ;
476 #define ASSERT_HAVE_FORMATS_FOR(forwhat) \ 477 { if (!assert_have_formats_for(us_outputs, us_skipfmts, forwhat)) { \ 478 res.status = KLFERR_USERSCRIPT_BADSKIPFORMATS; \ 479 res.errorstr = QObject::tr("User Script broke dependencies in skip-formats list", "KLFBackend"); \ 496 settings = usersettings;
507 klfDbg(
"current environment is "<<curenv) ;
509 QStringList() <<
"PATH" <<
"TEXINPUTS" <<
"BIBINPUTS",
513 klfDbg(
"execution environment for sub-processes is "<<settings.
execenv) ;
532 initGsInfo(&settings, isMainThread);
535 res.
errorstr =
QObject::tr(
"Can't query version of ghostscript located at `%1'.",
"KLFBackend")
540 const GsInfo thisGsInfo = gsInfo.
value(settings.
gsexec);
547 QRgb bgcolor_when_correcting_bbox = qRgba(0,0,0,0);
553 qAlpha(in.
bg_color) != 0 && (in.
bg_color & qRgb(255,255,255)) != qRgb(255,255,255)) {
554 bgcolor_when_correcting_bbox = in.
bg_color;
603 QString ver = KLF_VERSION_STRING;
608 QString temptemplate = settings.
tempdir +
"/klftmp"+ver+
"-XXXXXX";
623 klfDbg(
"Temp location base name is "<<tempfname) ;
625 QString fnTex = tempfname +
".tex";
626 QString fnDvi = tempfname +
".dvi";
627 QString fnRawEps = tempfname +
".eps";
628 QString fnBBoxEps = tempfname +
"-bbox.eps";
629 QString fnProcessedEps = tempfname +
"-processed.eps";
630 QString fnRawPng = tempfname +
"-raw.png";
631 QString fnPdfMarks = tempfname +
".pdfmarks";
632 QString fnPdf = tempfname +
".pdf";
633 QString fnGsSvg = tempfname +
"-gs.svg";
636 QString fnSvg = tempfname +
".svg";
645 if (latexsimplified.
isEmpty()) {
662 bool r = file.
open(QIODevice::WriteOnly);
673 klfDbg(
"using custom template generator") ;
679 stream << t->generateTemplate(in, settings);
685 KLFStringSet us_outputs;
686 KLFStringSet us_skipfmts;
687 KLFStringSet our_skipfmts;
695 res.
status = scriptinfo.scriptInfoError();
696 res.
errorstr = scriptinfo.scriptInfoErrorString();
700 if ( (!scriptinfo.klfMinVersion().
isEmpty()
702 (!scriptinfo.klfMaxVersion().
isEmpty()
704 res.
status = KLFERR_USERSCRIPT_BADKLFVERSION;
705 res.
errorstr =
QObject::tr(
"User Script `%1' is not compatible with current version of KLatexFormula.",
706 "KLFBackend").
arg(scriptinfo.name());
710 if (scriptinfo.category() !=
QLatin1String(
"klf-backend-engine")) {
711 res.
status = KLFERR_USERSCRIPT_BADCATEGORY;
713 "KLFBackend").
arg(scriptinfo.name());
721 <<
"KLF_TEMPDIR=" + settings.
tempdir 722 <<
"KLF_TEMPFNAME=" + tempfname
725 <<
"KLF_GS=" + settings.
gsexec 726 <<
"KLF_GS_VERSION=" + thisGsInfo.version
727 <<
"KLF_GS_DEVICES=" +
QStringList(thisGsInfo.availdevices.toList()).join(
",")
729 << klfInputToEnvironmentForUserScript(in)
731 << klfSettingsToEnvironmentForUserScript(settings)
733 <<
"KLF_FN_TEX=" + fnTex
734 <<
"KLF_FN_LATEX=" + fnTex
735 <<
"KLF_FN_DVI=" + fnDvi
736 <<
"KLF_FN_EPS_RAW=" + fnRawEps
737 <<
"KLF_FN_EPS_PROCESSED=" + fnProcessedEps
738 <<
"KLF_FN_PNG=" + fnRawPng
739 <<
"KLF_FN_PDFMARKS=" + fnPdfMarks
740 <<
"KLF_FN_PDF=" + fnPdf
741 <<
"KLF_FN_SVG_GS=" + fnGsSvg
742 <<
"KLF_FN_SVG=" + fnSvg
748 p.addExecEnviron(addenv);
750 p.setProcessAppEvents(
false);
754 p.collectStderrTo(&stderrdata);
755 p.collectStdoutTo(&stdoutdata);
761 foreach (
QString fmt, outfmts) {
771 outdata[fnRawEps] = &rawepsdata;
773 outdata[fnBBoxEps] = &bboxepsdata;
775 outdata[fnProcessedEps] = &res.
epsdata;
787 outdata[fnGsSvg] = & gssvgdata;
793 klfWarning(
"Can't handle output format from user script: "<<fmt) ;
807 outdata.
remove(fnBBoxEps);
813 if ((tempi = skipfmts.
indexOf(
"ALL_EXCEPT")) >= 0) {
816 foreach (
QString f, klfbackend_fmts) { us_skipfmts << f; }
818 foreach (
QString fmt, skipfmts) {
819 if (!klfbackend_fmts.contains(fmt)) {
820 klfWarning(
"User Script Info: Unknown format to skip: "<<fmt) ;
828 our_skipfmts = us_skipfmts;
829 foreach (
QString fmt, outfmts) {
831 klfWarning(
"User Script Info: format " << fmt <<
" provided by script is also marked " 832 "as to be skipped!") ;
837 our_skipfmts <<
"eps-bbox";
840 our_skipfmts <<
"eps-raw";
843 our_skipfmts <<
"svg-gs";
846 klfDbg(
"us_skipfmts = " << us_skipfmts) ;
851 res.
errorstr = p.resultErrorString();
852 switch (p.resultStatus()) {
854 case KLFFP_NOEXIT: res.
status = KLFERR_USERSCRIPT_NONORMALEXIT;
break;
856 case KLFFP_NODATA: res.
status = KLFERR_USERSCRIPT_NOOUTPUT;
break;
857 case KLFFP_DATAREADFAIL: res.
status = KLFERR_USERSCRIPT_OUTPUTREADFAIL;
break;
859 res.
status = p.resultStatus();
865 foreach (
QString fmt, outfmts) {
872 corrfname = fnRawEps;
874 corrfname = fnBBoxEps;
876 corrfname = fnProcessedEps;
878 corrfname = fnRawPng;
890 klfWarning(
"Promised format " << fmt <<
" did not appear after calling user script.") ;
896 klfDbg(
"our_skipfmts = " << our_skipfmts) ;
899 if (!has_userscript_output(us_outputs,
"dvi") && !our_skipfmts.
contains(
"dvi")) {
901 klfDbg(
"preparing to launch latex.") ;
909 KLFBackendFilterProgram p(
QLatin1String(
"LaTeX"), &settings, isMainThread, tempdir.
path());
920 ok = p.run(userinputforerrors, fnDvi, &res.
dvidata);
922 p.errorToOutput(&res);
927 if (!has_userscript_output(us_outputs,
"eps-raw") && !our_skipfmts.
contains(
"eps-raw")) {
929 ASSERT_HAVE_FORMATS_FOR(
"eps-raw") ;
938 KLFBackendFilterProgram p(
QLatin1String(
"dvips"), &settings, isMainThread, tempdir.
path());
948 ok = p.run(fnRawEps, &rawepsdata);
951 p.errorToOutput(&res);
954 klfDbg(
"read raw EPS; rawepsdata/length="<<rawepsdata.
size()) ;
965 if (!has_userscript_output(us_outputs,
"eps-bbox") && !our_skipfmts.
contains(
"eps-bbox")) {
969 ASSERT_HAVE_FORMATS_FOR(
"eps-bbox") ;
971 klfbbox bbox, bbox_corrected;
974 bool ok = calculate_gs_eps_bbox(
QByteArray(), fnRawEps, &bbox, &res, settings, isMainThread);
978 bool ok = read_eps_bbox(rawepsdata, &bbox, &res);
993 bbox_corrected.x1 = 0;
994 bbox_corrected.y1 = 0;
1000 correct_eps_bbox(rawepsdata, bbox_corrected, bbox, in.
vectorscale,
1001 bgcolor_when_correcting_bbox, &bboxepsdata);
1003 klfDbg(
"corrected bbox to "<<bbox.x1<<
","<<bbox.y1<<
","<<bbox.x2<<
","<<bbox.y2);
1004 }
else if (!our_skipfmts.
contains(
"eps-bbox")) {
1013 if (us_outputs.
contains(
"eps-processed")) {
1014 fn = fnProcessedEps;
1022 bool ok = calculate_gs_eps_bbox(
QByteArray(), fn, &bb, &res, settings, isMainThread);
1026 bool ok = read_eps_bbox(bboxepsdata, &bb, &res);
1039 if (!has_userscript_output(us_outputs,
"eps-processed") && !our_skipfmts.
contains(
"eps-processed")) {
1042 ASSERT_HAVE_FORMATS_FOR(
"eps-processed") ;
1053 KLFBackendFilterProgram p(
QLatin1String(
"gs (EPS Post-Processing Outline Fonts)"), &settings, isMainThread,
1063 const char *env_gs_device = getenv(
"KLFBACKEND_GS_PS_DEVICE");
1064 if (env_gs_device != NULL) {
1066 gsoptions =
QStringList() <<
"-dNOCACHE -dNoOutputFonts";
1067 }
else if (thisGsInfo.version_maj < 9 ||
1068 (thisGsInfo.version_maj == 9 && thisGsInfo.version_min <= 7)) {
1072 }
else if (thisGsInfo.version_maj > 9 ||
1073 (thisGsInfo.version_maj == 9 && thisGsInfo.version_min >= 15)) {
1082 res.
errorstr =
QObject::tr(
"Installed Ghostscript version %1 may not be used to create font outlines." 1083 " Please upgrade to gs >= 9.15 (or downgrade to gs <= 9.07).",
1084 "KLFBackend").
arg(thisGsInfo.version);
1088 p.addArgv(settings.
gsexec);
1090 <<
"-dNOPAUSE" <<
"-dSAFER" <<
"-dEPSCrop" <<
QString::fromLatin1(
"-sDEVICE=%1").arg(psdevice)
1092 <<
"-q" <<
"-dBATCH" <<
"-");
1094 ok = p.run(bboxepsdata, fnProcessedEps, &res.
epsdata);
1096 p.errorToOutput(&res);
1108 if (!has_userscript_output(us_outputs,
"png") && !our_skipfmts.
contains(
"png")) {
1110 ASSERT_HAVE_FORMATS_FOR(
"png") ;
1119 KLFBackendFilterProgram p(
QLatin1String(
"gs (PNG)"), &settings, isMainThread, tempdir.
path());
1132 <<
"-dNOPAUSE" <<
"-dSAFER" <<
"-dTextAlphaBits=4" <<
"-dGraphicsAlphaBits=4" 1135 p.addArgv(
"-sDEVICE=png16m");
1137 p.addArgv(
"-sDEVICE=pngalpha");
1141 ok = p.run(bboxepsdata, fnRawPng, &res.
pngdata_raw);
1143 p.errorToOutput(&res);
1151 klfWarning(
"PNG format was skipped by user script. The QImage object will be invalid.") ;
1156 if (!has_userscript_output(us_outputs,
"png") || !
QFile::exists(fnRawPng)) {
1157 klfWarning(
"PNG format is required to initialize the QImage object, but was not generated by user script.") ;
1165 if (!our_skipfmts.
contains(
"png")) {
1169 metainfo.saveMetaInfo(in, settings);
1173 buf.
open(QIODevice::WriteOnly);
1177 klfWarning(
"Can't save \"final\" PNG data.") ;
1182 klfDbg(
"prepared final PNG data.") ;
1185 if ( settings.
wantPDF && !has_userscript_output(us_outputs,
"pdf") && !our_skipfmts.
contains(
"pdf") ) {
1187 ASSERT_HAVE_FORMATS_FOR(
"pdf") ;
1190 {
QFile fpdfmarks(fnPdfMarks);
1191 bool r = fpdfmarks.
open(QIODevice::WriteOnly);
1200 pdfmetainfo.
savePDFField(
"Keywords",
"KLatexFormula KLF LaTeX equation formula");
1201 pdfmetainfo.
savePDFField(
"Creator",
"KLatexFormula " KLF_VERSION_STRING);
1202 pdfmetainfo.saveMetaInfo(in, settings);
1203 pdfmetainfo.finish();
1204 fpdfmarks.
write(pdfmarkstr);
1215 KLFBackendFilterProgram p(
QLatin1String(
"gs (PDF)"), &settings, isMainThread, tempdir.
path());
1223 <<
"-dNOPAUSE" <<
"-dSAFER" <<
"-sDEVICE=pdfwrite" 1225 <<
"-q" <<
"-dBATCH" <<
"-" << fnPdfMarks);
1230 p.errorToOutput(&res);
1237 if (!has_userscript_output(us_outputs,
"svg-gs") &&
1238 !our_skipfmts.
contains(
"svg-gs")) {
1240 ASSERT_HAVE_FORMATS_FOR(
"svg-gs") ;
1243 if (!thisGsInfo.availdevices.contains(
"svg")) {
1257 KLFBackendFilterProgram p(
QLatin1String(
"gs (SVG)"), &settings, isMainThread, tempdir.
path());
1264 p.addArgv(settings.
gsexec);
1266 p.addArgv(
QStringList() <<
"-dNOCACHE" <<
"-dNOPAUSE" <<
"-dSAFER" <<
"-dEPSCrop" <<
"-sDEVICE=svg" 1268 <<
"-q" <<
"-dBATCH" <<
"-");
1271 ok = p.run(bboxepsdata, fnGsSvg, &gssvgdata);
1273 p.errorToOutput(&res);
1278 if (!has_userscript_output(us_outputs,
"svg") && !our_skipfmts.
contains(
"svg")) {
1280 ASSERT_HAVE_FORMATS_FOR(
"svg") ;
1288 replace_svg_width_or_height(&gssvgdata,
"width=", res.
width_pt);
1289 replace_svg_width_or_height(&gssvgdata,
"height=", res.
height_pt);
1297 klfDbg(
"end of function.") ;
1304 static bool calculate_gs_eps_bbox(
const QByteArray& epsData,
const QString& epsFile, klfbbox *bbox,
1319 KLFBackendFilterProgram p(
QLatin1String(
"GhostScript (bbox)"), &settings, isMainThread, settings.
tempdir);
1326 p.setOutputStdout(
true);
1327 p.setOutputStderr(
true);
1331 p.setArgv(
QStringList() << settings.
gsexec <<
"-dNOPAUSE" <<
"-dSAFER" <<
"-sDEVICE=bbox" <<
"-q" <<
"-dBATCH" 1334 bool ok = p.run(epsData ,
QString() , &bboxdata);
1336 p.errorToOutput(resError);
1340 klfDbg(
"gs provided output:\n"<<bboxdata);
1343 QRegExp rx_gsbbox(
"%%HiResBoundingBox\\s*:\\s+" D_RX
"\\s+" D_RX
"\\s+" D_RX
"\\s+" D_RX
"");
1347 resError->
errorstr =
QObject::tr(
"Ghostscript did not provide parsable BBox output!",
"KLFBackend");
1359 static bool parse_bbox_values(
const QString& str, klfbbox *bbox)
1362 QRegExp rx_bbvalues(
"" D_RX
"\\s+" D_RX
"\\s+" D_RX
"\\s+" D_RX
"");
1363 int i = rx_bbvalues.
indexIn(str);
1374 static bool s_starts_with(
const char * x,
int len_x,
const char *test,
int len_test)
1376 if (len_x < len_test)
1378 return !strncmp(x, test, len_test);
1385 static const char * hibboxtag =
"%%HiResBoundingBox:";
1386 static const char * bboxtag =
"%%BoundingBox:";
1387 static const int hibboxtaglen = strlen(hibboxtag);
1388 static const int bboxtaglen = strlen(bboxtag);
1393 bool r = buf.
open(QIODevice::ReadOnly | QIODevice::Text);
1395 klfWarning(
"What's going on!!?! can't open buffer for reading? Will Fail!!!") ;
1399 QObject::tr(
"DVIPS did not provide parsable %%BoundingBox: in its output!",
"KLFBackend");
1401 char linebuffer[512];
1403 bool gotepsbbox =
false;
1404 int still_look_for_hiresbbox_lines = 5;
1405 while ((n = buf.
readLine(linebuffer,
sizeof(linebuffer)-1)) > 0) {
1406 if (gotepsbbox && still_look_for_hiresbbox_lines-- < 0) {
1409 klfDbg(
"stopped looking for hires-bbox.") ;
1412 if (s_starts_with(linebuffer, n, hibboxtag, hibboxtaglen)) {
1422 klfDbg(
"got hires-bbox.") ;
1426 if (s_starts_with(linebuffer, n, bboxtag, bboxtaglen)) {
1434 klfDbg(
"got normal bbox.") ;
1457 static void correct_eps_bbox(
const QByteArray& rawepsdata,
const klfbbox& bbox_corrected,
1458 const klfbbox& bbox_orig,
double vectorscale, QRgb bgcolor,
1463 static const char * bboxdecl =
"%%BoundingBox:";
1464 static int bboxdecl_len = strlen(bboxdecl);
1466 double offx = bbox_corrected.x1 - bbox_orig.x1;
1467 double offy = bbox_corrected.y1 - bbox_orig.y1;
1471 char nl[] =
"\0\0\0";
1472 i = rawepsdata.
indexOf(bboxdecl);
1477 int j = i+bboxdecl_len;
1478 while (j < (
int)rawepsdata.
size() && rawepsdata[j] !=
'\r' && rawepsdata[j] !=
'\n')
1481 if (rawepsdata[j] ==
'\r' && j < (
int)rawepsdata.
size()-1 && rawepsdata[j+1] ==
'\n') {
1482 nl[0] =
'\r', nl[1] =
'\n';
1484 nl[0] = rawepsdata[j];
1488 double dwi = bbox_corrected.x2 * vectorscale;
1489 double dhi = bbox_corrected.y2 * vectorscale;
1490 int wi = (int)(dwi + 0.99999) ;
1491 int hi = (int)(dhi + 0.99999) ;
1495 snprintf(buffer,
sizeof(buffer)-1,
1496 "%%%%BoundingBox: 0 0 %d %d%s" 1497 "%%%%HiResBoundingBox: 0 0 %s %s%s",
1500 buffer_len = strlen(buffer);
1502 char backgroundfillps[1024] =
"";
1503 if (qAlpha(bgcolor) > 0) {
1504 klfDbg(
"we have a bg color, so draw the background. bgcolor="<<
klfFmt(
"%#10x", (uint)bgcolor));
1505 snprintf(backgroundfillps,
sizeof(backgroundfillps)-1,
1514 "%s %s %s setrgbcolor " 1530 snprintf(buffer2,
sizeof(buffer2)-1,
1533 "%%%%PageBoundingBox 0 0 %d %d%s" 1534 "<< /PageSize [%d %d] >> setpagedevice%s" 1551 klfDbg(
"buffer is `"<<buffer<<
"', length="<<buffer_len) ;
1552 klfDbg(
"rawepsdata has length="<<rawepsdata.
size()) ;
1556 neweps = rawepsdata;
1557 neweps.
replace(i, len, buffer);
1559 const char * endsetupstr =
"%%EndSetup";
1560 int i2 = neweps.
indexOf(endsetupstr);
1562 i2 = i + buffer_len;
1564 i2 += strlen(endsetupstr);
1566 neweps.replace(i2, 0, buffer2);
1568 klfDbg(
"neweps has now length="<<neweps.size());
1569 klfDebugf((
"New eps bbox is [0 0 %.6g %.6g] with translate [%.6g %.6g] and scale %.6g.",
1570 dwi, dhi, offx, offy, vectorscale));
1572 *epsdatacorrected = neweps;
1576 static void replace_svg_width_or_height(
QByteArray *svgdata,
const char * attreq,
double val)
1580 int i = svgdataref.
indexOf(attreq);
1582 while (j < (
int)svgdataref.
size() && (!isspace(svgdataref[j]) && svgdataref[j] !=
'>'))
1586 snprintf(buffer,
sizeof(buffer)-1,
"%s'%s'", attreq,
klfFmtDoubleCC(val,
'f', 3));
1588 svgdata->
replace(i, j-i, buffer);
1601 a.fg_color == b.fg_color &&
1634 return availableSaveFormats(*output);
1637 fmts <<
"PNG" <<
"PS" <<
"EPS" <<
"DVI" <<
"PDF" <<
"SVG";
1662 formats <<
"PS" <<
"EPS";
1684 if (format ==
"PNG") {
1686 }
else if (format ==
"EPS" || format ==
"PS") {
1688 }
else if (format ==
"DVI") {
1690 }
else if (format ==
"PDF") {
1693 "KLFBackend::saveOutputToFile");
1694 qWarning(
"%s", qPrintable(error));
1695 if (errorStringPtr != NULL)
1696 errorStringPtr->operator=(error);
1700 }
else if (format ==
"SVG") {
1703 "KLFBackend::saveOutputToFile");
1704 qWarning(
"%s", qPrintable(error));
1705 if (errorStringPtr != NULL)
1706 errorStringPtr->operator=(error);
1714 "KLFBackend::saveOutputToDevice").
arg(format);
1715 qWarning(
"%s", qPrintable(errstr));
1716 if (errorStringPtr != NULL)
1717 *errorStringPtr = errstr;
1740 if (fileName.
isEmpty() || fileName ==
"-") {
1741 if ( ! fout.
open(stdout, QIODevice::WriteOnly) ) {
1743 "KLFBackend::saveOutputToFile").
arg(fout.
error());
1744 qWarning(
"%s", qPrintable(error));
1745 if (errorStringPtr != NULL)
1746 *errorStringPtr = error;
1751 if ( ! fout.
open(QIODevice::WriteOnly) ) {
1753 "KLFBackend::saveOutputToFile")
1755 qWarning(
"%s", qPrintable(error));
1756 if (errorStringPtr != NULL)
1757 *errorStringPtr = error;
1762 return saveOutputToDevice(klfoutput, &fout, format, errorStringPtr);
1772 for (k = 0; standard_extra_paths[k] != NULL; ++k) {
1773 stdextrapaths.
append(standard_extra_paths[k]);
1799 { & settings->
gsexec, progGS },
1804 klfDbg(
klfFmtCC(
"Our base extra paths are: %s", qPrintable(extra_paths))) ;
1805 QString ourextrapaths = extra_paths;
1806 ourextrapaths.
replace(
"@executable_path", qApp->applicationDirPath());
1807 klfDbg(
klfFmtCC(
"Our extra paths are: %s", qPrintable(ourextrapaths))) ;
1809 for (k = 0; progs_to_find[k].target_setting != NULL; ++k) {
1810 klfDbg(
"Looking for "+progs_to_find[k].prog_names.join(
" or ")) ;
1811 for (j = 0; j < (int)progs_to_find[k].prog_names.size(); ++j) {
1812 klfDbg(
"Testing `"+progs_to_find[k].prog_names[j]+
"'") ;
1813 *progs_to_find[k].target_setting
1814 =
klfSearchPath(progs_to_find[k].prog_names[j], ourextrapaths);
1815 if (!progs_to_find[k].target_setting->isEmpty()) {
1816 klfDbg(
"Found! at `"+ *progs_to_find[k].target_setting+
"'") ;
1822 bool r1 = detectOptionSettings(settings, isMainThread);
1824 bool result_failure =
1828 return !result_failure;
1844 initGsInfo(settings, isMainThread);
1846 klfWarning(
"Cannot get 'gs' devices information with "<<(settings->
gsexec+
" --version/--help"));
1848 }
else if (gsInfo[settings->
gsexec].availdevices.
contains(
"svg")) {
1863 if (gsfi.
fileName() ==
"mgs.exe") {
1869 klfDbg(
"Adjusting environment for mgs.exe: `MIKTEX_GS_LIB="+mgsenv+
"'") ;
1893 KLFBackendFilterProgram p(
QLatin1String(
"gs (test version)"), settings, isMainThread, settings->
tempdir);
1900 p.setExecEnviron(settings->
execenv);
1903 p.setProcessAppEvents(
false);
1908 bool ok = p.run(
QString(), &ba_gsver);
1911 klfDbg(
"gs version text (untrimmed): "<<gsver) ;
1918 KLFStringSet availdevices;
1920 KLFBackendFilterProgram p(
QLatin1String(
"gs (query help)"), settings, isMainThread, settings->
tempdir);
1930 p.setExecEnviron(ee);
1933 p.setProcessAppEvents(
false);
1938 bool ok = p.run(
QString(), &ba_gshelp);
1942 klfDbg(
"gs help text: "<<gshelp) ;
1944 const char * availdevstr =
"Available devices:";
1945 int k = gshelp.
indexOf(availdevstr, 0, Qt::CaseInsensitive) ;
1947 klfWarning(
"Unable to parse gs' available devices.") ;
1949 k += strlen(availdevstr);
1957 klfDbg(
"Detected devices: "<<availdevices) ;
1964 QRegExp rx_version(
"^(\\d+)\\.(\\d+)");
1965 int foundver = rx_version.
indexIn(gsver);
1966 if (foundver >= 0) {
1967 gsvermaj = rx_version.
cap(1).
toInt();
1968 gsvermin = rx_version.
cap(2).
toInt();
1971 klfDbg(
"GS Version: "<<gsver<<
" = "<<gsvermaj<<
"."<<gsvermin);
1975 i.version_maj = gsvermaj;
1976 i.version_min = gsvermin;
1978 i.availdevices = availdevices;
1980 gsInfo[settings->
gsexec] = i;
1990 env <<
"KLF_SETTINGS_BORDEROFFSET=" +
klfFmt(
"%.3g,%.3g,%.3g,%.3g pt", settings.
tborderoffset,
2004 .
arg(qGreen(in.fg_color)).
arg(qBlue(in.fg_color)).
arg(qAlpha(in.fg_color));
2007 env <<
"KLF_INPUT_LATEX=" + in.
latex 2008 <<
"KLF_INPUT_MATHMODE=" + in.
mathmode 2009 <<
"KLF_INPUT_PREAMBLE=" + in.
preamble 2011 <<
"KLF_INPUT_FG_COLOR_WEB=" +
QColor(in.fg_color).
name()
2012 <<
"KLF_INPUT_FG_COLOR_RGBA=" + fgcol
2015 <<
"KLF_INPUT_BG_COLOR_RGBA=" + bgcol
2023 env <<
"KLF_ARG_"+cit.
key() +
"=" + cit.
value();
QStringList skipFormats() const
List of formats that klfbackend should not attempt to generate.
#define KLFERR_LATEX_NORUN
Error while launching the given latex program.
QByteArray fromUnicode(const QString &str) const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
#define KLFERR_PROGERR_GSPDF
gs exited with non-zero status while producing PDF
bool loadFromData(const uchar *data, int len, const char *format)
QString toNativeSeparators(const QString &pathName)
QString cap(int nth) const
Defines the KLFBlockProcess class.
bool load(QIODevice *device, const char *format)
#define KLFERR_GSPDF_OUTPUTREADFAIL
Failed to read PDF file produced by 'gs'.
KLF_EXPORT QByteArray klfSaveVariantToText(const QVariant &value, bool saveListAndMapsAsXML, QByteArray *savedType, QByteArray *savedListOrMapType)
#define KLFERR_PROGERR_LATEX
latex exited with a non-zero status
bool contains(const Key &key) const
#define KLFERR_USERSCRIPT_NORUN
Failed to execute user wrapper script.
QString fromNativeSeparators(const QString &pathName)
#define KLFERR_GSSVG_NOSVG
This version of gs cannot produce SVG.
QByteArray trimmed() const
#define KLFERR_TEXWRITEFAIL
Error while opening .tex file for writing.
KLF_EXPORT void klfSetEnvironmentVariable(QStringList *env, const QString &var, const QString &value)
#define KLFERR_GSPOSTPROC_NOOUTPUT
Program 'gs' didn't provide any data after post-processing EPS file.
#define KLFERR_MISSINGMATHMODETHREEDOTS
The "..." is missing in math mode string.
bool save(const QString &fileName, const char *format, int quality) const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
KLF_EXPORT QByteArray klfFmt(const char *fmt, va_list pp)
#define KLFERR_GSPNG_NOOUTPUT
No PNG file appeared after running 'gs'.
void klfMergeEnvironment(QStringList *env, const QStringList &addvars, const QStringList &pathvars, uint actions)
#define KLFERR_PROGERR_GSBBOX
gs exited with non-zero status while calculating bbox of EPS file generated by dvips ...
#define KLFERR_GSPNG_OUTPUTREADFAIL
Failed to read PNG file produced by 'gs'.
#define KLFERR_GSSVG_NOOUTPUT
No SVG file appeared after running 'gs'.
#define KLFERR_DVIPS_NORUN
Error while launching the given dvips program.
static bool detectSettings(klfSettings *settings, const QString &extraPath=QString(), bool isMainThread=true)
Detects the system settings and stores the guessed values in settings.
const_iterator constBegin() const
QByteArray pdfdata
data for a pdf file
QByteArray toUpper() const
bool contains(const QString &str, Qt::CaseSensitivity cs) const
void setData(const QByteArray &data)
#define KLFERR_LATEX_OUTPUTREADFAIL
Error while opening .dvi file for reading.
KLF_EXPORT QString klfSearchPath(const QString &programName, const QString &extra_path)
void setFileName(const QString &name)
#define klfDbg(streamableItems)
#define KLF_DEBUG_BLOCK(msg)
double width_pt
Width in points of the resulting equation.
#define KLFERR_NOERROR
No Error.
QString join(const QString &separator) const
#define KLFERR_NOLATEXPROG
obsolete, same as KLFERR_LATEX_NORUN
#define KLFERR_GSPDF_NORUN
Program 'gs' couldn't be executed to generate PDF.
QString text(const QString &key) const
double toDouble(bool *ok) const
static klfOutput getLatexFormula(const klfInput &in, const klfSettings &settings, bool isMainThread=true)
The function that processes everything.
int status
A code describing the status of the request.
KLF_EXPORT QByteArray klfEscapedToData(const QByteArray &data, char escapechar)
QString tr(const char *sourceText, const char *disambiguation, int n)
klfSettings settings
The settings that this output was generated with.
QStringList spitsOut() const
List of formats that this script will generate.
#define KLF_ASSERT_NOT_NULL(ptr, msg, failaction)
#define KLFERR_DVIPS_NONORMALEXIT
dvips program did not exit properly (program killed) (see also KLFERR_PROGERR_DVIPS) ...
QByteArray pngdata
the data for a png file (re-processed with meta information)
TemplateGenerator * templateGenerator
QByteArray pngdata_raw
the data for a png file (exact gs output content)
int indexIn(const QString &str, int offset, CaretMode caretMode) const
KLF_EXPORT int klfVersionCompare(const QString &v1, const QString &v2)
void setText(const QString &key, const QString &text)
QString userScriptPath() const
e.g. "/path/to/klffeynmf.klfuserscript"
int indexOf(char ch, int from) const
klfInput input
The input parameters used to generate this output.
QString number(int n, int base)
void append(const T &value)
QString fromUtf8(const char *str, int size)
static bool saveOutputToDevice(const klfOutput &output, QIODevice *device, const QString &format=QString("PNG"), QString *errorString=NULL)
Saves the given output into the given device.
#define klfWarning(streamableItems)
int toInt(bool *ok, int base) const
#define KLFERR_GSPDF_NOOUTPUT
No PDF file appeared after running 'gs'.
virtual QString generateTemplate(const klfInput &input, const klfSettings &settings)
const_iterator constEnd() const
#define KLFERR_PDFMARKSWRITEFAIL
Error while opening pdfmarks file for writing.
#define KLFERR_TEMPDIR_FAIL
Failed to create the temporary directory.
QByteArray & replace(int pos, int len, const char *after)
#define KLFERR_GSBBOX_NOOUTPUT
Program 'gs' didn't provide any output.
QVariantMap klfMapToVariantMap(const QMap< QString, T > &map)
#define KLFERR_GSPOSTPROC_NOOUTLINEFONTS
'gs' cannot outline fonts: need version <= 9.07 (pswrite -dNOCACHE) or >= 9.15 (ps2write -dNoOutputFo...
#define KLFERR_LATEX_NONORMALEXIT
latex program did not exit properly (program killed) (see also KLFERR_PROGERR_LATEX) ...
QByteArray epsdata
data for an (eps-)postscript file.
#define KLFERR_GSPNG_NORUN
Program 'gs' couldn't be executed to generate PNG.
virtual bool open(OpenMode flags)
#define KLFERR_GSBBOX_NORUN
Program 'gs' cannot be executed to calculate bounding box.
virtual bool open(OpenMode mode)
QByteArray epsdata_raw
data for an (eps-)postscript file.
double height_pt
Width in points of the resulting equation.
#define KLF_DEBUG_TIME_BLOCK(msg)
static QStringList availableSaveFormats(const klfOutput *output=NULL)
Get a list of available output formats.
QByteArray & append(char ch)
#define KLFERR_PROGERR_GSPNG
gs exited with a non-zero status while producing PNG
#define KLFERR_PROGERR_GSPOSTPROC
gs exited with non-zero status while post-processing EPS file (page size, font outlines) ...
#define klfDebugf(arglist)
bool contains(QChar ch, Qt::CaseSensitivity cs) const
#define KLFERR_PROGERR_USERSCRIPT
user wrapper script exited with non-zero status
#define KLFERR_DVIPS_OUTPUTNOBBOX
Error while reading/parsing %BoundingBox: in dvips output.
#define KLFERR_PROGERR_DVIPS
dvips exited with a non-zero status
bool contains(const T &value) const
Definition of class KLFBackend.
const Key key(const T &value, const Key &defaultKey) const
#define KLFERR_NOGSVERSION
Failed to query gs version.
QString & replace(int position, int n, QChar after)
QByteArray toLatin1() const
QString mid(int position, int n) const
bool remove(const T &value)
QImage result
The actual resulting image.
#define KLFERR_GSSVG_OUTPUTREADFAIL
Failed to read SVG file produced by 'gs'.
#define KLFERR_PROGERR_GSSVG
gs exited with non-zero status while producing SVG
#define KLFERR_MISSINGLATEXFORMULA
No LaTeX formula is specified (empty string)
#define KLFERR_NODVIPSPROG
obsolete, same as KLFERR_DVIPS_NORUN
KLF_EXPORT bool operator==(const KLFBackend::klfInput &a, const KLFBackend::klfInput &b)
QString errorstr
An explicit error string.
QTextCodec * codecForName(const QByteArray &name)
KLFBackend::getLatexFormula() result.
QSet< T > fromList(const QList< T > &list)
#define KLFERR_DVIPS_NOOUTPUT
no .eps file appeared after running dvips program
#define KLFERR_GSPDF_NONORMALEXIT
Program 'gs' didn't exit noramally (crashed) while generating PDF (see also KLFERR_PROGERR_GSPDF) ...
#define KLFERR_NOGSPROG
obsolete, same as KLFERR_GSPNG_NORUN
qint64 write(const char *data, qint64 maxSize)
QString fromLatin1(const char *str, int size)
#define KLFERR_GSPOSTPROC_NONORMALEXIT
Program 'gs' crashed while post-processing EPS file (see also KLFERR_PROGERR_GSPOSTPROC) ...
#define KLFERR_GSSVG_NONORMALEXIT
Program 'gs' didn't exit noramally (crashed) while generating SVG (see also KLFERR_PROGERR_GSSVG) ...
int indexOf(const QRegExp &rx, int from) const
#define KLFERR_LATEX_NOOUTPUT
No .dvi file appeared after runnig latex program.
KLF_EXPORT QByteArray klfDataToEscaped(const QByteArray &value_ba, char escapechar)
static bool detectOptionSettings(klfSettings *settings, bool isMainThread=true)
Detects additional options (e.g. klfSettings::wantSVG) that depend on specific program versions...
QByteArray dvidata
The DVI file data outputted by latex executable.
QByteArray epsdata_bbox
data for an (eps-)postscript file.
KLF_EXPORT bool klf_detect_execenv(KLFBackend::klfSettings *settings)
detects any additional settings to environment variables
#define KLF_ASSERT_CONDITION(expr, msg, failaction)
#define KLFERR_GSPOSTPROC_OUTPUTREADFAIL
Couldn't read output provided by 'gs' program after post-processing EPS file.
#define KLFERR_GSBBOX_NOBBOX
Program 'gs' calculating bbox didn't provide parsable output.
#define KLFERR_GSPOSTPROC_NORUN
Program 'gs' cannot be executed to post-process EPS file (page size, outline fonts) ...
QByteArray svgdata
data for a SVG file, if ghostscript supports SVG
QString absolutePath() const
#define KLFERR_GSSVG_NORUN
Program 'gs' couldn't be executed to generate SVG.
#define KLFERR_GSBBOX_NONORMALEXIT
Program 'gs' crashed while calculating bbox (see also KLFERR_PROGERR_GSBBOX)
#define KLFERR_GSPNG_NONORMALEXIT
Program 'gs' didn't exit noramally (crashed) while generating PNG (see also KLFERR_PROGERR_GSPNG) ...
static bool saveOutputToFile(const klfOutput &output, const QString &fileName, const QString &format=QString(), QString *errorString=NULL)
Save the output to image file.
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
KLF_EXPORT QStringList klfCurrentEnvironment()
#define KLFERR_DVIPS_OUTPUTREADFAIL
Error while opening .eps file for reading.
General settings for KLFBackend::getLatexFormula()
qint64 readLine(char *data, qint64 maxSize)
const T value(const Key &key, const T &defaultValue) const
int remove(const Key &key)
QByteArray toUtf8() const