/****************************************************************************** * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * Documents produced by Doxygen are derivative works derived from the * input used in their production; they are not affected by this license. * */ #include #include #include #include #include #include "formula.h" #include "image.h" #include "util.h" #include "message.h" #include "config.h" #include "portable.h" #include "index.h" #include "doxygen.h" #include "ftextstream.h" Formula::Formula(const char *text) { static int count=0; number = count++; form=text; } Formula::~Formula() { } int Formula::getId() { return number; } void FormulaList::generateBitmaps(const char *path) { int x1,y1,x2,y2; QDir d(path); // store the original directory if (!d.exists()) { err("Output dir %s does not exist!\n",path); exit(1); } QCString oldDir = QDir::currentDirPath().utf8(); // go to the html output directory (i.e. path) QDir::setCurrent(d.absPath()); QDir thisDir; // generate a latex file containing one formula per page. QCString texName="_formulas.tex"; QList pagesToGenerate; pagesToGenerate.setAutoDelete(TRUE); FormulaListIterator fli(*this); Formula *formula; QFile f(texName); bool formulaError=FALSE; if (f.open(IO_WriteOnly)) { FTextStream t(&f); if (Config_getBool(LATEX_BATCHMODE)) t << "\\batchmode" << endl; t << "\\documentclass{article}" << endl; t << "\\usepackage{epsfig}" << endl; // for those who want to include images writeExtraLatexPackages(t); t << "\\pagestyle{empty}" << endl; t << "\\begin{document}" << endl; int page=0; for (fli.toFirst();(formula=fli.current());++fli) { QCString resultName; resultName.sprintf("form_%d.png",formula->getId()); // only formulas for which no image exists are generated QFileInfo fi(resultName); if (!fi.exists()) { // we force a pagebreak after each formula t << formula->getFormulaText() << endl << "\\pagebreak\n\n"; pagesToGenerate.append(new int(page)); } Doxygen::indexList->addImageFile(resultName); page++; } t << "\\end{document}" << endl; f.close(); } if (pagesToGenerate.count()>0) // there are new formulas { //printf("Running latex...\n"); //system("latex _formulas.tex /dev/null"); QCString latexCmd = Config_getString(LATEX_CMD_NAME); if (latexCmd.isEmpty()) latexCmd="latex"; portable_sysTimerStart(); if (portable_system(latexCmd,"_formulas.tex")!=0) { err("Problems running latex. Check your installation or look " "for typos in _formulas.tex and check _formulas.log!\n"); formulaError=TRUE; //return; } portable_sysTimerStop(); //printf("Running dvips...\n"); QListIterator pli(pagesToGenerate); int *pagePtr; int pageIndex=1; for (;(pagePtr=pli.current());++pli,++pageIndex) { int pageNum=*pagePtr; msg("Generating image form_%d.png for formula\n",pageNum); char dviArgs[4096]; QCString formBase; formBase.sprintf("_form%d",pageNum); // run dvips to convert the page with number pageIndex to an // encapsulated postscript. sprintf(dviArgs,"-q -D 600 -E -n 1 -p %d -o %s.eps _formulas.dvi", pageIndex,formBase.data()); portable_sysTimerStart(); if (portable_system("dvips",dviArgs)!=0) { err("Problems running dvips. Check your installation!\n"); portable_sysTimerStop(); QDir::setCurrent(oldDir); return; } portable_sysTimerStop(); // now we read the generated postscript file to extract the bounding box QFileInfo fi(formBase+".eps"); if (fi.exists()) { QCString eps = fileToString(formBase+".eps"); int i=eps.find("%%BoundingBox:"); if (i!=-1) { sscanf(eps.data()+i,"%%%%BoundingBox:%d %d %d %d",&x1,&y1,&x2,&y2); } else { err("Couldn't extract bounding box!\n"); } } // next we generate a postscript file which contains the eps // and displays it in the right colors and the right bounding box f.setName(formBase+".ps"); if (f.open(IO_WriteOnly)) { FTextStream t(&f); t << "1 1 1 setrgbcolor" << endl; // anti-alias to white background t << "newpath" << endl; t << "-1 -1 moveto" << endl; t << (x2-x1+2) << " -1 lineto" << endl; t << (x2-x1+2) << " " << (y2-y1+2) << " lineto" << endl; t << "-1 " << (y2-y1+2) << " lineto" <50) zoomFactor=10; scaleFactor *= zoomFactor/10.0; int gx = (((int)((x2-x1)*scaleFactor))+3)&~1; int gy = (((int)((y2-y1)*scaleFactor))+3)&~1; // Then we run ghostscript to convert the postscript to a pixmap // The pixmap is a truecolor image, where only black and white are // used. char gsArgs[4096]; sprintf(gsArgs,"-q -g%dx%d -r%dx%dx -sDEVICE=ppmraw " "-sOutputFile=%s.pnm -dNOPAUSE -dBATCH -- %s.ps", gx,gy,(int)(scaleFactor*72),(int)(scaleFactor*72), formBase.data(),formBase.data() ); portable_sysTimerStart(); if (portable_system(portable_ghostScriptCommand(),gsArgs)!=0) { err("Problem running ghostscript %s %s. Check your installation!\n",portable_ghostScriptCommand(),gsArgs); portable_sysTimerStop(); QDir::setCurrent(oldDir); return; } portable_sysTimerStop(); f.setName(formBase+".pnm"); uint imageX=0,imageY=0; // we read the generated image again, to obtain the pixel data. if (f.open(IO_ReadOnly)) { QTextStream t(&f); QCString s; if (!t.eof()) s=t.readLine().utf8(); if (s.length()<2 || s.left(2)!="P6") err("ghostscript produced an illegal image format!"); else { // assume the size is after the first line that does not start with // # excluding the first line of the file. while (!t.eof() && (s=t.readLine().utf8()) && !s.isEmpty() && s.at(0)=='#') { } sscanf(s,"%d %d",&imageX,&imageY); } if (imageX>0 && imageY>0) { //printf("Converting image...\n"); char *data = new char[imageX*imageY*3]; // rgb 8:8:8 format uint i,x,y,ix,iy; f.readBlock(data,imageX*imageY*3); Image srcImage(imageX,imageY), filteredImage(imageX,imageY), dstImage(imageX/4,imageY/4); uchar *ps=srcImage.getData(); // convert image to black (1) and white (0) index. for (i=0;igetId() << ":" << formula->getFormulaText() << endl; } f.close(); } // reset the directory to the original location. QDir::setCurrent(oldDir); } #ifdef FORMULA_TEST int main() { FormulaList fl; fl.append(new Formula("$x^2$")); fl.append(new Formula("$y^2$")); fl.append(new Formula("$\\sqrt{x_0^2+x_1^2+x_2^2}$")); fl.generateBitmaps("dest"); return 0; } #endif