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 DString &fileName)
static bool createPostscriptFile (const DString &fileName, const DString &formBase, int pageIndex)
static bool createEPSbboxFile (const DString &formBase)
static bool extractBoundingBox (const DString &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 DString &formBase, int x1, int y1, int x2, int y2)
static bool createCroppedEPS (const DString &formBase)
static bool createSVGFromPDF (const DString &formBase, const DString &outFile)
static bool createSVGFromPDFviaInkscape (const Dir &thisDir, const DString &formBase, const DString &outFile)
static bool updateEPSBoundingBox (const DString &formBase, int x1, int y1, int x2, int y2, double x1hi, double y1hi, double x2hi, double y2hi)
static bool createPNG (const DString &formBase, const DString &outFile, double scaleFactor)
static StringVector generateFormula (const Dir &thisDir, const DString &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 DString & formBase)
static

Definition at line 364 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ createCroppedPDF()

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

Definition at line 348 of file formula.cpp.

349{
350 const size_t argsLen = 4096;
351 char args[argsLen];
352 // crop the image to its bounding box
353 snprintf(args,argsLen,"-q -dBATCH -dNOPAUSE -P- -dNOSAFER -sDEVICE=pdfwrite"
354 " -o %s_tmp.pdf -c \"[/CropBox [%d %d %d %d] /PAGES pdfmark\" -f %s_tmp.ps",
355 qPrint(formBase),x1,y1,x2,y2,qPrint(formBase));
357 {
358 err("Problems running {}. Check your installation!\n",Portable::ghostScriptCommand());
359 return false;
360 }
361 return true;
362}

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

Referenced by generateFormula().

◆ createDVIFile()

bool createDVIFile ( const DString & fileName)
static

Definition at line 240 of file formula.cpp.

241{
242 DString 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 snprintf(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 DString logFile = fileToString(fileName+".log");
258 if (logFile.empty() ||
259 (logFile.find("Rerun to get cross-references right")==DString::npos &&
260 logFile.find("Rerun LaTeX")==DString::npos))
261 {
262 break;
263 }
264 rerunCount++;
265 }
266 return true;
267}
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:88
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:152
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
Definition dstring.h:182
size_t find(char c, size_t pos=0) const
Definition dstring.h:243
const char * devNull()
Definition portable.cpp:614
DString fileToString(const DString &name, bool filter, bool isSourceCode)
Definition util.cpp:1055

References Portable::devNull(), DString::empty(), err, fileToString(), DString::find(), DString::npos, qPrint(), and Portable::system().

Referenced by FormulaManager::createFormulasTexFile().

◆ createEPSbboxFile()

bool createEPSbboxFile ( const DString & 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 snprintf(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 {}. Check your installation!\n",Portable::ghostScriptCommand());
294 return false;
295 }
296 return true;
297}

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

Referenced by generateFormula().

◆ createPNG()

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

Definition at line 457 of file formula.cpp.

458{
459 const size_t argsLen = 4096;
460 char args[argsLen];
461 snprintf(args,argsLen,"-q -dNOSAFER -dBATCH -dNOPAUSE -dEPSCrop -sDEVICE=pngalpha -dGraphicsAlphaBits=4 -dTextAlphaBits=4 "
462 "-r%d -sOutputFile=%s %s_tmp_corr.eps",static_cast<int>(scaleFactor*72),qPrint(outFile),qPrint(formBase));
464 {
465 err("Problems running {}. Check your installation!\n",Portable::ghostScriptCommand());
466 return false;
467 }
468 return true;
469}

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

Referenced by generateFormula().

◆ createPostscriptFile()

bool createPostscriptFile ( const DString & fileName,
const DString & 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 snprintf(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(), and Portable::system().

Referenced by generateFormula().

◆ createSVGFromPDF()

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

Definition at line 379 of file formula.cpp.

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

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

Referenced by generateFormula().

◆ createSVGFromPDFviaInkscape()

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

Definition at line 392 of file formula.cpp.

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

References determineInkscapeVersion(), Portable::devNull(), err, qPrint(), 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 DString inkscapeVersionFile = "inkscape_version" ;
738 inkscapeVersion = -1;
739 DString 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}
const std::string & str() const
Definition dstring.h:649
@ Formula
Definition debug.h:34
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:133
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:315
static std::mutex g_inkscapeDetectionMutex
Definition formula.cpp:724
std::ifstream openInputStream(const DString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:676

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

Referenced by createSVGFromPDFviaInkscape().

◆ extractBoundingBox()

bool extractBoundingBox ( const DString & 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 DString eps = fileToString(formBase+"_tmp.epsi");
307 if (size_t i = eps.find("%%BoundingBox:"); i!=DString::npos)
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 if (size_t i = eps.find("%%HiResBoundingBox:"); i!=DString::npos)
317 {
318 sscanf(eps.data()+i,"%%%%HiResBoundingBox:%lf %lf %lf %lf",x1hi,y1hi,x2hi,y2hi);
319 }
320 else
321 {
322 err("Couldn't extract high resolution bounding box from {}_tmp.epsi\n",formBase);
323 return false;
324 }
325 }
326 //printf("Bounding box [%d %d %d %d]\n",x1,y1,x2,y2);
327 return true;
328}
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition dstring.h:161
Minimal replacement for QFileInfo.
Definition fileinfo.h:26

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

Referenced by generateFormula().

◆ generateFormula()

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

Definition at line 471 of file formula.cpp.

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

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

Referenced by FormulaManager::createFormulasTexFile().

◆ updateEPSBoundingBox()

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

Definition at line 419 of file formula.cpp.

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

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

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

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