1 /*****************************************************************************
2 ** Copyright (C) 1998-2001 Ljubomir Milanovic & Horst Wagner
3 ** This file is part of the g2 library
4 **
5 ** This library is free software; you can redistribute it and/or
6 ** modify it under the terms of the GNU Lesser General Public
7 ** License as published by the Free Software Foundation; either
8 ** version 2.1 of the License, or (at your option) any later version.
9 **
10 ** This library is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ** Lesser General Public License for more details.
14 **
15 ** You should have received a copy of the GNU Lesser General Public
16 ** License along with this library; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ******************************************************************************/
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <limits.h>
23 #include <math.h>
24 #include <string.h>
25
26 #include "g2.h"
27 #include "g2_device.h"
28 #include "g2_util.h"
29 #include "g2_config.h"
30
31 #include "g2_PS.h"
32 #include "g2_PS_P.h"
33 #include "g2_PS_funix.h"
34 #include "g2_PS_definitions.h"
35
36 static int N_PS=0;
37 static g2_PS_device *g2_PS_dev=NULL;
38
39 /**
40 * \ingroup physdev
41 * \defgroup PS PostScript
42 */
43
44
45 /*
46 *
47 * Attach generic PS device
48 *
49 */
g2_open_PS_generic(const char * file_name,enum g2_PS_paper paper,enum g2_PS_orientation orientation,enum g2_PS_format format,long width,long height)50 G2L int g2_open_PS_generic(const char *file_name,
51 enum g2_PS_paper paper,
52 enum g2_PS_orientation orientation,
53 enum g2_PS_format format,
54 long width,
55 long height)
56 {
57 g2_PS_device *psout=NULL;
58 int pid=-1, i;
59 int vid;
60 FILE *fp;
61
62 if((fp=fopen(file_name, "w"))==NULL) {
63 fprintf(stderr, "g2_attach_PS: Error! Can not open file '%s'\n",
64 file_name);
65 return -1;
66 }
67
68 if(g2_PS_dev==NULL) {
69 g2_PS_dev=g2_malloc(sizeof(g2_PS_device));
70 N_PS=1; /* first PS device */
71 psout=&g2_PS_dev[N_PS-1];
72 pid=0;
73 } else {
74 for(i=0;i<N_PS;i++) /* find free place */
75 if(g2_PS_dev[i].fp==NULL) {
76 psout=&g2_PS_dev[i];
77 pid=i;
78 break;
79 }
80 if(i==N_PS) { /* free place not avail. */
81 N_PS++;
82 g2_PS_dev=g2_realloc(g2_PS_dev,
83 sizeof(g2_PS_device)*N_PS);
84 psout=&g2_PS_dev[N_PS-1];
85 pid=N_PS-1;
86 }
87 }
88
89 vid = g2_register_physical_device(pid, NULL,
90 g2_DoubleCoor, g2_PS_funix,
91 1.0, 1.0,
92 0.0, 0.0);
93
94 psout->fp=fp; /* init PostScript structures */
95 psout->paper=paper;
96 psout->orient=orientation;
97 psout->format=format;
98 psout->width=width;
99 psout->height=height;
100 psout->inks=NULL;
101 psout->N_ink=0;
102 psout->pen=0;
103 psout->page_counter=0;
104 psout->bbox = 0;
105
106 g2_PS_write_file_header(psout);
107
108 g2_PS_set_line_width(pid, NULL, 0.0);
109 g2_PS_set_font_size(pid, NULL, 12.0);
110
111 /* g2 settings */
112 g2_allocate_basic_colors(vid);
113 g2_pen(vid, 1);
114
115 return vid;
116 }
117
118
119 /**
120 *
121 * Create a PS device.
122 *
123 * \param file_name postscript file name
124 * \param paper paper type, see ::g2_PS_paper and \ref appendix Appendix
125 * \param orientation paper orientation, see ::g2_PS_orientation
126 *
127 * \return physical device id
128 *
129 * \ingroup PS
130 */
g2_open_PS(const char * file_name,enum g2_PS_paper paper,enum g2_PS_orientation orientation)131 G2L int g2_open_PS(const char *file_name,
132 enum g2_PS_paper paper,
133 enum g2_PS_orientation orientation)
134 {
135 return g2_open_PS_generic(file_name,paper,orientation,g2_PS_PostScript,0,0);
136 }
137
138
139 /**
140 *
141 * Create an encapsulated PS device.
142 *
143 * \param file_name postscript file name
144 *
145 * \return physical device id
146 *
147 * \ingroup PS
148 */
g2_open_EPSF(const char * file_name)149 G2L int g2_open_EPSF(const char *file_name)
150 {
151 return g2_open_PS_generic(file_name,0,0,g2_PS_EPSF,0,0);
152 }
153
154
155 /**
156 *
157 * Create an encapsulated PS device with clipping.
158 *
159 * \param file_name postscript file name
160 * \param width clipping region width
161 * \param height clipping region height
162 *
163 * \return physical device id
164 *
165 * \ingroup PS
166 */
g2_open_EPSF_CLIP(const char * file_name,long width,long height)167 G2L int g2_open_EPSF_CLIP(const char *file_name,
168 long width, long height)
169 {
170 return g2_open_PS_generic(file_name,0,0,g2_PS_EPSF_CLIP,width,height);
171 }
172
173 /*
174 *
175 * Write header for postscript file
176 *
177 */
g2_PS_write_file_header(g2_PS_device * ps)178 int g2_PS_write_file_header(g2_PS_device *ps)
179 {
180 int i;
181 if (ps->format == g2_PS_PostScript)
182 {
183 fprintf(ps->fp,"%%!PS-Adobe-2.0\n");
184 switch(ps->orient)
185 {
186 case g2_PS_land:
187 fprintf(ps->fp,"%%%%Orientation: Landscape\n");
188 break;
189 case g2_PS_port:
190 fprintf(ps->fp,"%%%%Orientation: Portrait\n");
191 break;
192 }
193 }
194 else if (ps->format == g2_PS_EPSF_CLIP)
195 {
196 fprintf(ps->fp,"%%!PS-Adobe-3.0 EPSF-2.0\n");
197 fprintf(ps->fp,"%%%%BoundingBox: 0 0 %ld %ld\n",ps->width,ps->height);
198 }
199 else if (ps->format == g2_PS_EPSF)
200 {
201 fprintf(ps->fp,"%%!PS-Adobe-3.0 EPSF-2.0\n");
202 fprintf(ps->fp,"%%%%BoundingBox: (atend)\n");
203 }
204
205 fprintf(ps->fp,"%%%%Creator: g2 %s\n", G2_VERSION);
206 fprintf(ps->fp, "%%%%EndComments\n");
207
208 if (ps->format == g2_PS_EPSF_CLIP)
209 {
210 fprintf(ps->fp,"0 0 moveto\n");
211 fprintf(ps->fp,"0 %ld rlineto\n",ps->height);
212 fprintf(ps->fp,"%ld 0 rlineto\n",ps->width);
213 fprintf(ps->fp,"0 %ld rlineto\n",-ps->height);
214 fprintf(ps->fp,"closepath\n");
215 fprintf(ps->fp,"clip\n");
216 }
217
218 for(i=0;g2_PS_operators[i]!=NULL;i++)
219 fputs(g2_PS_operators[i], ps->fp);
220
221 fprintf(ps->fp,"newpath\n");
222 if((ps->orient==g2_PS_land) && (ps->format == g2_PS_PostScript))
223 fprintf(ps->fp,"%d 0 translate 90 rotate\n",
224 g2_PS_paper_size[ps->paper][0]);
225
226 fputs("%%PageTrailer\n%%Page: 1 1\n", ps->fp);
227
228 return 0;
229 }
230
231 /*
232 *
233 * Add circle at (x,y) of dimension size to bounding box
234 *
235 */
g2_PS_bbox_add(g2_PS_device * ps,double x,double y,double size)236 void g2_PS_bbox_add(g2_PS_device *ps,double x,double y,double size)
237 {
238 if (ps->bbox == 0) /* bbox is empty */
239 {
240 ps->x1=x-size;
241 ps->x2=x+size;
242 ps->y1=y-size;
243 ps->y2=y+size;
244 ps->bbox=1;
245 return;
246 }
247
248 if (ps->x1 > x-size)
249 ps->x1=x-size;
250 else if (ps->x2 < x+size)
251 ps->x2=x+size;
252
253 if (ps->y1 > y-size)
254 ps->y1=y-size;
255 else if (ps->y2 < y+size)
256 ps->y2=y+size;
257 return;
258 }
259
260 /*
261 *
262 * Delete PS device
263 *
264 */
g2_PS_delete(int pid,void * pdp)265 int g2_PS_delete(int pid, void *pdp)
266 {
267 g2_PS_device *ps=&g2_PS_dev[pid];
268 fprintf(ps->fp,"\nshowpage\n");
269 fprintf(ps->fp,"%%%%PageTrailer\n");
270 fprintf(ps->fp,"%%%%EndPage\n");
271 fprintf(ps->fp,"%%%%Trailer\n");
272 if (ps->format == g2_PS_EPSF)
273 {
274 fprintf(ps->fp,"%%%%BoundingBox: %d %d %d %d\n",
275 (int)floor(ps->x1),(int)floor(ps->y1),
276 (int)ceil(ps->x2),(int)ceil(ps->y2));
277 }
278 fprintf(ps->fp,"%%%%EOF\n");
279 fclose(ps->fp);
280 free(ps->inks);
281
282 ps->fp=NULL; /* free place */
283
284 return 0;
285 }
286
287
288
g2_PS_ink(int pid,void * pdp,double red,double green,double blue)289 int g2_PS_ink(int pid, void *pdp,
290 double red, double green, double blue)
291 {
292 g2_PS_device *ps=&g2_PS_dev[pid];
293 ps->N_ink++;
294 if(ps->inks==NULL)
295 ps->inks=(g2_PS_inks *)g2_malloc(ps->N_ink*
296 sizeof(g2_PS_inks));
297 else
298 ps->inks=(g2_PS_inks *)g2_realloc((void *)ps->inks,
299 ps->N_ink*
300 sizeof(g2_PS_inks));
301
302 ps->inks[ps->N_ink-1].r=red;
303 ps->inks[ps->N_ink-1].g=green;
304 ps->inks[ps->N_ink-1].b=blue;
305
306 return ps->N_ink-1;
307 }
308
309
310
g2_PS_pen(int pid,void * pdp,int color)311 int g2_PS_pen(int pid, void *pdp, int color)
312 {
313 g2_PS_device *ps=&g2_PS_dev[pid];
314 if(color>=ps->N_ink || color<0)
315 return -1;
316 fprintf(ps->fp,"%.4g %.4g %.4g setrgbcolor\n",
317 (double)ps->inks[color].r,
318 (double)ps->inks[color].g,
319 (double)ps->inks[color].b);
320 ps->pen=color;
321 return 0;
322 }
323
324
325
g2_PS_set_background(int pid,void * pdp,int color)326 int g2_PS_set_background(int pid, void *pdp, int color)
327 {
328 return 0;
329 }
330
331
332
g2_PS_clear_palette(int pid,void * pdp)333 int g2_PS_clear_palette(int pid, void *pdp)
334 {
335 g2_PS_device *ps=&g2_PS_dev[pid];
336 free((void *)ps->inks);
337 ps->N_ink=0;
338 ps->inks=NULL;
339 return 0;
340 }
341
342
343
g2_PS_set_line_width(int pid,void * pdp,double w)344 int g2_PS_set_line_width(int pid, void *pdp, double w)
345 {
346 g2_PS_device *ps=&g2_PS_dev[pid];
347 fprintf(ps->fp,"%.4g setlinewidth\n", w);
348 ps->w = w;
349 return 0;
350 }
351
352
353
g2_PS_set_dash(int pid,void * pdp,int N,double * data)354 int g2_PS_set_dash(int pid, void *pdp, int N, double *data)
355 {
356 g2_PS_device *ps=&g2_PS_dev[pid];
357 int i;
358 fprintf(ps->fp, "[ ");
359 for(i=0;i<N;i++)
360 if(data[i]>0.0)
361 fprintf(ps->fp, "%.4g ", data[i]);
362 fprintf(ps->fp, "] 0 setdash\n");
363 return 0;
364 }
365
366
367
g2_PS_set_font_size(int pid,void * pdp,double size)368 int g2_PS_set_font_size(int pid, void *pdp, double size)
369 {
370 g2_PS_device *ps=&g2_PS_dev[pid];
371 if(size<=0.0)
372 return -1;
373 fprintf(ps->fp,"%s findfont %.4g scalefont setfont\n", g2_PSFont, size);
374 ps->size = size;
375 return 0;
376 }
377
378
379
g2_PS_clear(int pid,void * pdp)380 int g2_PS_clear(int pid, void *pdp)
381 {
382 g2_PS_device *ps=&g2_PS_dev[pid];
383 fprintf(ps->fp, "gsave showpage\n");
384 fprintf(ps->fp, "%%%%PageTrailer\n%%%%EndPage\n");
385 fprintf(ps->fp, "%%%%Page: %d %d\ngrestore newpath\n",
386 ps->page_counter+1, ps->page_counter+1);
387 ps->page_counter++;
388 return 0;
389 }
390
391
392
g2_PS_flush(int pid,void * pdp)393 int g2_PS_flush(int pid, void *pdp)
394 {
395 g2_PS_device *ps=&g2_PS_dev[pid];
396 fflush(ps->fp);
397 return 0;
398 }
399
400
401
g2_PS_plot(int pid,void * pdp,double x,double y)402 int g2_PS_plot(int pid, void *pdp, double x, double y)
403 {
404 g2_PS_device *ps=&g2_PS_dev[pid];
405 fprintf(ps->fp,"%.4g %.4g P\n", x, y);
406 g2_PS_bbox_add(ps,x,y,1);
407 return 0;
408 }
409
410
411
g2_PS_line(int pid,void * pdp,double x1,double y1,double x2,double y2)412 int g2_PS_line(int pid, void *pdp, double x1, double y1, double x2, double y2)
413 {
414 g2_PS_device *ps=&g2_PS_dev[pid];
415 fprintf(ps->fp,"%.4g %.4g M %.4g %.4g L St\n",
416 x1, y1, x2, y2);
417 g2_PS_bbox_add(ps,x1,y1,ps->w);
418 g2_PS_bbox_add(ps,x2,y2,ps->w);
419 return 0;
420 }
421
422
423
g2_PS_poly_line(int pid,void * pdp,int N,double * points)424 int g2_PS_poly_line(int pid, void *pdp, int N, double *points)
425 {
426 g2_PS_device *ps=&g2_PS_dev[pid];
427 int i;
428 fprintf(ps->fp,"%.4g %.4g M\n", points[0], points[1]);
429 g2_PS_bbox_add(ps,points[0], points[1],ps->w);
430 for(i=2;i<2*N;i+=2)
431 {
432 fprintf(ps->fp, "%.4g %.4g L\n", points[i], points[i+1]);
433 g2_PS_bbox_add(ps,points[i], points[i+1],ps->w);
434 }
435 fprintf(ps->fp, "St\n");
436 return 0;
437 }
438
439
440
g2_PS_polygon(int pid,void * pdp,int N,double * points)441 int g2_PS_polygon(int pid, void *pdp, int N, double *points)
442 {
443 g2_PS_device *ps=&g2_PS_dev[pid];
444 int i;
445 fprintf(ps->fp,"%.4g %.4g M\n",points[0], points[1]);
446 g2_PS_bbox_add(ps,points[0], points[1],ps->w);
447 for(i=2;i<2*N;i+=2)
448 {
449 fprintf(ps->fp, "%.4g %.4g L\n", points[i], points[i+1]);
450 g2_PS_bbox_add(ps,points[i], points[i+1],ps->w);
451 }
452 fprintf(ps->fp, "%.4g %.4g L St\n", points[0], points[1]);
453 return 0;
454 }
455
456
457
g2_PS_filled_polygon(int pid,void * pdp,int N,double * points)458 int g2_PS_filled_polygon(int pid, void *pdp, int N, double *points)
459 {
460 g2_PS_device *ps=&g2_PS_dev[pid];
461 int i;
462 fprintf(ps->fp,"newpath %.4g %.4g M\n",points[0], points[1]);
463 g2_PS_bbox_add(ps,points[0], points[1],ps->w);
464 for(i=2;i<2*N;i+=2)
465 {
466 fprintf(ps->fp, "%.4g %.4g L\n", points[i], points[i+1]);
467 g2_PS_bbox_add(ps,points[i], points[i+1],ps->w);
468 }
469 fprintf(ps->fp, "%.4g %.4g L fill St\n", points[0], points[1]);
470 return 0;
471 }
472
473
474
g2_PS_rectangle(int pid,void * pdp,double x1,double y1,double x2,double y2)475 int g2_PS_rectangle(int pid, void *pdp,
476 double x1, double y1, double x2, double y2)
477 {
478 g2_PS_device *ps=&g2_PS_dev[pid];
479 fprintf(ps->fp,"%.4g %.4g %.4g %.4g R\n",
480 x2, y2, x1, y1);
481 g2_PS_bbox_add(ps,x1,y1,ps->w);
482 g2_PS_bbox_add(ps,x2,y2,ps->w);
483 return 0;
484 }
485
486
487
g2_PS_filled_rectangle(int pid,void * pdp,double x1,double y1,double x2,double y2)488 int g2_PS_filled_rectangle(int pid, void *pdp,
489 double x1, double y1, double x2, double y2)
490 {
491 g2_PS_device *ps=&g2_PS_dev[pid];
492 fprintf(ps->fp,"%.4g %.4g %.4g %.4g FR\n",
493 x2, y2, x1, y1);
494 g2_PS_bbox_add(ps,x1,y1,ps->w);
495 g2_PS_bbox_add(ps,x2,y2,ps->w);
496 return 0;
497 }
498
499
500
g2_PS_triangle(int pid,void * pdp,double x1,double y1,double x2,double y2,double x3,double y3)501 int g2_PS_triangle(int pid, void *pdp,
502 double x1, double y1,
503 double x2, double y2,
504 double x3, double y3)
505 {
506 g2_PS_device *ps=&g2_PS_dev[pid];
507 fprintf(ps->fp,"%.4g %.4g %.4g %.4g %.4g %.4g T\n",
508 x1,y1,x2,y2,x3,y3);
509 g2_PS_bbox_add(ps,x1,y1,ps->w);
510 g2_PS_bbox_add(ps,x2,y2,ps->w);
511 g2_PS_bbox_add(ps,x3,y3,ps->w);
512 return 0;
513 }
514
515
g2_PS_filled_triangle(int pid,void * pdp,double x1,double y1,double x2,double y2,double x3,double y3)516 int g2_PS_filled_triangle(int pid, void *pdp,
517 double x1, double y1,
518 double x2, double y2,
519 double x3, double y3)
520 {
521 g2_PS_device *ps=&g2_PS_dev[pid];
522 fprintf(ps->fp,"%.4g %.4g %.4g %.4g %.4g %.4g FT\n",
523 x1,y1,x2,y2,x3,y3);
524 g2_PS_bbox_add(ps,x1,y1,ps->w);
525 g2_PS_bbox_add(ps,x2,y2,ps->w);
526 g2_PS_bbox_add(ps,x3,y3,ps->w);
527 return 0;
528 }
529
530
531
g2_PS_arc(int pid,void * pdp,double x,double y,double r1,double r2,double a1,double a2)532 int g2_PS_arc(int pid, void *pdp,
533 double x, double y,
534 double r1, double r2,
535 double a1, double a2)
536 {
537 g2_PS_device *ps=&g2_PS_dev[pid];
538 if(a1==a2) {
539 a1=0;
540 a2=360;
541 }
542 fprintf(ps->fp,"%.4g %.4g %.4g %.4g %.4g %.4g A\n",
543 a1, a2, r1, r2, x, y);
544 g2_PS_bbox_add(ps,x+r1,y+r2,ps->w);
545 g2_PS_bbox_add(ps,x-r1,y-r2,ps->w);
546 return 0;
547 }
548
549
550
g2_PS_filled_arc(int pid,void * pdp,double x,double y,double r1,double r2,double a1,double a2)551 int g2_PS_filled_arc(int pid, void *pdp,
552 double x, double y,
553 double r1, double r2,
554 double a1, double a2)
555 {
556 g2_PS_device *ps=&g2_PS_dev[pid];
557 if(a1==a2) {
558 a1=0;
559 a2=360;
560 }
561 fprintf(ps->fp,"%.4g %.4g %.4g %.4g %.4g %.4g FA\n",
562 a1, a2, r1, r2, x, y);
563 g2_PS_bbox_add(ps,x+r1,y+r2,ps->w);
564 g2_PS_bbox_add(ps,x-r1,y-r2,ps->w);
565 return 0;
566 }
567
568
569
g2_PS_ellipse(int pid,void * pdp,double x,double y,double r1,double r2)570 int g2_PS_ellipse(int pid, void *pdp,
571 double x, double y,
572 double r1, double r2)
573 {
574 g2_PS_device *ps=&g2_PS_dev[pid];
575 fprintf(ps->fp,"0 360 %.4g %.4g %.4g %.4g A\n",
576 r1, r2, x, y);
577 g2_PS_bbox_add(ps,x+r1,y+r2,ps->w);
578 g2_PS_bbox_add(ps,x-r1,y-r2,ps->w);
579 return 0;
580 }
581
582
583
584
g2_PS_filled_ellipse(int pid,void * pdp,double x,double y,double r1,double r2)585 int g2_PS_filled_ellipse(int pid, void *pdp,
586 double x, double y,
587 double r1, double r2)
588 {
589 g2_PS_device *ps=&g2_PS_dev[pid];
590 fprintf(ps->fp,"0 360 %.4g %.4g %.4g %.4g FA\n",
591 r1, r2, x, y);
592 g2_PS_bbox_add(ps,x+r1,y+r2,ps->w);
593 g2_PS_bbox_add(ps,x-r1,y-r2,ps->w);
594 return 0;
595 }
596
597
598
g2_PS_draw_string(int pid,void * pdp,double x,double y,const char * text)599 int g2_PS_draw_string(int pid, void *pdp,
600 double x, double y, const char *text)
601 {
602 g2_PS_device *ps=&g2_PS_dev[pid];
603 fputc('(', ps->fp);
604 for(;*text!='\0';text++)
605 switch(*text) {
606 case '(':
607 fputs("\\(", ps->fp);
608 break;
609 case ')':
610 fputs("\\)", ps->fp);
611 break;
612 case '\\':
613 fputs("\\\\", ps->fp);
614 break;
615 default:
616 fputc(*text, ps->fp);
617 break;
618 }
619 fprintf(ps->fp,") %.4g %.4g S\n", x, y);
620 g2_PS_bbox_add(ps,x,y,ps->size);
621 g2_PS_bbox_add(ps,x+ps->size*strlen(text),y,ps->size);
622 return 0;
623 }
624
625