lib/psGfx.c

Go to the documentation of this file.
00001 /* PostScript graphics - 
00002  * This provides a bit of a shell around writing graphics to
00003  * a postScript file.  Perhaps the most important thing it
00004  * does is convert 0,0 from being at the bottom left to
00005  * being at the top left. */
00006 #include "common.h"
00007 #include "psPoly.h"
00008 #include "psGfx.h"
00009 #include "linefile.h"
00010 
00011 static char const rcsid[] = "$Id: psGfx.c,v 1.30 2007/04/15 00:29:47 galt Exp $";
00012 
00013 static void psFloatOut(FILE *f, double x)
00014 /* Write out a floating point number, but not in too much
00015  * precision. */
00016 {
00017 int i = round(x);
00018 if (i == x)
00019    fprintf(f, "%d ", i);
00020 else
00021    fprintf(f, "%0.4f ", x);
00022 }
00023 
00024 void psClipRect(struct psGfx *ps, double x, double y, 
00025         double width, double height)
00026 /* Set clipping rectangle. */
00027 {
00028 FILE *f = ps->f;
00029 fprintf(f, "cliprestore ");
00030 psXyOut(ps, x, y+height); 
00031 psWhOut(ps, width, height);       
00032 fprintf(f, "rectclip\n");
00033 }
00034 
00035 static void psWriteHeader(FILE *f, double width, double height)
00036 /* Write postScript header.  It's encapsulated PostScript
00037  * actually, so you need to supply image width and height
00038  * in points. */
00039 {
00040 char *s =
00041 #include "common.pss"
00042 ;
00043 
00044 fprintf(f, "%%!PS-Adobe-3.1 EPSF-3.0\n");
00045 fprintf(f, "%%%%BoundingBox: 0 0 %d %d\n\n", (int)ceil(width), (int)ceil(height));
00046 fprintf(f, "%s", s);
00047 }
00048 
00049 struct psGfx *psOpen(char *fileName, 
00050         double userWidth, double userHeight, /* Dimension of image in user's units. */
00051         double ptWidth, double ptHeight,     /* Dimension of image in points. */
00052         double ptMargin)                     /* Image margin in points. */
00053 /* Open up a new postscript file.  If ptHeight is 0, it will be
00054  * calculated to keep pixels square. */
00055 {
00056 struct psGfx *ps;
00057 
00058 /* Allocate structure and open file. */
00059 AllocVar(ps);
00060 ps->f = mustOpen(fileName, "w");
00061 
00062 /* Save page dimensions and calculate scaling factors. */
00063 ps->userWidth = userWidth;
00064 ps->userHeight = userHeight;
00065 ps->ptWidth = ptWidth;
00066 ps->xScale = (ptWidth - 2*ptMargin)/userWidth;
00067 if (ptHeight != 0.0)
00068    {
00069    ps->ptHeight = ptHeight;
00070    ps->yScale = (ptHeight - 2*ptMargin) / userHeight;
00071    }
00072 else
00073    {
00074    ps->yScale = ps->xScale;
00075    ptHeight = ps->ptHeight = userHeight * ps->yScale + 2*ptMargin;
00076    }
00077 /* 0.5, 0.5 is the center of the pixel in upper-left corner which corresponds to (0,0) */
00078 ps->xOff = ptMargin;
00079 ps->yOff = ptMargin;
00080 ps->fontHeight = 10;
00081 
00082 /* Cope with fact y coordinates are bottom to top rather
00083  * than top to bottom. */
00084 ps->yScale = -ps->yScale;
00085 ps->yOff = ps->ptHeight - ps->yOff;
00086 
00087 psWriteHeader(ps->f, ptWidth, ptHeight);
00088 
00089 /* Set initial clipping rectangle. */
00090 psClipRect(ps, 0, 0, ps->userWidth, ps->userHeight);
00091 
00092 /* Set line width to a single pixel. */
00093 fprintf(ps->f, "%f setlinewidth\n", ps->xScale);
00094 
00095 return ps;
00096 }
00097 
00098 void psTranslate(struct psGfx *ps, double xTrans, double yTrans)
00099 /* add a constant to translate all coordinates */
00100 {
00101 ps->xOff += xTrans*ps->xScale;   
00102 ps->yOff += yTrans*ps->yScale;
00103 }
00104 
00105 void psClose(struct psGfx **pPs)
00106 /* Close out postScript file. */
00107 {
00108 struct psGfx *ps = *pPs;
00109 if (ps != NULL)
00110     {
00111     carefulClose(&ps->f);
00112     freez(pPs);
00113     }
00114 }
00115 
00116 void psXyOut(struct psGfx *ps, double x, double y)
00117 /* Output x,y position transformed into PostScript space. */
00118 {
00119 FILE *f = ps->f;
00120 psFloatOut(f, x * ps->xScale + ps->xOff);
00121 psFloatOut(f, y * ps->yScale + ps->yOff);
00122 }
00123 
00124 void psWhOut(struct psGfx *ps, double width, double height)
00125 /* Output width/height transformed into PostScript space. */
00126 {
00127 FILE *f = ps->f;
00128 psFloatOut(f, width * ps->xScale);
00129 psFloatOut(f, height * -ps->yScale);
00130 }
00131 
00132 void psMoveTo(struct psGfx *ps, double x, double y)
00133 /* Move PostScript position to given point. */
00134 {
00135 psXyOut(ps, x, y);
00136 fprintf(ps->f, "moveto\n");
00137 }
00138 
00139 void psLineTo(struct psGfx *ps, double x, double y)
00140 /* Draw line from current point to given point,
00141  * and make given point new current point. */
00142 {
00143 psXyOut(ps, x, y);
00144 fprintf(ps->f, "lineto\n");
00145 }
00146 
00147 void psDrawBox(struct psGfx *ps, double x, double y, 
00148         double width, double height)
00149 /* Draw a filled box in current color. */
00150 {
00151 if (width > 0 && height > 0)
00152     {
00153     psWhOut(ps, width, height);
00154     psXyOut(ps, x, y+height); 
00155     fprintf(ps->f, "fillBox\n");
00156     }
00157 }
00158 
00159 void psDrawLine(struct psGfx *ps, double x1, double y1, double x2, double y2)
00160 /* Draw a line from x1/y1 to x2/y2 */
00161 {
00162 FILE *f = ps->f;
00163 fprintf(f, "newpath\n");
00164 psMoveTo(ps, x1, y1);
00165 psXyOut(ps, x2, y2);
00166 fprintf(ps->f, "lineto\n");
00167 fprintf(f, "stroke\n");
00168 }
00169 
00170 void psFillUnder(struct psGfx *ps, double x1, double y1, 
00171         double x2, double y2, double bottom)
00172 /* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
00173  * it's top, a horizontal line at bottom at it's bottom,  and
00174  * vertical lines from the bottom to y1 on the left and bottom to
00175  * y2 on the right. */
00176 {
00177 FILE *f = ps->f;
00178 fprintf(f, "newpath\n");
00179 psMoveTo(ps, x1, y1);
00180 psLineTo(ps, x2, y2);
00181 psLineTo(ps, x2, bottom);
00182 psLineTo(ps, x1, bottom);
00183 fprintf(f, "closepath\n");
00184 fprintf(f, "fill\n");
00185 }
00186 
00187 void psTimesFont(struct psGfx *ps, double size)
00188 /* Set font to times of a certain size. */
00189 {
00190 FILE *f = ps->f;
00191 fprintf(f, "/Helvetica findfont ");
00192 
00193 /* Note the 1.2 and the 1.0 below seem to get it to 
00194  * position about where the stuff developed for pixel
00195  * based systems expects it.  It is all a kludge though! */
00196 fprintf(f, "%f scalefont setfont\n", -size*ps->yScale*1.2);
00197 ps->fontHeight = size*0.8;
00198 }
00199 
00200 
00201 void psTextAt(struct psGfx *ps, double x, double y, char *text)
00202 /* Output text in current font at given position. */
00203 {
00204 char c;
00205 psMoveTo(ps, x, y + ps->fontHeight);
00206 fprintf(ps->f, "(");
00207 while ((c = *text++) != 0)
00208     {
00209     if (c == ')' || c == '(')
00210         fprintf(ps->f, "\\");
00211     fprintf(ps->f, "%c", c);
00212     }
00213 fprintf(ps->f, ") show\n");
00214 }
00215 
00216 void psTextRight(struct psGfx *ps, double x, double y, 
00217         double width, double height, 
00218         char *text)
00219 /* Draw a line of text right justified in box defined by x/y/width/height */
00220 {
00221 y += (height - ps->fontHeight)/2;
00222 psMoveTo(ps, x+width, y + ps->fontHeight);
00223 fprintf(ps->f, "(%s) showBefore\n", text);
00224 }
00225 
00226 void psTextCentered(struct psGfx *ps, double x, double y, 
00227         double width, double height, 
00228         char *text)
00229 /* Draw a line of text centered in box defined by x/y/width/height */
00230 {
00231 char c;
00232 y += (height - ps->fontHeight)/2;
00233 psMoveTo(ps, x+width/2, y + ps->fontHeight);
00234 fprintf(ps->f, "(");
00235 while ((c = *text++) != 0)
00236     {
00237     if (c == ')' || c == '(')
00238         fprintf(ps->f, "\\");
00239     fprintf(ps->f, "%c", c);
00240     }
00241 fprintf(ps->f, ") showMiddle\n");
00242 }
00243 
00244 void psTextDown(struct psGfx *ps, double x, double y, char *text)
00245 /* Output text going downwards rather than across at position. */
00246 {
00247 psMoveTo(ps, x, y);
00248 fprintf(ps->f, "gsave\n");
00249 fprintf(ps->f, "-90 rotate\n");
00250 fprintf(ps->f, "(%s) show\n", text);
00251 fprintf(ps->f, "grestore\n");
00252 }
00253 
00254 void psSetColor(struct psGfx *ps, int r, int g, int b)
00255 /* Set current color. */
00256 {
00257 FILE *f = ps->f;
00258 double scale = 1.0/255;
00259 if (r == g && g == b)
00260     {
00261     psFloatOut(f, scale * r);
00262     fprintf(f, "setgray\n");
00263     }
00264 else
00265     {
00266     psFloatOut(f, scale * r);
00267     psFloatOut(f, scale * g);
00268     psFloatOut(f, scale * b);
00269     fprintf(f, "setrgbcolor\n");
00270     }
00271 }
00272 
00273 void psSetGray(struct psGfx *ps, double grayVal)
00274 /* Set gray value. */
00275 {
00276 FILE *f = ps->f;
00277 if (grayVal < 0) grayVal = 0;
00278 if (grayVal > 1) grayVal = 1;
00279 psFloatOut(f, grayVal);
00280 fprintf(f, "setgray\n");
00281 }
00282 
00283 void psPushG(struct psGfx *ps)
00284 /* Save graphics state on stack. */
00285 {
00286 fprintf(ps->f, "gsave\n");
00287 }
00288 
00289 void psPopG(struct psGfx *ps)
00290 /* Pop off saved graphics state. */
00291 {
00292 fprintf(ps->f, "grestore\n");
00293 }
00294 
00295 void psDrawPoly(struct psGfx *ps, struct psPoly *poly, boolean filled)
00296 /* Draw a possibly filled polygon */
00297 {
00298 FILE *f = ps->f;
00299 struct psPoint *p = poly->ptList;
00300 fprintf(f, "newpath\n");
00301 psMoveTo(ps, p->x, p->y);
00302 for (;;)
00303     {
00304     p = p->next;
00305     psLineTo(ps, p->x, p->y);
00306     if (p == poly->ptList)
00307         break;
00308     }
00309 if (filled)
00310     {
00311     fprintf(f, "fill\n");
00312     }
00313 else
00314     {
00315     fprintf(f, "closepath\n");
00316     fprintf(f, "stroke\n");
00317     }
00318 }
00319 
00320 
00321 void psFillEllipse(struct psGfx *ps, double x, double y, double xrad, double yrad)
00322 {
00323 FILE *f = ps->f;
00324 fprintf(f, "newpath\n");
00325 psXyOut(ps, x, y);
00326 psWhOut(ps, xrad, yrad);
00327 fprintf(f, "%d %d ellipse\n",   0, 360);
00328 fprintf(f, "closepath\n");
00329 fprintf(f, "fill\n");
00330 }
00331 
00332 void psDrawEllipse(struct psGfx *ps, double x, double y, double xrad, double yrad,
00333     double startAngle, double endAngle)
00334 {
00335 FILE *f = ps->f;
00336 fprintf(f, "newpath\n");
00337 psXyOut(ps, x, y);
00338 psWhOut(ps, xrad, yrad);
00339 psFloatOut(f, startAngle);
00340 psFloatOut(f, endAngle);
00341 fprintf(f, "ellipse\n");
00342 fprintf(f, "closepath\n");
00343 fprintf(f, "stroke\n");
00344 }
00345 
00346 char * convertEpsToPdf(char *epsFile) 
00347 /* Convert EPS to PDF and return filename, or NULL if failure. */
00348 {
00349 char *pdfTmpName = NULL, *pdfName=NULL;
00350 char cmdBuffer[2048];
00351 int sysVal = 0;
00352 struct lineFile *lf = NULL;
00353 char *line;
00354 int lineSize=0;
00355 float width=0, height=0;
00356 pdfTmpName = cloneString(epsFile);
00357 
00358 /* Get the dimensions of bounding box. */
00359 lf = lineFileOpen(epsFile, TRUE);
00360 while(lineFileNext(lf, &line, &lineSize)) 
00361     {
00362     if(strstr( line, "BoundingBox:")) 
00363         {
00364         char *words[5];
00365         chopLine(line, words);
00366         width = atof(words[3]);
00367         height = atof(words[4]);
00368         break;
00369         }
00370     }
00371 lineFileClose(&lf);
00372         
00373 /* Do conversion. */
00374 chopSuffix(pdfTmpName);
00375 pdfName = addSuffix(pdfTmpName, ".pdf");
00376 safef(cmdBuffer, sizeof(cmdBuffer), "ps2pdf -dDEVICEWIDTHPOINTS=%d -dDEVICEHEIGHTPOINTS=%d %s %s", 
00377       round(width), round(height), epsFile, pdfName);
00378 sysVal = system(cmdBuffer);
00379 if(sysVal != 0)
00380     freez(&pdfName);
00381 freez(&pdfTmpName);
00382 return pdfName;
00383 }
00384 

Generated on Tue Dec 25 18:39:31 2007 for blat by  doxygen 1.5.2