Public Member Functions | List of all members
FormulaList Class Reference

#include <formula.h>

Inheritance diagram for FormulaList:
QList< Formula > QGList

Public Member Functions

void generateBitmaps (const char *path)
 
- Public Member Functions inherited from QList< Formula >
 QList ()
 
 QList (const QList< Formula > &l)
 
 ~QList ()
 
QList< Formula > & operator= (const QList< Formula > &l)
 
bool operator== (const QList< Formula > &list) const
 
uint count () const
 
bool isEmpty () const
 
bool insert (uint i, const Formula *d)
 
void inSort (const Formula *d)
 
void prepend (const Formula *d)
 
void append (const Formula *d)
 
bool remove (uint i)
 
bool remove (const Formula *d)
 
bool removeRef (const Formula *d)
 
bool removeFirst ()
 
bool removeLast ()
 
Formulatake (uint i)
 
void clear ()
 
void sort ()
 
int find (const Formula *d) const
 
int findRef (const Formula *d) const
 
uint contains (const Formula *d) const
 
uint containsRef (const Formula *d) const
 
Formulaat (uint i) const
 
FormulagetFirst () const
 
FormulagetLast () const
 
void setAutoDelete (bool enable)
 

Detailed Description

A list of Formula objects.

Definition at line 39 of file formula.h.

Member Function Documentation

void FormulaList::generateBitmaps ( const char *  path)

Definition at line 49 of file formula.cpp.

50 {
51  int x1,y1,x2,y2;
52  QDir d(path);
53  // store the original directory
54  if (!d.exists()) { err("Output dir %s does not exist!\n",path); exit(1); }
55  QCString oldDir = QDir::currentDirPath().utf8();
56  // go to the html output directory (i.e. path)
57  QDir::setCurrent(d.absPath());
58  QDir thisDir;
59  // generate a latex file containing one formula per page.
60  QCString texName="_formulas.tex";
61  QList<int> pagesToGenerate;
62  pagesToGenerate.setAutoDelete(TRUE);
63  FormulaListIterator fli(*this);
64  Formula *formula;
65  QFile f(texName);
66  bool formulaError=FALSE;
67  if (f.open(IO_WriteOnly))
68  {
69  FTextStream t(&f);
70  if (Config_getBool("LATEX_BATCHMODE")) t << "\\batchmode" << endl;
71  t << "\\documentclass{article}" << endl;
72  t << "\\usepackage{epsfig}" << endl; // for those who want to include images
73  const char *s=Config_getList("EXTRA_PACKAGES").first();
74  while (s)
75  {
76  t << "\\usepackage{" << s << "}\n";
77  s=Config_getList("EXTRA_PACKAGES").next();
78  }
79  t << "\\pagestyle{empty}" << endl;
80  t << "\\begin{document}" << endl;
81  int page=0;
82  for (fli.toFirst();(formula=fli.current());++fli)
83  {
84  QCString resultName;
85  resultName.sprintf("form_%d.png",formula->getId());
86  // only formulas for which no image exists are generated
87  QFileInfo fi(resultName);
88  if (!fi.exists())
89  {
90  // we force a pagebreak after each formula
91  t << formula->getFormulaText() << endl << "\\pagebreak\n\n";
92  pagesToGenerate.append(new int(page));
93  }
94  Doxygen::indexList->addImageFile(resultName);
95  page++;
96  }
97  t << "\\end{document}" << endl;
98  f.close();
99  }
100  if (pagesToGenerate.count()>0) // there are new formulas
101  {
102  //printf("Running latex...\n");
103  //system("latex _formulas.tex </dev/null >/dev/null");
104  QCString latexCmd = Config_getString("LATEX_CMD_NAME");
105  if (latexCmd.isEmpty()) latexCmd="latex";
107  if (portable_system(latexCmd,"_formulas.tex")!=0)
108  {
109  err("Problems running latex. Check your installation or look "
110  "for typos in _formulas.tex and check _formulas.log!\n");
111  formulaError=TRUE;
112  //return;
113  }
115  //printf("Running dvips...\n");
116  QListIterator<int> pli(pagesToGenerate);
117  int *pagePtr;
118  int pageIndex=1;
119  for (;(pagePtr=pli.current());++pli,++pageIndex)
120  {
121  int pageNum=*pagePtr;
122  msg("Generating image form_%d.png for formula\n",pageNum);
123  char dviArgs[4096];
124  QCString formBase;
125  formBase.sprintf("_form%d",pageNum);
126  // run dvips to convert the page with number pageIndex to an
127  // encapsulated postscript.
128  sprintf(dviArgs,"-q -D 600 -E -n 1 -p %d -o %s.eps _formulas.dvi",
129  pageIndex,formBase.data());
131  if (portable_system("dvips",dviArgs)!=0)
132  {
133  err("Problems running dvips. Check your installation!\n");
135  QDir::setCurrent(oldDir);
136  return;
137  }
139  // now we read the generated postscript file to extract the bounding box
140  QFileInfo fi(formBase+".eps");
141  if (fi.exists())
142  {
143  QCString eps = fileToString(formBase+".eps");
144  int i=eps.find("%%BoundingBox:");
145  if (i!=-1)
146  {
147  sscanf(eps.data()+i,"%%%%BoundingBox:%d %d %d %d",&x1,&y1,&x2,&y2);
148  }
149  else
150  {
151  err("Couldn't extract bounding box!\n");
152  }
153  }
154  // next we generate a postscript file which contains the eps
155  // and displays it in the right colors and the right bounding box
156  f.setName(formBase+".ps");
157  if (f.open(IO_WriteOnly))
158  {
159  FTextStream t(&f);
160  t << "1 1 1 setrgbcolor" << endl; // anti-alias to white background
161  t << "newpath" << endl;
162  t << "-1 -1 moveto" << endl;
163  t << (x2-x1+2) << " -1 lineto" << endl;
164  t << (x2-x1+2) << " " << (y2-y1+2) << " lineto" << endl;
165  t << "-1 " << (y2-y1+2) << " lineto" <<endl;
166  t << "closepath" << endl;
167  t << "fill" << endl;
168  t << -x1 << " " << -y1 << " translate" << endl;
169  t << "0 0 0 setrgbcolor" << endl;
170  t << "(" << formBase << ".eps) run" << endl;
171  f.close();
172  }
173  // scale the image so that it is four times larger than needed.
174  // and the sizes are a multiple of four.
175  double scaleFactor = 16.0/3.0;
176  int zoomFactor = Config_getInt("FORMULA_FONTSIZE");
177  if (zoomFactor<8 || zoomFactor>50) zoomFactor=10;
178  scaleFactor *= zoomFactor/10.0;
179  int gx = (((int)((x2-x1)*scaleFactor))+3)&~1;
180  int gy = (((int)((y2-y1)*scaleFactor))+3)&~1;
181  // Then we run ghostscript to convert the postscript to a pixmap
182  // The pixmap is a truecolor image, where only black and white are
183  // used.
184 
185  char gsArgs[4096];
186  sprintf(gsArgs,"-q -g%dx%d -r%dx%dx -sDEVICE=ppmraw "
187  "-sOutputFile=%s.pnm -dNOPAUSE -dBATCH -- %s.ps",
188  gx,gy,(int)(scaleFactor*72),(int)(scaleFactor*72),
189  formBase.data(),formBase.data()
190  );
193  {
194  err("Problem running ghostscript %s %s. Check your installation!\n",portable_ghostScriptCommand(),gsArgs);
196  QDir::setCurrent(oldDir);
197  return;
198  }
200  f.setName(formBase+".pnm");
201  uint imageX=0,imageY=0;
202  // we read the generated image again, to obtain the pixel data.
203  if (f.open(IO_ReadOnly))
204  {
205  QTextStream t(&f);
206  QCString s;
207  if (!t.eof())
208  s=t.readLine().utf8();
209  if (s.length()<2 || s.left(2)!="P6")
210  err("ghostscript produced an illegal image format!");
211  else
212  {
213  // assume the size is after the first line that does not start with
214  // # excluding the first line of the file.
215  while (!t.eof() && (s=t.readLine().utf8()) && !s.isEmpty() && s.at(0)=='#') { }
216  sscanf(s,"%d %d",&imageX,&imageY);
217  }
218  if (imageX>0 && imageY>0)
219  {
220  //printf("Converting image...\n");
221  char *data = new char[imageX*imageY*3]; // rgb 8:8:8 format
222  uint i,x,y,ix,iy;
223  f.readBlock(data,imageX*imageY*3);
224  Image srcImage(imageX,imageY),
225  filteredImage(imageX,imageY),
226  dstImage(imageX/4,imageY/4);
227  uchar *ps=srcImage.getData();
228  // convert image to black (1) and white (0) index.
229  for (i=0;i<imageX*imageY;i++) *ps++= (data[i*3]==0 ? 1 : 0);
230  // apply a simple box filter to the image
231  static int filterMask[]={1,2,1,2,8,2,1,2,1};
232  for (y=0;y<srcImage.getHeight();y++)
233  {
234  for (x=0;x<srcImage.getWidth();x++)
235  {
236  int s=0;
237  for (iy=0;iy<2;iy++)
238  {
239  for (ix=0;ix<2;ix++)
240  {
241  s+=srcImage.getPixel(x+ix-1,y+iy-1)*filterMask[iy*3+ix];
242  }
243  }
244  filteredImage.setPixel(x,y,s);
245  }
246  }
247  // down-sample the image to 1/16th of the area using 16 gray scale
248  // colors.
249  // TODO: optimize this code.
250  for (y=0;y<dstImage.getHeight();y++)
251  {
252  for (x=0;x<dstImage.getWidth();x++)
253  {
254  int xp=x<<2;
255  int yp=y<<2;
256  int c=filteredImage.getPixel(xp+0,yp+0)+
257  filteredImage.getPixel(xp+1,yp+0)+
258  filteredImage.getPixel(xp+2,yp+0)+
259  filteredImage.getPixel(xp+3,yp+0)+
260  filteredImage.getPixel(xp+0,yp+1)+
261  filteredImage.getPixel(xp+1,yp+1)+
262  filteredImage.getPixel(xp+2,yp+1)+
263  filteredImage.getPixel(xp+3,yp+1)+
264  filteredImage.getPixel(xp+0,yp+2)+
265  filteredImage.getPixel(xp+1,yp+2)+
266  filteredImage.getPixel(xp+2,yp+2)+
267  filteredImage.getPixel(xp+3,yp+2)+
268  filteredImage.getPixel(xp+0,yp+3)+
269  filteredImage.getPixel(xp+1,yp+3)+
270  filteredImage.getPixel(xp+2,yp+3)+
271  filteredImage.getPixel(xp+3,yp+3);
272  // here we scale and clip the color value so the
273  // resulting image has a reasonable contrast
274  dstImage.setPixel(x,y,QMIN(15,(c*15)/(16*10)));
275  }
276  }
277  // save the result as a bitmap
278  QCString resultName;
279  resultName.sprintf("form_%d.png",pageNum);
280  // the option parameter 1 is used here as a temporary hack
281  // to select the right color palette!
282  dstImage.save(resultName,1);
283  delete[] data;
284  }
285  f.close();
286  }
287  // remove intermediate image files
288  thisDir.remove(formBase+".eps");
289  thisDir.remove(formBase+".pnm");
290  thisDir.remove(formBase+".ps");
291  }
292  // remove intermediate files produced by latex
293  thisDir.remove("_formulas.dvi");
294  if (!formulaError) thisDir.remove("_formulas.log"); // keep file in case of errors
295  thisDir.remove("_formulas.aux");
296  }
297  // remove the latex file itself
298  if (!formulaError) thisDir.remove("_formulas.tex");
299  // write/update the formula repository so we know what text the
300  // generated images represent (we use this next time to avoid regeneration
301  // of the images, and to avoid forcing the user to delete all images in order
302  // to let a browser refresh the images).
303  f.setName("formula.repository");
304  if (f.open(IO_WriteOnly))
305  {
306  FTextStream t(&f);
307  for (fli.toFirst();(formula=fli.current());++fli)
308  {
309  t << "\\form#" << formula->getId() << ":" << formula->getFormulaText() << endl;
310  }
311  f.close();
312  }
313  // reset the directory to the original location.
314  QDir::setCurrent(oldDir);
315 }
Traverses directory structures and contents in a platform-independent way.
Definition: qdir.h:52
void portable_sysTimerStop()
Definition: portable.cpp:415
QCString fileToString(const char *name, bool filter, bool isSourceCode)
Definition: util.cpp:2418
QCString getFormulaText() const
Definition: formula.h:31
bool isEmpty() const
Definition: qcstring.h:189
void msg(const char *fmt,...)
Definition: message.cpp:107
uint length() const
Definition: qcstring.h:195
void append(const type *d)
Definition: qlist.h:73
#define IO_WriteOnly
Definition: qiodevice.h:62
char & at(uint i) const
Definition: qcstring.h:326
const bool FALSE
Definition: qglobal.h:370
#define Config_getList(val)
Definition: config.cpp:662
QCString left(uint len) const
Definition: qcstring.cpp:213
Simplified and optimized version of QTextStream.
Definition: ftextstream.h:11
const char * portable_ghostScriptCommand()
Definition: portable.cpp:373
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
unsigned char uchar
Definition: nybbler.cc:11
void portable_sysTimerStart()
Definition: portable.cpp:410
#define IO_ReadOnly
Definition: qiodevice.h:61
#define QMIN(a, b)
Definition: qglobal.h:391
#define Config_getInt(val)
Definition: config.cpp:661
uint count() const
Definition: qlist.h:66
static QString currentDirPath()
Definition: qdir_unix.cpp:141
const char * data() const
Definition: qcstring.h:207
void addImageFile(const char *name)
Definition: index.h:147
#define Config_getString(val)
Definition: config.cpp:660
#define Config_getBool(val)
Definition: config.cpp:664
static constexpr double ps
Definition: Units.h:99
void err(const char *fmt,...)
Definition: message.cpp:226
The QFile class is an I/O device that operates on files.
Definition: qfile.h:50
QCString & sprintf(const char *format,...)
Definition: qcstring.cpp:27
The QTextStream class provides basic functions for reading and writing text using a QIODevice...
Definition: qtextstream.h:53
int getId()
Definition: formula.cpp:44
Definition: image.h:24
list x
Definition: train.py:276
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:51
QCString utf8() const
Definition: qstring.cpp:14507
unsigned uint
Definition: qglobal.h:351
void setAutoDelete(bool enable)
Definition: qlist.h:99
static QCString * s
Definition: config.cpp:1042
const bool TRUE
Definition: qglobal.h:371
static IndexList * indexList
Definition: doxygen.h:149
static bool setCurrent(const QString &path)
Definition: qdir_unix.cpp:134
QTextStream & endl(QTextStream &s)
Definition: qlist.h:54
int portable_system(const char *command, const char *args, bool commandHasConsole)
Definition: portable.cpp:33

The documentation for this class was generated from the following files: