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()

static bool createCroppedEPS ( const QCString & formBase)
static

Definition at line 366 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ createCroppedPDF()

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

Definition at line 350 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ createDVIFile()

static bool createDVIFile ( const QCString & fileName)
static

Definition at line 241 of file formula.cpp.

242{
243 QCString latexCmd = "latex";
244 const size_t argsLen = 4096;
245 char args[argsLen];
246 int rerunCount=1;
247 while (rerunCount<8)
248 {
249 //printf("Running latex...\n");
250 qsnprintf(args,argsLen,"-interaction=batchmode %s >%s",qPrint(fileName),Portable::devNull());
251 if ((Portable::system(latexCmd,args)!=0) || (Portable::system(latexCmd,args)!=0))
252 {
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));
255 return false;
256 }
257 // check the log file if we need to run latex again to resolve references
258 QCString logFile = fileToString(fileName+".log");
259 if (logFile.isEmpty() ||
260 (logFile.find("Rerun to get cross-references right")==-1 && logFile.find("Rerun LaTeX")==-1))
261 {
262 break;
263 }
264 rerunCount++;
265 }
266 return true;
267}
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:150
const char * devNull()
Definition portable.cpp:631
QCString fileToString(const QCString &name, bool filter, bool isSourceCode)
Definition util.cpp:1414

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

Referenced by FormulaManager::createFormulasTexFile().

◆ createEPSbboxFile()

static bool createEPSbboxFile ( const QCString & formBase)
static

Definition at line 284 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ createPNG()

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

Definition at line 459 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ createPostscriptFile()

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

Definition at line 269 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ createSVGFromPDF()

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

Definition at line 381 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ createSVGFromPDFviaInkscape()

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

Definition at line 394 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ determineInkscapeVersion()

static int determineInkscapeVersion ( const Dir & thisDir)
static

Definition at line 729 of file formula.cpp.

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

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

Referenced by createSVGFromPDFviaInkscape().

◆ extractBoundingBox()

static 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 299 of file formula.cpp.

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

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

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

◆ generateFormula()

static 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 473 of file formula.cpp.

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

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

Referenced by FormulaManager::createFormulasTexFile().

◆ updateEPSBoundingBox()

static 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 421 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ updateFormulaSize()

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

Definition at line 334 of file formula.cpp.

335{
336 double scaleFactor = 1.25;
337 int zoomFactor = Config_getInt(FORMULA_FONTSIZE);
338 if (zoomFactor<8 || zoomFactor>50) zoomFactor=10;
339 scaleFactor *= zoomFactor/10.0;
340
341 if (formula)
342 {
343 std::lock_guard<std::mutex> lock(g_formulaUpdateMutex);
344 formula->setWidth(static_cast<int>((x2-x1)*scaleFactor+0.5));
345 formula->setHeight(static_cast<int>((y2-y1)*scaleFactor+0.5));
346 }
347 return scaleFactor;
348}
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:332

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 332 of file formula.cpp.

Referenced by updateFormulaSize().

◆ g_inkscapeDetectionMutex

std::mutex g_inkscapeDetectionMutex
static

Definition at line 725 of file formula.cpp.

Referenced by determineInkscapeVersion().