65 uint32_t formulaCount=0;
66 msg(
"Reading formula repository...\n");
69 std::string
prefix(
"\\_form#");
71 bool hasNextLine = !getline(f,readLine).fail();
75 int lineNr = nextLineNr;
78 while ((hasNextLine = !getline(f,readLine).fail()))
82 line +=
"\n" + readLine;
86 static const reg::Ex re_new(R
"(\\_form#(\d+)=(\d+)x(\d+):)");
88 static const reg::Ex re_old(R
"(\\_form#(\d+):)");
97 id = std::stoi(match[1].str());
98 width = std::stoi(match[2].str());
99 height = std::stoi(match[3].str());
100 text = line.substr(match.position()+match.length());
108 msg(
"old formula.repository format detected; forcing upgrade.\n");
109 p->repositoriesValid =
false;
114 warn_uncond(
"%s/formula.repository contains invalid content at line %d: found: '%s'\n",
qPrint(dir),lineNr,line.c_str());
115 p->repositoriesValid =
false;
119 auto it =
p->formulaIdMap.find(
id);
121 if (it!=
p->formulaIdMap.end())
123 formula = it->second;
124 if (formula->
text().
str()!=text)
126 msg(
"differences detected between formula.repository files; forcing upgrade.\n");
127 p->repositoriesValid =
false;
135 formula =
p->formulas.add(text.c_str(),
id,width,height);
136 p->formulaIdMap.emplace(
id,formula);
142 formImgName.
sprintf(
"form_%d",formula->
id());
143 FileInfo fiPng((dir+
"/"+formImgName+
".png").str());
144 FileInfo fiSvg((dir+
"/"+formImgName+
".svg").str());
150 FileInfo fiPngDark((dir+
"/"+formImgName+
"_dark.png").str());
151 FileInfo fiSvgDark((dir+
"/"+formImgName+
"_dark.svg").str());
152 bool isCachedDark = fiPngDark.
exists() || fiSvgDark.
exists();
161 if (formulaCount>0 && formulaCount!=
p->formulas.size())
163 msg(
"differences detected between formula.repository files; forcing upgrade.\n");
164 p->repositoriesValid =
false;
169 p->repositoriesValid =
false;
176 if (!
p->repositoriesValid)
180 p->repositoriesValid =
true;
192 t <<
"\\documentclass{article}\n";
193 t <<
"\\usepackage{iftex}\n";
194 t <<
"\\usepackage{ifthen}\n";
195 t <<
"\\usepackage{epsfig}\n";
196 t <<
"\\usepackage[utf8]{inputenc}\n";
197 t <<
"\\usepackage{xcolor}\n";
201 t <<
"\\color{white}\n";
202 t <<
"\\pagecolor{black}\n";
213 t <<
"\\input{" << stripMacroFile <<
"}\n";
216 t <<
"\\pagestyle{empty}\n";
217 t <<
"\\begin{document}\n";
218 for (
const auto &formula :
p->formulas)
220 int id = formula->id();
224 (mode==
Mode::Dark && !formula->isCachedDark())
228 t << formula->text() <<
"\n\\pagebreak\n\n";
229 formulasToGenerate.push_back(
id);
235 t <<
"\\end{document}\n";
244 const size_t argsLen = 4096;
253 err(
"Problems running latex. Check your installation or look "
254 "for typos in %s.tex and check %s.log!\n",
qPrint(fileName),
qPrint(fileName));
260 (logFile.
find(
"Rerun to get cross-references right")==-1 && logFile.
find(
"Rerun LaTeX")==-1))
271 const size_t argsLen = 4096;
275 qsnprintf(args,argsLen,
"-q -D 600 -n 1 -p %d -o %s_tmp.ps %s.dvi",pageIndex,
qPrint(formBase),
qPrint(fileName));
278 err(
"Problems running dvips. Check your installation!\n");
286 const size_t argsLen = 4096;
289 qsnprintf(args,argsLen,
"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=bbox %s_tmp.ps 2>%s_tmp.epsi",
300 int *x1,
int *y1,
int *x2,
int *y2,
301 double *x1hi,
double *y1hi,
double *x2hi,
double *y2hi)
303 FileInfo fi((formBase+
"_tmp.epsi").str());
307 int i = eps.
find(
"%%BoundingBox:");
310 sscanf(eps.
data()+i,
"%%%%BoundingBox:%d %d %d %d",x1,y1,x2,y2);
314 err(
"Couldn't extract bounding box from %s_tmp.epsi\n",
qPrint(formBase));
317 i = eps.
find(
"%%HiResBoundingBox:");
320 sscanf(eps.
data()+i,
"%%%%HiResBoundingBox:%lf %lf %lf %lf",x1hi,y1hi,x2hi,y2hi);
324 err(
"Couldn't extract high resolution bounding box from %s_tmp.epsi\n",
qPrint(formBase));
336 double scaleFactor = 1.25;
338 if (zoomFactor<8 || zoomFactor>50) zoomFactor=10;
339 scaleFactor *= zoomFactor/10.0;
344 formula->
setWidth(
static_cast<int>((x2-x1)*scaleFactor+0.5));
345 formula->
setHeight(
static_cast<int>((y2-y1)*scaleFactor+0.5));
352 const size_t argsLen = 4096;
355 qsnprintf(args,argsLen,
"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=pdfwrite"
356 " -o %s_tmp.pdf -c \"[/CropBox [%d %d %d %d] /PAGES pdfmark\" -f %s_tmp.ps",
368 const size_t argsLen = 4096;
371 qsnprintf(args,argsLen,
"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=eps2write"
372 " -o %s_tmp.eps -f %s_tmp.ps",
qPrint(formBase),
qPrint(formBase));
383 const size_t argsLen = 4096;
388 err(
"Problems running pdf2svg. Check your installation!\n");
396 const size_t argsLen = 4096;
399 if (inkscapeVersion == -1)
401 err(
"Problems determining the version of inkscape. Check your installation!\n");
404 else if (inkscapeVersion == 0)
414 err(
"Problems running inkscape. Check your installation!\n");
422 int x1,
int y1,
int x2,
int y2,
423 double x1hi,
double y1hi,
double x2hi,
double y2hi)
429 if (epsIn.is_open() && epsOut.is_open())
432 while (getline(epsIn,line))
434 if (line.rfind(
"%%BoundingBox",0)==0)
436 epsOut <<
"%%BoundingBox: " << std::max(0,x1-1) <<
" " << std::max(0,y1-1) <<
" " << (x2+1) <<
" " << (y2+1) <<
"\n";
438 else if (line.rfind(
"%%HiResBoundingBox",0)==0)
440 epsOut <<
"%%HiResBoundingBox: " << std::max(0.0,x1hi-1.0) <<
" " << std::max(0.0,y1hi-1.0) <<
" " << (x2hi+1.0) <<
" " << (y2hi+1.0) <<
"\n";
444 epsOut << line <<
"\n";
452 err(
"Problems correcting the eps files from %s_tmp.eps to %s_tmp_corr.eps\n",
461 const size_t argsLen = 4096;
463 qsnprintf(args,argsLen,
"-q -dNOSAFER -dBATCH -dNOPAUSE -dEPSCrop -sDEVICE=pngalpha -dGraphicsAlphaBits=4 -dTextAlphaBits=4 "
464 "-r%d -sOutputFile=%s %s_tmp_corr.eps",
static_cast<int>(scaleFactor*72),
qPrint(outFile),
qPrint(formBase));
479 msg(
"Generating image %s for formula\n",
qPrint(outputFile));
486 int x1=0,y1=0,x2=0,y2=0;
487 double x1hi=0.0,y1hi=0.0,x2hi=0.0,y2hi=0.0;
492 if (!
extractBoundingBox(formBase,&x1,&y1,&x2,&y2,&x1hi,&y1hi,&x2hi,&y2hi))
return tempFiles;
498 formBaseLight.
sprintf(
"_form%d",pageNum);
499 if (!
extractBoundingBox(formBaseLight,&x1,&y1,&x2,&y2,&x1hi,&y1hi,&x2hi,&y2hi))
return tempFiles;
520 err(
"Neither 'pdf2svg' nor 'inkscape' present for conversion of formula to 'svg'\n");
524 tempFiles.push_back(formBase.
str()+
"_tmp.pdf");
538 if (!
createPNG(formBase,outputFile,scaleFactor))
return tempFiles;
540 tempFiles.push_back(formBase.
str()+
"_tmp.eps");
541 tempFiles.push_back(formBase.
str()+
"_tmp_corr.eps");
545 tempFiles.push_back(formBase.
str()+
"_tmp.ps");
548 tempFiles.push_back(formBase.
str()+
"_tmp.epsi");
559 if (!formulasToGenerate.empty())
563 auto getFormula = [
this](
int pageNum) ->
Formula *
565 auto it =
p->formulaIdMap.find(pageNum);
566 if (it!=
p->formulaIdMap.end())
574 std::size_t numThreads =
static_cast<std::size_t
>(
Config_getInt(NUM_PROC_THREADS));
578 std::vector< std::future< StringVector > > results;
579 for (
int pageNum : formulasToGenerate)
582 auto formula = getFormula(pageNum);
585 return generateFormula(thisDir,formulaFileName,formula,pageNum,pageIndex,format,hd,mode);
587 results.emplace_back(threadPool.
queue(processFormula));
590 for (
auto &f : results)
593 p->tempFiles.insert(
p->tempFiles.end(),tf.begin(),tf.end());
598 for (
int pageNum : formulasToGenerate)
601 auto formula = getFormula(pageNum);
603 p->tempFiles.insert(
p->tempFiles.end(),tf.begin(),tf.end());
609 p->tempFiles.push_back(formulaFileName.
str()+
".dvi");
610 p->tempFiles.push_back(formulaFileName.
str()+
".log");
611 p->tempFiles.push_back(formulaFileName.
str()+
".aux");
614 p->tempFiles.push_back(formulaFileName.
str()+
".tex");
624 for (
const auto &formula :
p->formulas)
626 t <<
"\\_form#" << formula->id();
627 if (formula->width()!=-1 && formula->height()!=-1)
629 t <<
"=" << formula->width() <<
"x" << formula->height();
631 t <<
":" << formula->text() <<
"\n";
642 term(
"Output directory '%s' does not exist!\n",
qPrint(path));
675 for (
const auto &file :
p->tempFiles)
688 p->formulaIdMap.clear();
693 Formula *formula =
p->formulas.find(formulaText);
696 return formula->
id();
699 int id =
static_cast<int>(
p->formulas.size());
700 formula =
p->formulas.add(formulaText.c_str(),
id,width,height);
701 p->formulaIdMap.emplace(
id,formula);
707 auto it =
p->formulaIdMap.find(formulaId);
708 return it !=
p->formulaIdMap.end() ? it->second :
nullptr;
714 auto it =
p->formulaIdMap.find(formulaId);
715 return it !=
p->formulaIdMap.end() ? it->second :
nullptr;
722 return !
p->formulas.empty();
735 static int inkscapeVersion = -2;
736 if (inkscapeVersion == -2)
738 QCString inkscapeVersionFile =
"inkscape_version" ;
739 inkscapeVersion = -1;
752 if (inkscapeVersionIn.is_open())
755 while (getline(inkscapeVersionIn,line))
757 size_t dotPos = line.find(
'.');
758 if (line.rfind(
"Inkscape ",0)==0 && dotPos>0)
761 inkscapeVersion = std::stoi(line.substr(9,dotPos-9));
765 inkscapeVersionIn.close();
773 thisDir.
remove(inkscapeVersionFile.
str());
776 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)
void msg(const char *fmt,...)
#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.