Doxygen
FormulaManager类 参考

#include <formula.h>

struct  DisplaySize
 
struct  Private
 

Public 类型

enum  Format { Format::Bitmap, Format::Vector }
 
enum  HighDPI { HighDPI::On, HighDPI::Off }
 

Public 成员函数

void readFormulas (const QCString &dir, bool doCompare=false)
 
void clear ()
 
int addFormula (const std::string &formulaText)
 
void generateImages (const QCString &outputDir, Format format, HighDPI hd=HighDPI::Off) const
 
std::string findFormula (int formulaId) const
 
bool hasFormulas () const
 
DisplaySize displaySize (int formulaId) const
 

静态 Public 成员函数

static FormulaManagerinstance ()
 

Private 成员函数

 FormulaManager ()
 

Private 属性

std::unique_ptr< Privatep
 

详细描述

Manager class to handle formulas

在文件 formula.h27 行定义.

成员枚举类型说明

◆ Format

枚举值
Bitmap 
Vector 

在文件 formula.h51 行定义.

◆ HighDPI

枚举值
On 
Off 

在文件 formula.h52 行定义.

构造及析构函数说明

◆ FormulaManager()

FormulaManager::FormulaManager ( )
private

在文件 formula.cpp61 行定义.

61  : p(new Private)
62 {
63 }

成员函数说明

◆ addFormula()

int FormulaManager::addFormula ( const std::string &  formulaText)

在文件 formula.cpp467 行定义.

468 {
469  auto it = p->formulaMap.find(formulaText);
470  if (it!=p->formulaMap.end()) // already stored
471  {
472  return it->second;
473  }
474  // store new formula
475  int id = (int)p->formulas.size();
476  p->formulaMap.insert(std::pair<std::string,int>(formulaText,id));
477  p->formulas.push_back(formulaText);
478  return id;
479 }

引用了 p.

被这些函数引用 readFormulas().

◆ clear()

void FormulaManager::clear ( )

在文件 formula.cpp461 行定义.

462 {
463  p->formulas.clear();
464  p->formulaMap.clear();
465 }

引用了 p.

被这些函数引用 cleanUpDoxygen() , 以及 clearAll().

◆ displaySize()

FormulaManager::DisplaySize FormulaManager::displaySize ( int  formulaId) const

在文件 formula.cpp495 行定义.

496 {
497  return p->getDisplaySize(formulaId);
498 }

引用了 p.

被这些函数引用 HtmlDocVisitor::visit().

◆ findFormula()

std::string FormulaManager::findFormula ( int  formulaId) const

在文件 formula.cpp481 行定义.

482 {
483  if (formulaId>=0 && formulaId<(int)p->formulas.size())
484  {
485  return p->formulas[formulaId];
486  }
487  return std::string();
488 }

引用了 p.

被这些函数引用 DocFormula::DocFormula() , 以及 readFormulas().

◆ generateImages()

void FormulaManager::generateImages ( const QCString outputDir,
Format  format,
HighDPI  hd = HighDPI::Off 
) const

在文件 formula.cpp130 行定义.

131 {
132  Dir d(path.str());
133  // store the original directory
134  if (!d.exists())
135  {
136  term("Output directory '%s' does not exist!\n",qPrint(path));
137  }
138  std::string oldDir = Dir::currentDirPath();
139  QCString macroFile = Config_getString(FORMULA_MACROFILE);
140  QCString stripMacroFile;
141  if (!macroFile.isEmpty())
142  {
143  FileInfo fi(macroFile.str());
144  macroFile=fi.absFilePath();
145  stripMacroFile = fi.fileName();
146  }
147 
148  // go to the html output directory (i.e. path)
149  Dir::setCurrent(d.absPath());
150  Dir thisDir;
151  // generate a latex file containing one formula per page.
152  QCString texName="_formulas.tex";
153  IntVector formulasToGenerate;
154  std::ofstream f(texName.str(),std::ofstream::out | std::ofstream::binary);
155  if (f.is_open())
156  {
157  TextStream t(&f);
158  t << "\\documentclass{article}\n";
159  t << "\\usepackage{ifthen}\n";
160  t << "\\usepackage{epsfig}\n"; // for those who want to include images
161  t << "\\usepackage[utf8]{inputenc}\n"; // looks like some older distributions with newunicode package 1.1 need this option.
164  if (!macroFile.isEmpty())
165  {
166  copyFile(macroFile,stripMacroFile);
167  t << "\\input{" << stripMacroFile << "}\n";
168  }
169  t << "\\pagestyle{empty}\n";
170  t << "\\begin{document}\n";
171  for (int i=0; i<(int)p->formulas.size(); i++)
172  {
173  QCString resultName;
174  resultName.sprintf("form_%d.%s",i,format==Format::Vector?"svg":"png");
175  // only formulas for which no image exists are generated
176  FileInfo fi(resultName.str());
177  if (!fi.exists())
178  {
179  // we force a pagebreak after each formula
180  t << p->formulas[i].c_str() << "\n\\pagebreak\n\n";
181  formulasToGenerate.push_back(i);
182  }
183  Doxygen::indexList->addImageFile(resultName);
184  }
185  t << "\\end{document}\n";
186  t.flush();
187  f.close();
188  }
189  if (!formulasToGenerate.empty()) // there are new formulas
190  {
191  QCString latexCmd = "latex";
192  char args[4096];
194  int rerunCount=1;
195  while (rerunCount<8)
196  {
197  //printf("Running latex...\n");
198  sprintf(args,"-interaction=batchmode _formulas.tex >%s",Portable::devNull());
199  if ((Portable::system(latexCmd,args)!=0) || (Portable::system(latexCmd,args)!=0))
200  {
201  err("Problems running latex. Check your installation or look "
202  "for typos in _formulas.tex and check _formulas.log!\n");
204  Dir::setCurrent(oldDir);
205  return;
206  }
207  // check the log file if we need to run latex again to resolve references
208  QCString logFile = fileToString("_formulas.log");
209  if (logFile.isEmpty() ||
210  (logFile.find("Rerun to get cross-references right")==-1 && logFile.find("Rerun LaTeX")==-1))
211  {
212  break;
213  }
214  rerunCount++;
215  }
217  //printf("Running dvips...\n");
218  int pageIndex=1;
219  for (int pageNum : formulasToGenerate)
220  {
221  msg("Generating image form_%d.%s for formula\n",pageNum,(format==Format::Vector) ? "svg" : "png");
222  QCString formBase;
223  formBase.sprintf("_form%d",pageNum);
224  // run dvips to convert the page with number pageIndex to an
225  // postscript file.
226  sprintf(args,"-q -D 600 -n 1 -p %d -o %s_tmp.ps _formulas.dvi",
227  pageIndex,qPrint(formBase));
229  if (Portable::system("dvips",args)!=0)
230  {
231  err("Problems running dvips. Check your installation!\n");
233  Dir::setCurrent(oldDir);
234  return;
235  }
237 
238  // extract the bounding box for the postscript file
239  sprintf(args,"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=bbox %s_tmp.ps 2>%s_tmp.epsi",
240  qPrint(formBase),qPrint(formBase));
243  {
244  err("Problems running %s. Check your installation!\n",Portable::ghostScriptCommand());
246  Dir::setCurrent(oldDir);
247  return;
248  }
250 
251  // extract the bounding box info from the generate .epsi file
252  int x1=0,y1=0,x2=0,y2=0;
253  FileInfo fi((formBase+"_tmp.epsi").str());
254  if (fi.exists())
255  {
256  QCString eps = fileToString(formBase+"_tmp.epsi");
257  int i = eps.find("%%BoundingBox:");
258  if (i!=-1)
259  {
260  sscanf(eps.data()+i,"%%%%BoundingBox:%d %d %d %d",&x1,&y1,&x2,&y2);
261  }
262  else
263  {
264  err("Couldn't extract bounding box from %s_tmp.epsi",qPrint(formBase));
265  }
266  }
267  //printf("Bounding box [%d %d %d %d]\n",x1,y1,x2,y2);
268 
269  // convert the corrected EPS to a bitmap
270  double scaleFactor = 1.25;
271  int zoomFactor = Config_getInt(FORMULA_FONTSIZE);
272  if (zoomFactor<8 || zoomFactor>50) zoomFactor=10;
273  scaleFactor *= zoomFactor/10.0;
274 
275  int width = (int)((x2-x1)*scaleFactor+0.5);
276  int height = (int)((y2-y1)*scaleFactor+0.5);
277  p->storeDisplaySize(pageNum,width,height);
278 
279  if (format==Format::Vector)
280  {
281  // crop the image to its bounding box
282  sprintf(args,"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=pdfwrite"
283  " -o %s_tmp.pdf -c \"[/CropBox [%d %d %d %d] /PAGES pdfmark\" -f %s_tmp.ps",
284  qPrint(formBase),x1,y1,x2,y2,qPrint(formBase));
287  {
288  err("Problems running %s. Check your installation!\n",Portable::ghostScriptCommand());
290  Dir::setCurrent(oldDir);
291  return;
292  }
294 
295  // if we have pdf2svg available use it to create a SVG image
296  if (Portable::checkForExecutable("pdf2svg"))
297  {
298  sprintf(args,"%s_tmp.pdf form_%d.svg",qPrint(formBase),pageNum);
300  if (Portable::system("pdf2svg",args)!=0)
301  {
302  err("Problems running pdf2svg. Check your installation!\n");
304  Dir::setCurrent(oldDir);
305  return;
306  }
308  }
309  else if (Portable::checkForExecutable("inkscape")) // alternative is to use inkscape
310  {
311  int inkscapeVersion = determineInkscapeVersion(thisDir);
312  if (inkscapeVersion == -1)
313  {
314  err("Problems determining the version of inkscape. Check your installation!\n");
315  Dir::setCurrent(oldDir);
316  return;
317  }
318  else if (inkscapeVersion == 0)
319  {
320  sprintf(args,"-l form_%d.svg -z %s_tmp.pdf 2>%s",pageNum,qPrint(formBase),Portable::devNull());
321  }
322  else // inkscapeVersion >= 1
323  {
324  sprintf(args,"--export-type=svg --export-filename=form_%d.svg %s_tmp.pdf 2>%s",pageNum,qPrint(formBase),Portable::devNull());
325  }
327  if (Portable::system("inkscape",args)!=0)
328  {
329  err("Problems running inkscape. Check your installation!\n");
331  Dir::setCurrent(oldDir);
332  return;
333  }
335  }
336  else
337  {
338  err("Neither 'pdf2svg' nor 'inkscape' present for conversion of formula to 'svg'\n");
339  return;
340  }
341 
342  if (RM_TMP_FILES)
343  {
344  thisDir.remove(formBase.str()+"_tmp.pdf");
345  }
346  }
347  else // format==Format::Bitmap
348  {
349  // crop the image to its bounding box
350  sprintf(args,"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=eps2write"
351  " -o %s_tmp.eps -f %s_tmp.ps",qPrint(formBase),qPrint(formBase));
354  {
355  err("Problems running %s. Check your installation!\n",Portable::ghostScriptCommand());
357  Dir::setCurrent(oldDir);
358  return;
359  }
360 
361  // read back %s_tmp.eps and replace
362  // bounding box values with x1,y1,x2,y2 and remove the HiResBoundingBox
363  std::ifstream epsIn(formBase.str()+"_tmp.eps",std::ifstream::in);
364  std::ofstream epsOut(formBase.str()+"_tmp_corr.eps",std::ofstream::out | std::ofstream::binary);
365  if (epsIn.is_open() && epsOut.is_open())
366  {
367  std::string line;
368  while (getline(epsIn,line))
369  {
370  if (line.rfind("%%BoundingBox",0)==0)
371  {
372  epsOut << "%%BoundingBox: " << x1 << " " << y1 << " " << x2 << " " << y2 << "\n";
373  }
374  else if (line.rfind("%%HiResBoundingBox",0)==0) // skip this one
375  {
376  }
377  else
378  {
379  epsOut << line << "\n";
380  }
381  }
382  epsIn.close();
383  epsOut.close();
384  }
385  else
386  {
387  err("Problems correcting the eps files from %s_tmp.eps to %s_tmp_corr.eps\n",
388  qPrint(formBase),qPrint(formBase));
389  Dir::setCurrent(oldDir);
390  return;
391  }
392 
393  if (hd==HighDPI::On) // for high DPI display it looks much better if the
394  // image resolution is higher than the display resolution
395  {
396  scaleFactor*=2;
397  }
398 
400  sprintf(args,"-q -dNOSAFER -dBATCH -dNOPAUSE -dEPSCrop -sDEVICE=pnggray -dGraphicsAlphaBits=4 -dTextAlphaBits=4 "
401  "-r%d -sOutputFile=form_%d.png %s_tmp_corr.eps",(int)(scaleFactor*72),pageNum,qPrint(formBase));
404  {
405  err("Problems running %s. Check your installation!\n",Portable::ghostScriptCommand());
407  Dir::setCurrent(oldDir);
408  return;
409  }
411 
412  if (RM_TMP_FILES)
413  {
414  thisDir.remove(formBase.str()+"_tmp.eps");
415  thisDir.remove(formBase.str()+"_tmp_corr.eps");
416  }
417  }
418 
419  // remove intermediate image files
420  if (RM_TMP_FILES)
421  {
422  thisDir.remove(formBase.str()+"_tmp.ps");
423  thisDir.remove(formBase.str()+"_tmp.epsi");
424  }
425  pageIndex++;
426  }
427  // remove intermediate files produced by latex
428  if (RM_TMP_FILES)
429  {
430  thisDir.remove("_formulas.dvi");
431  thisDir.remove("_formulas.log"); // keep file in case of errors
432  thisDir.remove("_formulas.aux");
433  }
434  }
435  // remove the latex file itself
436  if (RM_TMP_FILES) thisDir.remove("_formulas.tex");
437 
438  // write/update the formula repository so we know what text the
439  // generated images represent (we use this next time to avoid regeneration
440  // of the images, and to avoid forcing the user to delete all images in order
441  // to let a browser refresh the images).
442  f.open("formula.repository",std::ofstream::out | std::ofstream::binary);
443  if (f.is_open())
444  {
445  TextStream t(&f);
446  for (int i=0; i<(int)p->formulas.size(); i++)
447  {
448  DisplaySize size = p->getDisplaySize(i);
449  t << "\\_form#" << i;
450  if (size.width!=-1 && size.height!=-1)
451  {
452  t << "=" << size.width << "x" << size.height;
453  }
454  t << ":" << p->formulas[i].c_str() << "\n";
455  }
456  }
457  // reset the directory to the original location.
458  Dir::setCurrent(oldDir);
459 }

引用了 FileInfo::absFilePath(), Dir::absPath(), IndexList::addImageFile(), Portable::checkForExecutable(), Config_getInt, Config_getString, copyFile(), Dir::currentDirPath(), QCString::data(), determineInkscapeVersion(), Portable::devNull(), err(), FileInfo::exists(), Dir::exists(), FileInfo::fileName(), fileToString(), QCString::find(), TextStream::flush(), Portable::ghostScriptCommand(), FormulaManager::DisplaySize::height, Doxygen::indexList, QCString::isEmpty(), msg(), On, p, qPrint(), Dir::remove(), RM_TMP_FILES, Dir::setCurrent(), QCString::sprintf(), QCString::str(), Portable::system(), Portable::sysTimerStart(), Portable::sysTimerStop(), term(), Vector, FormulaManager::DisplaySize::width, writeExtraLatexPackages() , 以及 writeLatexSpecialFormulaChars().

被这些函数引用 generateOutput().

◆ hasFormulas()

bool FormulaManager::hasFormulas ( ) const

在文件 formula.cpp490 行定义.

491 {
492  return !p->formulas.empty();
493 }

引用了 p.

被这些函数引用 generateOutput().

◆ instance()

FormulaManager & FormulaManager::instance ( )
static

在文件 formula.cpp65 行定义.

66 {
67  static FormulaManager fm;
68  return fm;
69 }

被这些函数引用 cleanUpDoxygen(), clearAll(), DocFormula::DocFormula(), generateOutput(), parseInput(), readFormulas() , 以及 HtmlDocVisitor::visit().

◆ readFormulas()

void FormulaManager::readFormulas ( const QCString dir,
bool  doCompare = false 
)

在文件 formula.cpp71 行定义.

72 {
73  std::ifstream f(dir.str()+"/formula.repository",std::ifstream::in);
74  if (f.is_open())
75  {
76  uint formulaCount=0;
77  msg("Reading formula repository...\n");
78  std::string line;
79  int lineNr=1;
80  while (getline(f,line))
81  {
82  // format: \_form#<digits>=<digits>x<digits>:formula
83  size_t hi=line.find('#');
84  size_t ei=line.find('=');
85  size_t se=line.find(':'); // find name and text separator.
86  if (ei==std::string::npos || hi==std::string::npos || se==std::string::npos || hi>se || ei<hi || ei>se)
87  {
88  warn_uncond("%s/formula.repository is corrupted at line %d!\n",qPrint(dir),lineNr);
89  break;
90  }
91  else
92  {
93  std::string formName = line.substr(0,se); // '\_form#<digits>=<digits>x<digits>' part
94  std::string formText = line.substr(se+1); // 'formula' part
95  int w=-1,h=-1;
96  size_t xi=formName.find('x',ei);
97  if (xi!=std::string::npos)
98  {
99  w=std::stoi(formName.substr(ei+1,xi-ei-1)); // digits from '=<digits>x' part as int
100  h=std::stoi(formName.substr(xi+1)); // digits from 'x<digits>' part as int
101  }
102  formName = formName.substr(0,ei); // keep only the '\_form#<digits>' part
103  if (doCompare)
104  {
105  int formId = std::stoi(formName.substr(hi+1));
106  std::string storedFormText = FormulaManager::instance().findFormula(formId);
107  if (storedFormText!=formText)
108  {
109  term("discrepancy between formula repositories! Remove "
110  "formula.repository and from_* files from output directories.\n");
111  }
112  formulaCount++;
113  }
114  int id = addFormula(formText);
115  if (w!=-1 && h!=-1)
116  {
117  p->storeDisplaySize(id,w,h);
118  }
119  }
120  lineNr++;
121  }
122  if (doCompare && formulaCount!=p->formulas.size())
123  {
124  term("size discrepancy between formula repositories! Remove "
125  "formula.repository and from_* files from output directories.\n");
126  }
127  }
128 }

引用了 addFormula(), findFormula(), instance(), msg(), p, qPrint(), QCString::str(), term() , 以及 warn_uncond().

被这些函数引用 parseInput().

类成员变量说明

◆ p

std::unique_ptr<Private> FormulaManager::p
private

在文件 formula.h63 行定义.

被这些函数引用 addFormula(), clear(), displaySize(), findFormula(), generateImages(), hasFormulas() , 以及 readFormulas().


该类的文档由以下文件生成:
Dir::currentDirPath
static std::string currentDirPath()
Definition: dir.cpp:282
Dir::remove
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition: dir.cpp:256
Dir
Class representing a directory in the file system
Definition: dir.h:68
Private
@ Private
Definition: types.h:26
Portable::devNull
const char * devNull()
Definition: portable.cpp:595
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
Doxygen::indexList
static IndexList * indexList
Definition: doxygen.h:114
FormulaManager::p
std::unique_ptr< Private > p
Definition: formula.h:63
copyFile
bool copyFile(const QCString &src, const QCString &dest)
Copies the contents of file with name src to the newly created file with name dest.
Definition: util.cpp:6439
FormulaManager::Format::Vector
@ Vector
FormulaManager::instance
static FormulaManager & instance()
Definition: formula.cpp:65
QCString::str
std::string str() const
Definition: qcstring.h:442
IntVector
std::vector< int > IntVector
Definition: containers.h:36
err
void err(const char *fmt,...)
Definition: message.cpp:203
TextStream
Text streaming class that buffers data.
Definition: textstream.h:33
QCString::find
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:38
determineInkscapeVersion
static int determineInkscapeVersion(Dir &thisDir)
Definition: formula.cpp:502
uint
unsigned uint
Definition: qcstring.h:40
warn_uncond
void warn_uncond(const char *fmt,...)
Definition: message.cpp:194
Config_getInt
#define Config_getInt(name)
Definition: config.h:34
Portable::ghostScriptCommand
const char * ghostScriptCommand()
Definition: portable.cpp:410
Portable::sysTimerStart
void sysTimerStart()
Definition: portable.cpp:470
IndexList::addImageFile
void addImageFile(const QCString &name)
Definition: index.h:105
FormulaManager::HighDPI::On
@ On
fileToString
QCString fileToString(const QCString &name, bool filter, bool isSourceCode)
Definition: util.cpp:1394
Portable::system
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
Definition: portable.cpp:42
Dir::setCurrent
static bool setCurrent(const std::string &path)
Definition: dir.cpp:290
writeLatexSpecialFormulaChars
void writeLatexSpecialFormulaChars(TextStream &t)
Definition: util.cpp:7084
RM_TMP_FILES
#define RM_TMP_FILES
Definition: formula.cpp:38
writeExtraLatexPackages
void writeExtraLatexPackages(TextStream &t)
Definition: util.cpp:7066
Portable::checkForExecutable
bool checkForExecutable(const QCString &fileName)
Definition: portable.cpp:396
FormulaManager
Definition: formula.h:27
msg
void msg(const char *fmt,...)
Definition: message.cpp:53
term
void term(const char *fmt,...)
Definition: message.cpp:220
FileInfo
Minimal replacement for QFileInfo.
Definition: fileinfo.h:22
qPrint
const char * qPrint(const char *s)
Definition: qcstring.h:589
Config_getString
#define Config_getString(name)
Definition: config.h:32
FormulaManager::addFormula
int addFormula(const std::string &formulaText)
Definition: formula.cpp:467
Portable::sysTimerStop
void sysTimerStop()
Definition: portable.cpp:475
QCString::data
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string
Definition: qcstring.h:153
FormulaManager::findFormula
std::string findFormula(int formulaId) const
Definition: formula.cpp:481
QCString::sprintf
QCString & sprintf(const char *format,...)
Definition: qcstring.cpp:24
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108