Doxygen
Loading...
Searching...
No Matches
formula.cpp File Reference
#include <map>
#include <vector>
#include <string>
#include <utility>
#include "formula.h"
#include "message.h"
#include "config.h"
#include "util.h"
#include "portable.h"
#include "image.h"
#include "fileinfo.h"
#include "dir.h"
#include "regex.h"
#include "linkedmap.h"
#include "threadpool.h"
#include "latexgen.h"
#include "debug.h"
#include "doxygen.h"
#include "indexlist.h"
Include dependency graph for formula.cpp:

Go to the source code of this file.

Classes

struct  FormulaManager::Private

Functions

static int determineInkscapeVersion (const Dir &thisDir)
static bool createDVIFile (const QCString &fileName)
static bool createPostscriptFile (const QCString &fileName, const QCString &formBase, int pageIndex)
static bool createEPSbboxFile (const QCString &formBase)
static bool extractBoundingBox (const QCString &formBase, int *x1, int *y1, int *x2, int *y2, double *x1hi, double *y1hi, double *x2hi, double *y2hi)
static double updateFormulaSize (Formula *formula, int x1, int y1, int x2, int y2)
static bool createCroppedPDF (const QCString &formBase, int x1, int y1, int x2, int y2)
static bool createCroppedEPS (const QCString &formBase)
static bool createSVGFromPDF (const QCString &formBase, const QCString &outFile)
static bool createSVGFromPDFviaInkscape (const Dir &thisDir, const QCString &formBase, const QCString &outFile)
static bool updateEPSBoundingBox (const QCString &formBase, int x1, int y1, int x2, int y2, double x1hi, double y1hi, double x2hi, double y2hi)
static bool createPNG (const QCString &formBase, const QCString &outFile, double scaleFactor)
static StringVector generateFormula (const Dir &thisDir, const QCString &formulaFileName, Formula *formula, int pageNum, int pageIndex, FormulaManager::Format format, FormulaManager::HighDPI hd, FormulaManager::Mode mode)

Variables

static std::mutex g_formulaUpdateMutex
static std::mutex g_inkscapeDetectionMutex

Function Documentation

◆ createCroppedEPS()

bool createCroppedEPS ( const QCString & formBase)
static

Definition at line 365 of file formula.cpp.

366{
367 const size_t argsLen = 4096;
368 char args[argsLen];
369 // crop the image to its bounding box
370 qsnprintf(args,argsLen,"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=eps2write"
371 " -o %s_tmp.eps -f %s_tmp.ps",qPrint(formBase),qPrint(formBase));
373 {
374 err("Problems running {}. Check your installation!\n",Portable::ghostScriptCommand());
375 return false;
376 }
377 return true;
378}
#define err(fmt,...)
Definition message.h:127
const char * ghostScriptCommand()
Definition portable.cpp:437
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
Definition portable.cpp:105
#define qsnprintf
Definition qcstring.h:49
const char * qPrint(const char *s)
Definition qcstring.h:687

References err, Portable::ghostScriptCommand(), qPrint(), qsnprintf, and Portable::system().

Referenced by generateFormula().

◆ createCroppedPDF()

bool createCroppedPDF ( const QCString & formBase,
int x1,
int y1,
int x2,
int y2 )
static

Definition at line 349 of file formula.cpp.

350{
351 const size_t argsLen = 4096;
352 char args[argsLen];
353 // crop the image to its bounding box
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",
356 qPrint(formBase),x1,y1,x2,y2,qPrint(formBase));
358 {
359 err("Problems running {}. Check your installation!\n",Portable::ghostScriptCommand());
360 return false;
361 }
362 return true;
363}

References err, Portable::ghostScriptCommand(), qPrint(), qsnprintf, and Portable::system().

Referenced by generateFormula().

◆ createDVIFile()

bool createDVIFile ( const QCString & fileName)
static

Definition at line 240 of file formula.cpp.

241{
242 QCString latexCmd = "latex";
243 const size_t argsLen = 4096;
244 char args[argsLen];
245 int rerunCount=1;
246 while (rerunCount<8)
247 {
248 //printf("Running latex...\n");
249 qsnprintf(args,argsLen,"-interaction=batchmode %s >%s",qPrint(fileName),Portable::devNull());
250 if ((Portable::system(latexCmd,args)!=0) || (Portable::system(latexCmd,args)!=0))
251 {
252 err("Problems running latex. Check your installation or look "
253 "for typos in {0}.tex and check {0}.log!\n",fileName);
254 return false;
255 }
256 // check the log file if we need to run latex again to resolve references
257 QCString logFile = fileToString(fileName+".log");
258 if (logFile.isEmpty() ||
259 (logFile.find("Rerun to get cross-references right")==-1 && logFile.find("Rerun LaTeX")==-1))
260 {
261 break;
262 }
263 rerunCount++;
264 }
265 return true;
266}
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
const char * devNull()
Definition portable.cpp:614
QCString fileToString(const QCString &name, bool filter, bool isSourceCode)
Definition util.cpp:1494

References Portable::devNull(), err, fileToString(), QCString::find(), QCString::isEmpty(), qPrint(), qsnprintf, and Portable::system().

Referenced by FormulaManager::createFormulasTexFile().

◆ createEPSbboxFile()

bool createEPSbboxFile ( const QCString & formBase)
static

Definition at line 283 of file formula.cpp.

284{
285 const size_t argsLen = 4096;
286 char args[argsLen];
287 // extract the bounding box for the postscript file
288 qsnprintf(args,argsLen,"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=bbox %s_tmp.ps 2>%s_tmp.epsi",
289 qPrint(formBase),qPrint(formBase));
291 {
292 err("Problems running {}. Check your installation!\n",Portable::ghostScriptCommand());
293 return false;
294 }
295 return true;
296}

References err, Portable::ghostScriptCommand(), qPrint(), qsnprintf, and Portable::system().

Referenced by generateFormula().

◆ createPNG()

bool createPNG ( const QCString & formBase,
const QCString & outFile,
double scaleFactor )
static

Definition at line 458 of file formula.cpp.

459{
460 const size_t argsLen = 4096;
461 char args[argsLen];
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));
465 {
466 err("Problems running {}. Check your installation!\n",Portable::ghostScriptCommand());
467 return false;
468 }
469 return true;
470}

References err, Portable::ghostScriptCommand(), qPrint(), qsnprintf, and Portable::system().

Referenced by generateFormula().

◆ createPostscriptFile()

bool createPostscriptFile ( const QCString & fileName,
const QCString & formBase,
int pageIndex )
static

Definition at line 268 of file formula.cpp.

269{
270 const size_t argsLen = 4096;
271 char args[argsLen];
272 // run dvips to convert the page with number pageIndex to an
273 // postscript file.
274 qsnprintf(args,argsLen,"-q -D 600 -n 1 -p %d -o %s_tmp.ps %s.dvi",pageIndex,qPrint(formBase),qPrint(fileName));
275 if (Portable::system("dvips",args)!=0)
276 {
277 err("Problems running dvips. Check your installation!\n");
278 return false;
279 }
280 return true;
281}

References err, qPrint(), qsnprintf, and Portable::system().

Referenced by generateFormula().

◆ createSVGFromPDF()

bool createSVGFromPDF ( const QCString & formBase,
const QCString & outFile )
static

Definition at line 380 of file formula.cpp.

381{
382 const size_t argsLen = 4096;
383 char args[argsLen];
384 qsnprintf(args,argsLen,"%s_tmp.pdf %s",qPrint(formBase),qPrint(outFile));
385 if (Portable::system("pdf2svg",args)!=0)
386 {
387 err("Problems running pdf2svg. Check your installation!\n");
388 return false;
389 }
390 return true;
391}

References err, qPrint(), qsnprintf, and Portable::system().

Referenced by generateFormula().

◆ createSVGFromPDFviaInkscape()

bool createSVGFromPDFviaInkscape ( const Dir & thisDir,
const QCString & formBase,
const QCString & outFile )
static

Definition at line 393 of file formula.cpp.

394{
395 const size_t argsLen = 4096;
396 char args[argsLen];
397 int inkscapeVersion = determineInkscapeVersion(thisDir);
398 if (inkscapeVersion == -1)
399 {
400 err("Problems determining the version of inkscape. Check your installation!\n");
401 return false;
402 }
403 else if (inkscapeVersion == 0)
404 {
405 qsnprintf(args,argsLen,"-l %s -z %s_tmp.pdf 2>%s",qPrint(outFile),qPrint(formBase),Portable::devNull());
406 }
407 else // inkscapeVersion >= 1
408 {
409 qsnprintf(args,argsLen,"--export-type=svg --export-filename=%s %s_tmp.pdf 2>%s",qPrint(outFile),qPrint(formBase),Portable::devNull());
410 }
411 if (Portable::system("inkscape",args)!=0)
412 {
413 err("Problems running inkscape. Check your installation!\n");
414 return false;
415 }
416 return true;
417}
static int determineInkscapeVersion(const Dir &thisDir)
Definition formula.cpp:728

References determineInkscapeVersion(), Portable::devNull(), err, qPrint(), qsnprintf, and Portable::system().

Referenced by generateFormula().

◆ determineInkscapeVersion()

int determineInkscapeVersion ( const Dir & thisDir)
static

Definition at line 728 of file formula.cpp.

729{
730 std::lock_guard<std::mutex> lock(g_inkscapeDetectionMutex);
731 // The command line interface (CLI) of Inkscape 1.0 has changed in comparison to
732 // previous versions. In order to invokine Inkscape, the used version is detected
733 // and based on the version the right syntax of the CLI is chosen.
734 static int inkscapeVersion = -2;
735 if (inkscapeVersion == -2) // initial one time version check
736 {
737 QCString inkscapeVersionFile = "inkscape_version" ;
738 inkscapeVersion = -1;
739 QCString args = "-z --version >"+inkscapeVersionFile+" 2>"+Portable::devNull();
740 if (Portable::system("inkscape",args)!=0)
741 {
742 // looks like the old syntax gave problems, lets try the new syntax
743 args = " --version >"+inkscapeVersionFile+" 2>"+Portable::devNull();
744 if (Portable::system("inkscape",args)!=0)
745 {
746 return -1;
747 }
748 }
749 // read version file and determine major version
750 std::ifstream inkscapeVersionIn = Portable::openInputStream(inkscapeVersionFile);
751 if (inkscapeVersionIn.is_open())
752 {
753 std::string line;
754 while (getline(inkscapeVersionIn,line))
755 {
756 size_t dotPos = line.find('.');
757 if (line.rfind("Inkscape ",0)==0 && dotPos>0)
758 {
759 // get major version
760 inkscapeVersion = std::stoi(line.substr(9,dotPos-9));
761 break;
762 }
763 }
764 inkscapeVersionIn.close();
765 }
766 else // failed to open version file
767 {
768 return -1;
769 }
771 {
772 thisDir.remove(inkscapeVersionFile.str());
773 }
774 }
775 return inkscapeVersion;
776}
@ Formula
Definition debug.h:33
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:314
const std::string & str() const
Definition qcstring.h:552
static std::mutex g_inkscapeDetectionMutex
Definition formula.cpp:724
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:659

References Portable::devNull(), Debug::Formula, g_inkscapeDetectionMutex, Debug::isFlagSet(), Portable::openInputStream(), Dir::remove(), QCString::str(), and Portable::system().

Referenced by createSVGFromPDFviaInkscape().

◆ extractBoundingBox()

bool extractBoundingBox ( const QCString & formBase,
int * x1,
int * y1,
int * x2,
int * y2,
double * x1hi,
double * y1hi,
double * x2hi,
double * y2hi )
static

Definition at line 298 of file formula.cpp.

301{
302 FileInfo fi((formBase+"_tmp.epsi").str());
303 if (fi.exists())
304 {
305 QCString eps = fileToString(formBase+"_tmp.epsi");
306 int i = eps.find("%%BoundingBox:");
307 if (i!=-1)
308 {
309 sscanf(eps.data()+i,"%%%%BoundingBox:%d %d %d %d",x1,y1,x2,y2);
310 }
311 else
312 {
313 err("Couldn't extract bounding box from {}_tmp.epsi\n",formBase);
314 return false;
315 }
316 i = eps.find("%%HiResBoundingBox:");
317 if (i!=-1)
318 {
319 sscanf(eps.data()+i,"%%%%HiResBoundingBox:%lf %lf %lf %lf",x1hi,y1hi,x2hi,y2hi);
320 }
321 else
322 {
323 err("Couldn't extract high resolution bounding box from {}_tmp.epsi\n",formBase);
324 return false;
325 }
326 }
327 //printf("Bounding box [%d %d %d %d]\n",x1,y1,x2,y2);
328 return true;
329}
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
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:172

References QCString::data(), err, FileInfo::exists(), fileToString(), and QCString::find().

Referenced by generateFormula(), and DotRunner::readBoundingBox().

◆ generateFormula()

StringVector generateFormula ( const Dir & thisDir,
const QCString & formulaFileName,
Formula * formula,
int pageNum,
int pageIndex,
FormulaManager::Format format,
FormulaManager::HighDPI hd,
FormulaManager::Mode mode )
static

Definition at line 472 of file formula.cpp.

474{
475 StringVector tempFiles;
476 QCString outputFile;
477 outputFile.sprintf("form_%d%s.%s",pageNum, mode==FormulaManager::Mode::Light?"":"_dark", format==FormulaManager::Format::Vector?"svg":"png");
478 msg("Generating image {} for formula\n",outputFile);
479
480 QCString formBase;
481 formBase.sprintf("_form%d%s",pageNum,mode==FormulaManager::Mode::Light?"":"_dark");
482
483 if (!createPostscriptFile(formulaFileName,formBase,pageIndex)) return tempFiles;
484
485 int x1=0,y1=0,x2=0,y2=0;
486 double x1hi=0.0,y1hi=0.0,x2hi=0.0,y2hi=0.0;
488 {
489 if (!createEPSbboxFile(formBase)) return tempFiles;
490 // extract the bounding box info from the generated .epsi file
491 if (!extractBoundingBox(formBase,&x1,&y1,&x2,&y2,&x1hi,&y1hi,&x2hi,&y2hi)) return tempFiles;
492 }
493 else // for dark images the bounding box is wrong (includes the black) so
494 // use the bounding box of the light image instead.
495 {
496 QCString formBaseLight;
497 formBaseLight.sprintf("_form%d",pageNum);
498 if (!extractBoundingBox(formBaseLight,&x1,&y1,&x2,&y2,&x1hi,&y1hi,&x2hi,&y2hi)) return tempFiles;
499 }
500
501 // convert the corrected EPS to a bitmap
502 double scaleFactor = updateFormulaSize(formula,x1,y1,x2,y2);
503
505 {
506 if (!createCroppedPDF(formBase,x1,y1,x2,y2)) return tempFiles;
507
508 // if we have pdf2svg available use it to create a SVG image
509 if (Portable::checkForExecutable("pdf2svg"))
510 {
511 createSVGFromPDF(formBase,outputFile);
512 }
513 else if (Portable::checkForExecutable("inkscape")) // alternative is to use inkscape
514 {
515 createSVGFromPDFviaInkscape(thisDir,formBase,outputFile);
516 }
517 else
518 {
519 err("Neither 'pdf2svg' nor 'inkscape' present for conversion of formula to 'svg'\n");
520 return tempFiles;
521 }
522
523 tempFiles.push_back(formBase.str()+"_tmp.pdf");
524 }
525 else // format==FormulaManager::Format::Bitmap
526 {
527 if (!createCroppedEPS(formBase)) return tempFiles;
528
529 if (!updateEPSBoundingBox(formBase,x1,y1,x2,y2,x1hi,y1hi,x2hi,y2hi)) return tempFiles;
530
531 if (hd==FormulaManager::HighDPI::On) // for high DPI display it looks much better if the
532 // image resolution is higher than the display resolution
533 {
534 scaleFactor*=2;
535 }
536
537 if (!createPNG(formBase,outputFile,scaleFactor)) return tempFiles;
538
539 tempFiles.push_back(formBase.str()+"_tmp.eps");
540 tempFiles.push_back(formBase.str()+"_tmp_corr.eps");
541 }
542
543 // remove intermediate image files
544 tempFiles.push_back(formBase.str()+"_tmp.ps");
546 {
547 tempFiles.push_back(formBase.str()+"_tmp.epsi");
548 }
549 return tempFiles;
550}
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
std::vector< std::string > StringVector
Definition containers.h:33
static bool createSVGFromPDFviaInkscape(const Dir &thisDir, const QCString &formBase, const QCString &outFile)
Definition formula.cpp:393
static bool createPNG(const QCString &formBase, const QCString &outFile, double scaleFactor)
Definition formula.cpp:458
static bool createCroppedEPS(const QCString &formBase)
Definition formula.cpp:365
static bool createPostscriptFile(const QCString &fileName, const QCString &formBase, int pageIndex)
Definition formula.cpp:268
static double updateFormulaSize(Formula *formula, int x1, int y1, int x2, int y2)
Definition formula.cpp:333
static bool createCroppedPDF(const QCString &formBase, int x1, int y1, int x2, int y2)
Definition formula.cpp:349
static bool createEPSbboxFile(const QCString &formBase)
Definition formula.cpp:283
static bool extractBoundingBox(const QCString &formBase, int *x1, int *y1, int *x2, int *y2, double *x1hi, double *y1hi, double *x2hi, double *y2hi)
Definition formula.cpp:298
static bool createSVGFromPDF(const QCString &formBase, const QCString &outFile)
Definition formula.cpp:380
static bool updateEPSBoundingBox(const QCString &formBase, int x1, int y1, int x2, int y2, double x1hi, double y1hi, double x2hi, double y2hi)
Definition formula.cpp:420
#define msg(fmt,...)
Definition message.h:94
bool checkForExecutable(const QCString &fileName)
Definition portable.cpp:423

References Portable::checkForExecutable(), createCroppedEPS(), createCroppedPDF(), createEPSbboxFile(), createPNG(), createPostscriptFile(), createSVGFromPDF(), createSVGFromPDFviaInkscape(), err, extractBoundingBox(), FormulaManager::Light, msg, FormulaManager::On, QCString::sprintf(), QCString::str(), updateEPSBoundingBox(), updateFormulaSize(), and FormulaManager::Vector.

Referenced by FormulaManager::createFormulasTexFile().

◆ updateEPSBoundingBox()

bool updateEPSBoundingBox ( const QCString & formBase,
int x1,
int y1,
int x2,
int y2,
double x1hi,
double y1hi,
double x2hi,
double y2hi )
static

Definition at line 420 of file formula.cpp.

423{
424 // read back %s_tmp.eps and replace
425 // bounding box values with x1,y1,x2,y2 and remove the HiResBoundingBox
426 std::ifstream epsIn = Portable::openInputStream(formBase+"_tmp.eps");
427 std::ofstream epsOut = Portable::openOutputStream(formBase+"_tmp_corr.eps");
428 if (epsIn.is_open() && epsOut.is_open())
429 {
430 std::string line;
431 while (getline(epsIn,line))
432 {
433 if (line.rfind("%%BoundingBox",0)==0)
434 {
435 epsOut << "%%BoundingBox: " << std::max(0,x1-1) << " " << std::max(0,y1-1) << " " << (x2+1) << " " << (y2+1) << "\n";
436 }
437 else if (line.rfind("%%HiResBoundingBox",0)==0)
438 {
439 epsOut << "%%HiResBoundingBox: " << std::max(0.0,x1hi-1.0) << " " << std::max(0.0,y1hi-1.0) << " " << (x2hi+1.0) << " " << (y2hi+1.0) << "\n";
440 }
441 else
442 {
443 epsOut << line << "\n";
444 }
445 }
446 epsIn.close();
447 epsOut.close();
448 }
449 else
450 {
451 err("Problems correcting the eps files from {}_tmp.eps to {}_tmp_corr.eps\n",
452 formBase,formBase);
453 return false;
454 }
455 return true;
456}
std::ofstream openOutputStream(const QCString &name, bool append=false)
Definition portable.cpp:648

References err, Portable::openInputStream(), and Portable::openOutputStream().

Referenced by generateFormula().

◆ updateFormulaSize()

double updateFormulaSize ( Formula * formula,
int x1,
int y1,
int x2,
int y2 )
static

Definition at line 333 of file formula.cpp.

334{
335 double scaleFactor = 1.25;
336 int zoomFactor = Config_getInt(FORMULA_FONTSIZE);
337 if (zoomFactor<8 || zoomFactor>50) zoomFactor=10;
338 scaleFactor *= zoomFactor/10.0;
339
340 if (formula)
341 {
342 std::lock_guard<std::mutex> lock(g_formulaUpdateMutex);
343 formula->setWidth(static_cast<int>((x2-x1)*scaleFactor+0.5));
344 formula->setHeight(static_cast<int>((y2-y1)*scaleFactor+0.5));
345 }
346 return scaleFactor;
347}
void setHeight(int height)
Definition formula.h:41
void setWidth(int width)
Definition formula.h:40
#define Config_getInt(name)
Definition config.h:34
static std::mutex g_formulaUpdateMutex
Definition formula.cpp:331

References Config_getInt, g_formulaUpdateMutex, Formula::setHeight(), and Formula::setWidth().

Referenced by generateFormula().

Variable Documentation

◆ g_formulaUpdateMutex

std::mutex g_formulaUpdateMutex
static

Definition at line 331 of file formula.cpp.

Referenced by updateFormulaSize().

◆ g_inkscapeDetectionMutex

std::mutex g_inkscapeDetectionMutex
static

Definition at line 724 of file formula.cpp.

Referenced by determineInkscapeVersion().