64 uint32_t formulaCount=0;
65 msg(
"Reading formula repository...\n");
68 std::string
prefix(
"\\_form#");
70 bool hasNextLine = !getline(f,readLine).fail();
74 int lineNr = nextLineNr;
77 while ((hasNextLine = !getline(f,readLine).fail()))
81 line +=
"\n" + readLine;
85 static const reg::Ex re_new(R
"(\\_form#(\d+)=(\d+)x(\d+):)");
87 static const reg::Ex re_old(R
"(\\_form#(\d+):)");
96 id = std::stoi(match[1].str());
97 width = std::stoi(match[2].str());
98 height = std::stoi(match[3].str());
99 text = line.substr(match.position()+match.length());
107 msg(
"old formula.repository format detected; forcing upgrade.\n");
108 p->repositoriesValid =
false;
113 warn_uncond(
"{}/formula.repository contains invalid content at line {}: found: '{}'\n",dir,lineNr,line);
114 p->repositoriesValid =
false;
118 auto it =
p->formulaIdMap.find(
id);
120 if (it!=
p->formulaIdMap.end())
122 formula = it->second;
123 if (formula->
text().
str()!=text)
125 msg(
"differences detected between formula.repository files; forcing upgrade.\n");
126 p->repositoriesValid =
false;
134 formula =
p->formulas.add(text,
id,width,height);
135 p->formulaIdMap.emplace(
id,formula);
141 formImgName.
sprintf(
"form_%d",formula->
id());
142 FileInfo fiPng((dir+
"/"+formImgName+
".png").str());
143 FileInfo fiSvg((dir+
"/"+formImgName+
".svg").str());
149 FileInfo fiPngDark((dir+
"/"+formImgName+
"_dark.png").str());
150 FileInfo fiSvgDark((dir+
"/"+formImgName+
"_dark.svg").str());
151 bool isCachedDark = fiPngDark.
exists() || fiSvgDark.
exists();
160 if (formulaCount>0 && formulaCount!=
p->formulas.size())
162 msg(
"differences detected between formula.repository files; forcing upgrade.\n");
163 p->repositoriesValid =
false;
168 p->repositoriesValid =
false;
175 if (!
p->repositoriesValid)
179 p->repositoriesValid =
true;
191 t <<
"\\documentclass{article}\n";
192 t <<
"\\usepackage{iftex}\n";
193 t <<
"\\usepackage{ifthen}\n";
194 t <<
"\\usepackage{epsfig}\n";
195 t <<
"\\usepackage[utf8]{inputenc}\n";
196 t <<
"\\usepackage{xcolor}\n";
200 t <<
"\\color{white}\n";
201 t <<
"\\pagecolor{black}\n";
212 t <<
"\\input{" << stripMacroFile <<
"}\n";
215 t <<
"\\pagestyle{empty}\n";
216 t <<
"\\begin{document}\n";
217 for (
const auto &formula :
p->formulas)
219 int id = formula->id();
223 (mode==
Mode::Dark && !formula->isCachedDark())
227 t << formula->text() <<
"\n\\pagebreak\n\n";
228 formulasToGenerate.push_back(
id);
234 t <<
"\\end{document}\n";
243 const size_t argsLen = 4096;
252 err(
"Problems running latex. Check your installation or look "
253 "for typos in {0}.tex and check {0}.log!\n",fileName);
259 (logFile.
find(
"Rerun to get cross-references right")==-1 && logFile.
find(
"Rerun LaTeX")==-1))
270 const size_t argsLen = 4096;
274 qsnprintf(args,argsLen,
"-q -D 600 -n 1 -p %d -o %s_tmp.ps %s.dvi",pageIndex,
qPrint(formBase),
qPrint(fileName));
277 err(
"Problems running dvips. Check your installation!\n");
285 const size_t argsLen = 4096;
288 qsnprintf(args,argsLen,
"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=bbox %s_tmp.ps 2>%s_tmp.epsi",
299 int *x1,
int *y1,
int *x2,
int *y2,
300 double *x1hi,
double *y1hi,
double *x2hi,
double *y2hi)
302 FileInfo fi((formBase+
"_tmp.epsi").str());
306 int i = eps.
find(
"%%BoundingBox:");
309 sscanf(eps.
data()+i,
"%%%%BoundingBox:%d %d %d %d",x1,y1,x2,y2);
313 err(
"Couldn't extract bounding box from {}_tmp.epsi\n",formBase);
316 i = eps.
find(
"%%HiResBoundingBox:");
319 sscanf(eps.
data()+i,
"%%%%HiResBoundingBox:%lf %lf %lf %lf",x1hi,y1hi,x2hi,y2hi);
323 err(
"Couldn't extract high resolution bounding box from {}_tmp.epsi\n",formBase);
335 double scaleFactor = 1.25;
337 if (zoomFactor<8 || zoomFactor>50) zoomFactor=10;
338 scaleFactor *= zoomFactor/10.0;
343 formula->
setWidth(
static_cast<int>((x2-x1)*scaleFactor+0.5));
344 formula->
setHeight(
static_cast<int>((y2-y1)*scaleFactor+0.5));
351 const size_t argsLen = 4096;
354 qsnprintf(args,argsLen,
"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=pdfwrite"
355 " -o %s_tmp.pdf -c \"[/CropBox [%d %d %d %d] /PAGES pdfmark\" -f %s_tmp.ps",
367 const size_t argsLen = 4096;
370 qsnprintf(args,argsLen,
"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=eps2write"
371 " -o %s_tmp.eps -f %s_tmp.ps",
qPrint(formBase),
qPrint(formBase));
382 const size_t argsLen = 4096;
387 err(
"Problems running pdf2svg. Check your installation!\n");
395 const size_t argsLen = 4096;
398 if (inkscapeVersion == -1)
400 err(
"Problems determining the version of inkscape. Check your installation!\n");
403 else if (inkscapeVersion == 0)
413 err(
"Problems running inkscape. Check your installation!\n");
421 int x1,
int y1,
int x2,
int y2,
422 double x1hi,
double y1hi,
double x2hi,
double y2hi)
428 if (epsIn.is_open() && epsOut.is_open())
431 while (getline(epsIn,line))
433 if (line.rfind(
"%%BoundingBox",0)==0)
435 epsOut <<
"%%BoundingBox: " << std::max(0,x1-1) <<
" " << std::max(0,y1-1) <<
" " << (x2+1) <<
" " << (y2+1) <<
"\n";
437 else if (line.rfind(
"%%HiResBoundingBox",0)==0)
439 epsOut <<
"%%HiResBoundingBox: " << std::max(0.0,x1hi-1.0) <<
" " << std::max(0.0,y1hi-1.0) <<
" " << (x2hi+1.0) <<
" " << (y2hi+1.0) <<
"\n";
443 epsOut << line <<
"\n";
451 err(
"Problems correcting the eps files from {}_tmp.eps to {}_tmp_corr.eps\n",
460 const size_t argsLen = 4096;
462 qsnprintf(args,argsLen,
"-q -dNOSAFER -dBATCH -dNOPAUSE -dEPSCrop -sDEVICE=pngalpha -dGraphicsAlphaBits=4 -dTextAlphaBits=4 "
463 "-r%d -sOutputFile=%s %s_tmp_corr.eps",
static_cast<int>(scaleFactor*72),
qPrint(outFile),
qPrint(formBase));
478 msg(
"Generating image {} for formula\n",outputFile);
485 int x1=0,y1=0,x2=0,y2=0;
486 double x1hi=0.0,y1hi=0.0,x2hi=0.0,y2hi=0.0;
491 if (!
extractBoundingBox(formBase,&x1,&y1,&x2,&y2,&x1hi,&y1hi,&x2hi,&y2hi))
return tempFiles;
497 formBaseLight.
sprintf(
"_form%d",pageNum);
498 if (!
extractBoundingBox(formBaseLight,&x1,&y1,&x2,&y2,&x1hi,&y1hi,&x2hi,&y2hi))
return tempFiles;
519 err(
"Neither 'pdf2svg' nor 'inkscape' present for conversion of formula to 'svg'\n");
523 tempFiles.push_back(formBase.
str()+
"_tmp.pdf");
537 if (!
createPNG(formBase,outputFile,scaleFactor))
return tempFiles;
539 tempFiles.push_back(formBase.
str()+
"_tmp.eps");
540 tempFiles.push_back(formBase.
str()+
"_tmp_corr.eps");
544 tempFiles.push_back(formBase.
str()+
"_tmp.ps");
547 tempFiles.push_back(formBase.
str()+
"_tmp.epsi");
558 if (!formulasToGenerate.empty())
562 auto getFormula = [
this](
int pageNum) ->
Formula *
564 auto it =
p->formulaIdMap.find(pageNum);
565 if (it!=
p->formulaIdMap.end())
573 std::size_t numThreads =
static_cast<std::size_t
>(
Config_getInt(NUM_PROC_THREADS));
577 std::vector< std::future< StringVector > > results;
578 for (
int pageNum : formulasToGenerate)
581 auto formula = getFormula(pageNum);
584 return generateFormula(thisDir,formulaFileName,formula,pageNum,pageIndex,format,hd,mode);
586 results.emplace_back(threadPool.
queue(processFormula));
589 for (
auto &f : results)
592 p->tempFiles.insert(
p->tempFiles.end(),tf.begin(),tf.end());
597 for (
int pageNum : formulasToGenerate)
600 auto formula = getFormula(pageNum);
602 p->tempFiles.insert(
p->tempFiles.end(),tf.begin(),tf.end());
608 p->tempFiles.push_back(formulaFileName.
str()+
".dvi");
609 p->tempFiles.push_back(formulaFileName.
str()+
".log");
610 p->tempFiles.push_back(formulaFileName.
str()+
".aux");
613 p->tempFiles.push_back(formulaFileName.
str()+
".tex");
623 for (
const auto &formula :
p->formulas)
625 t <<
"\\_form#" << formula->id();
626 if (formula->width()!=-1 && formula->height()!=-1)
628 t <<
"=" << formula->width() <<
"x" << formula->height();
630 t <<
":" << formula->text() <<
"\n";
641 term(
"Output directory '{}' does not exist!\n",path);
674 for (
const auto &file :
p->tempFiles)
687 p->formulaIdMap.clear();
692 Formula *formula =
p->formulas.find(formulaText);
695 return formula->
id();
698 int id =
static_cast<int>(
p->formulas.size());
699 formula =
p->formulas.add(formulaText,
id,width,height);
700 p->formulaIdMap.emplace(
id,formula);
706 auto it =
p->formulaIdMap.find(formulaId);
707 return it !=
p->formulaIdMap.end() ? it->second :
nullptr;
713 auto it =
p->formulaIdMap.find(formulaId);
714 return it !=
p->formulaIdMap.end() ? it->second :
nullptr;
721 return !
p->formulas.empty();
734 static int inkscapeVersion = -2;
735 if (inkscapeVersion == -2)
737 QCString inkscapeVersionFile =
"inkscape_version" ;
738 inkscapeVersion = -1;
751 if (inkscapeVersionIn.is_open())
754 while (getline(inkscapeVersionIn,line))
756 size_t dotPos = line.find(
'.');
757 if (line.rfind(
"Inkscape ",0)==0 && dotPos>0)
760 inkscapeVersion = std::stoi(line.substr(9,dotPos-9));
764 inkscapeVersionIn.close();
772 thisDir.
remove(inkscapeVersionFile.
str());
775 return inkscapeVersion;
static bool isFlagSet(const DebugMask mask)
Class representing a directory in the file system.
static std::string currentDirPath()
std::string absPath() const
bool remove(const std::string &path, bool acceptsAbsPath=true) const
static bool setCurrent(const std::string &path)
static IndexList * indexList
Minimal replacement for QFileInfo.
std::string fileName() const
std::string absFilePath() const
Container class representing a vector of objects with keys.
This is an alternative implementation of QCString.
int find(char c, int index=0, bool cs=TRUE) const
bool isEmpty() const
Returns TRUE iff the string is empty.
const std::string & str() const
QCString & sprintf(const char *format,...)
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Text streaming class that buffers data.
void flush()
Flushes the buffer.
Class managing a pool of worker threads.
auto queue(F &&f, Args &&... args) -> std::future< decltype(f(args...))>
Queue the callable function f for the threads to execute.
Class representing a regular expression.
Object representing the matching results.
#define Config_getInt(name)
#define Config_getString(name)
#define Config_getEnum(name)
std::vector< int > IntVector
std::vector< std::string > StringVector
void writeExtraLatexPackages(TextStream &t)
void writeLatexSpecialFormulaChars(TextStream &t)
#define warn_uncond(fmt,...)
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
std::ofstream openOutputStream(const QCString &name, bool append=false)
bool checkForExecutable(const QCString &fileName)
const char * ghostScriptCommand()
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
bool search(std::string_view str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Portable versions of functions that are platform dependent.
const char * qPrint(const char *s)
QCString fileToString(const QCString &name, bool filter, bool isSourceCode)
bool copyFile(const QCString &src, const QCString &dest)
Copies the contents of file with name src to the newly created file with name dest.
A bunch of utility functions.