Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/src/formula.cpp

Source at commit 1322 created 12 years 8 months ago.
By meklort, Add doxygen to utils folder
1/******************************************************************************
2 *
3 *
4 * Copyright (C) 1997-2011 by Dimitri van Heesch.
5 *
6 * Permission to use, copy, modify, and distribute this software and its
7 * documentation under the terms of the GNU General Public License is hereby
8 * granted. No representations are made about the suitability of this software
9 * for any purpose. It is provided "as is" without express or implied warranty.
10 * See the GNU General Public License for more details.
11 *
12 * Documents produced by Doxygen are derivative works derived from the
13 * input used in their production; they are not affected by this license.
14 *
15 */
16
17#include <stdlib.h>
18#include <unistd.h>
19
20#include "qtbc.h"
21#include <qfile.h>
22#include <qfileinfo.h>
23#include <qtextstream.h>
24#include <qdir.h>
25
26#include "formula.h"
27#include "image.h"
28#include "util.h"
29#include "message.h"
30#include "config.h"
31#include "portable.h"
32#include "index.h"
33#include "doxygen.h"
34#include "ftextstream.h"
35
36Formula::Formula(const char *text)
37{
38 static int count=0;
39 number = count++;
40 form=text;
41}
42
43Formula::~Formula()
44{
45}
46
47int Formula::getId()
48{
49 return number;
50}
51
52void FormulaList::generateBitmaps(const char *path)
53{
54 int x1,y1,x2,y2;
55 QDir d(path);
56 // store the original directory
57 if (!d.exists()) { err("error: Output dir %s does not exist!\n",path); exit(1); }
58 QCString oldDir = convertToQCString(QDir::currentDirPath());
59 // go to the html output directory (i.e. path)
60 QDir::setCurrent(d.absPath());
61 QDir thisDir;
62 // generate a latex file containing one formula per page.
63 QCString texName="_formulas.tex";
64 QList<int> pagesToGenerate;
65 pagesToGenerate.setAutoDelete(TRUE);
66 FormulaListIterator fli(*this);
67 Formula *formula;
68 QFile f(texName);
69 bool formulaError=FALSE;
70 if (f.open(IO_WriteOnly))
71 {
72 FTextStream t(&f);
73 if (Config_getBool("LATEX_BATCHMODE")) t << "\\batchmode" << endl;
74 t << "\\documentclass{article}" << endl;
75 t << "\\usepackage{epsfig}" << endl; // for those who want to include images
76 const char *s=Config_getList("EXTRA_PACKAGES").first();
77 while (s)
78 {
79 t << "\\usepackage{" << s << "}\n";
80 s=Config_getList("EXTRA_PACKAGES").next();
81 }
82 t << "\\pagestyle{empty}" << endl;
83 t << "\\begin{document}" << endl;
84 int page=0;
85 for (fli.toFirst();(formula=fli.current());++fli)
86 {
87 QCString resultName;
88 resultName.sprintf("form_%d.png",formula->getId());
89 // only formulas for which no image exists are generated
90 QFileInfo fi(resultName);
91 if (!fi.exists())
92 {
93 // we force a pagebreak after each formula
94 t << formula->getFormulaText() << endl << "\\pagebreak\n\n";
95 pagesToGenerate.append(new int(page));
96 }
97 Doxygen::indexList.addImageFile(resultName);
98 page++;
99 }
100 t << "\\end{document}" << endl;
101 f.close();
102 }
103 if (pagesToGenerate.count()>0) // there are new formulas
104 {
105 //printf("Running latex...\n");
106 //system("latex _formulas.tex </dev/null >/dev/null");
107 QCString latexCmd = Config_getString("LATEX_CMD_NAME");
108 if (latexCmd.isEmpty()) latexCmd="latex";
109 portable_sysTimerStart();
110 if (portable_system(latexCmd,"_formulas.tex")!=0)
111 {
112 err("Problems running latex. Check your installation or look "
113 "for typos in _formulas.tex and check _formulas.log!\n");
114 formulaError=TRUE;
115 //return;
116 }
117 portable_sysTimerStop();
118 //printf("Running dvips...\n");
119 QListIterator<int> pli(pagesToGenerate);
120 int *pagePtr;
121 int pageIndex=1;
122 for (;(pagePtr=pli.current());++pli,++pageIndex)
123 {
124 int pageNum=*pagePtr;
125 msg("Generating image form_%d.png for formula\n",pageNum);
126 char dviArgs[4096];
127 QCString formBase;
128 formBase.sprintf("_form%d",pageNum);
129 // run dvips to convert the page with number pageIndex to an
130 // encapsulated postscript.
131 sprintf(dviArgs,"-q -D 600 -E -n 1 -p %d -o %s.eps _formulas.dvi",
132 pageIndex,formBase.data());
133 portable_sysTimerStart();
134 if (portable_system("dvips",dviArgs)!=0)
135 {
136 err("Problems running dvips. Check your installation!\n");
137 portable_sysTimerStop();
138 return;
139 }
140 portable_sysTimerStop();
141 // now we read the generated postscript file to extract the bounding box
142 QFileInfo fi(formBase+".eps");
143 if (fi.exists())
144 {
145 QCString eps = fileToString(formBase+".eps");
146 int i=eps.find("%%BoundingBox:");
147 if (i!=-1)
148 {
149 sscanf(eps.data()+i,"%%%%BoundingBox:%d %d %d %d",&x1,&y1,&x2,&y2);
150 }
151 else
152 {
153 err("error: Couldn't extract bounding box!\n");
154 }
155 }
156 // next we generate a postscript file which contains the eps
157 // and displays it in the right colors and the right bounding box
158 f.setName(formBase+".ps");
159 if (f.open(IO_WriteOnly))
160 {
161 FTextStream t(&f);
162 t << "1 1 1 setrgbcolor" << endl; // anti-alias to white background
163 t << "newpath" << endl;
164 t << "-1 -1 moveto" << endl;
165 t << (x2-x1+2) << " -1 lineto" << endl;
166 t << (x2-x1+2) << " " << (y2-y1+2) << " lineto" << endl;
167 t << "-1 " << (y2-y1+2) << " lineto" <<endl;
168 t << "closepath" << endl;
169 t << "fill" << endl;
170 t << -x1 << " " << -y1 << " translate" << endl;
171 t << "0 0 0 setrgbcolor" << endl;
172 t << "(" << formBase << ".eps) run" << endl;
173 f.close();
174 }
175 // scale the image so that it is four times larger than needed.
176 // and the sizes are a multiple of four.
177 double scaleFactor = 16.0/3.0;
178 int zoomFactor = Config_getInt("FORMULA_FONTSIZE");
179 if (zoomFactor<8 || zoomFactor>50) zoomFactor=10;
180 scaleFactor *= zoomFactor/10.0;
181 int gx = (((int)((x2-x1)*scaleFactor))+3)&~1;
182 int gy = (((int)((y2-y1)*scaleFactor))+3)&~1;
183 // Then we run ghostscript to convert the postscript to a pixmap
184 // The pixmap is a truecolor image, where only black and white are
185 // used.
186
187 char gsArgs[4096];
188 sprintf(gsArgs,"-q -g%dx%d -r%dx%dx -sDEVICE=ppmraw "
189 "-sOutputFile=%s.pnm -dNOPAUSE -dBATCH -- %s.ps",
190 gx,gy,(int)(scaleFactor*72),(int)(scaleFactor*72),
191 formBase.data(),formBase.data()
192 );
193 portable_sysTimerStart();
194 if (portable_system(portable_ghostScriptCommand(),gsArgs)!=0)
195 {
196 err("Problem running ghostscript %s %s. Check your installation!\n",portable_ghostScriptCommand(),gsArgs);
197 portable_sysTimerStop();
198 return;
199 }
200 portable_sysTimerStop();
201 f.setName(formBase+".pnm");
202 uint imageX=0,imageY=0;
203 // we read the generated image again, to obtain the pixel data.
204 if (f.open(IO_ReadOnly))
205 {
206 QTextStream t(&f);
207 QCString s;
208 if (!t.eof())
209 s=t.readLine();
210 if (s.length()<2 || s.left(2)!="P6")
211 err("error: ghostscript produced an illegal image format!");
212 else
213 {
214 // assume the size if after the first line that does not start with
215 // # excluding the first line of the file.
216 while (!t.eof() && (s=t.readLine()) && !s.isEmpty() && s.at(0)=='#') { }
217 sscanf(s,"%d %d",&imageX,&imageY);
218 }
219 if (imageX>0 && imageY>0)
220 {
221 //printf("Converting image...\n");
222 char *data = new char[imageX*imageY*3]; // rgb 8:8:8 format
223 uint i,x,y,ix,iy;
224 f.readBlock(data,imageX*imageY*3);
225 Image srcImage(imageX,imageY),
226 filteredImage(imageX,imageY),
227 dstImage(imageX/4,imageY/4);
228 uchar *ps=srcImage.getData();
229 // convert image to black (1) and white (0) index.
230 for (i=0;i<imageX*imageY;i++) *ps++= (data[i*3]==0 ? 1 : 0);
231 // apply a simple box filter to the image
232 static int filterMask[]={1,2,1,2,8,2,1,2,1};
233 for (y=0;y<srcImage.getHeight();y++)
234 {
235 for (x=0;x<srcImage.getWidth();x++)
236 {
237 int s=0;
238 for (iy=0;iy<2;iy++)
239 {
240 for (ix=0;ix<2;ix++)
241 {
242 s+=srcImage.getPixel(x+ix-1,y+iy-1)*filterMask[iy*3+ix];
243 }
244 }
245 filteredImage.setPixel(x,y,s);
246 }
247 }
248 // down-sample the image to 1/16th of the area using 16 gray scale
249 // colors.
250 // TODO: optimize this code.
251 for (y=0;y<dstImage.getHeight();y++)
252 {
253 for (x=0;x<dstImage.getWidth();x++)
254 {
255 int xp=x<<2;
256 int yp=y<<2;
257 int c=filteredImage.getPixel(xp+0,yp+0)+
258 filteredImage.getPixel(xp+1,yp+0)+
259 filteredImage.getPixel(xp+2,yp+0)+
260 filteredImage.getPixel(xp+3,yp+0)+
261 filteredImage.getPixel(xp+0,yp+1)+
262 filteredImage.getPixel(xp+1,yp+1)+
263 filteredImage.getPixel(xp+2,yp+1)+
264 filteredImage.getPixel(xp+3,yp+1)+
265 filteredImage.getPixel(xp+0,yp+2)+
266 filteredImage.getPixel(xp+1,yp+2)+
267 filteredImage.getPixel(xp+2,yp+2)+
268 filteredImage.getPixel(xp+3,yp+2)+
269 filteredImage.getPixel(xp+0,yp+3)+
270 filteredImage.getPixel(xp+1,yp+3)+
271 filteredImage.getPixel(xp+2,yp+3)+
272 filteredImage.getPixel(xp+3,yp+3);
273 // here we scale and clip the color value so the
274 // resulting image has a reasonable contrast
275 dstImage.setPixel(x,y,QMIN(15,(c*15)/(16*10)));
276 }
277 }
278 // save the result as a bitmap
279 QCString resultName;
280 resultName.sprintf("form_%d.png",pageNum);
281 // the option parameter 1 is used here as a temporary hack
282 // to select the right color palette!
283 dstImage.save(resultName,1);
284 delete[] data;
285 }
286 f.close();
287 }
288 // remove intermediate image files
289 thisDir.remove(formBase+".eps");
290 thisDir.remove(formBase+".pnm");
291 thisDir.remove(formBase+".ps");
292 }
293 // remove intermediate files produced by latex
294 thisDir.remove("_formulas.dvi");
295 if (!formulaError) thisDir.remove("_formulas.log"); // keep file in case of errors
296 thisDir.remove("_formulas.aux");
297 }
298 // remove the latex file itself
299 if (!formulaError) thisDir.remove("_formulas.tex");
300 // write/update the formula repository so we know what text the
301 // generated images represent (we use this next time to avoid regeneration
302 // of the images, and to avoid forcing the user to delete all images in order
303 // to let a browser refresh the images).
304 f.setName("formula.repository");
305 if (f.open(IO_WriteOnly))
306 {
307 FTextStream t(&f);
308 for (fli.toFirst();(formula=fli.current());++fli)
309 {
310 t << "\\form#" << formula->getId() << ":" << formula->getFormulaText() << endl;
311 }
312 f.close();
313 }
314 // reset the directory to the original location.
315 QDir::setCurrent(oldDir);
316}
317
318
319#ifdef FORMULA_TEST
320int main()
321{
322 FormulaList fl;
323 fl.append(new Formula("$x^2$"));
324 fl.append(new Formula("$y^2$"));
325 fl.append(new Formula("$\\sqrt{x_0^2+x_1^2+x_2^2}$"));
326 fl.generateBitmaps("dest");
327 return 0;
328}
329#endif
330

Archive Download this file

Revision: 1322