1 /*
2 * Fig2dev: Translate Fig code to various Devices
3 * Copyright (c) 1991 by Micah Beck
4 * Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
5 * Parts Copyright (c) 1989-2015 by Brian V. Smith
6 * Parts Copyright (c) 2015-2020 by Thomas Loimer
7 *
8 * Any party obtaining a copy of these files is granted, free of charge, a
9 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10 * nonexclusive right and license to deal in this software and documentation
11 * files (the "Software"), including without limitation the rights to use,
12 * copy, modify, merge, publish, distribute, sublicense and/or sell copies
13 * of the Software, and to permit persons who receive copies from any such
14 * party to do so, with the only requirement being that the above copyright
15 * and this permission notice remain intact.
16 *
17 */
18
19 /*
20 * genps.c: convert fig to PostScript
21 *
22 * Modified by Herbert Bauer to support ISO-Characters,
23 * multiple page output, color mode etc.
24 * heb@regent.e-technik.tu-muenchen.de
25 *
26 * Modified by Eric Picheral to support the whole set of ISO-Latin-1
27 * Modified by Herve Soulard to allow non-iso coding on special fonts
28 * Herve.Soulard@inria.fr (8 Apr 1993)
29 *
30 * Development for new extensions at TU Darmstadt, Germany starting 2002
31 * Allow to "build" pictures incrementally.
32 * To achieve this we split the complete figure into layers in separate
33 * ps-figures. The complete figure will be seen when overlapping all layers.
34 * A layer is combined from adjacent depths in xfig. This makes it possible
35 * to overlap items also when splitting into layers.
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41 #include "genps.h"
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #ifdef HAVE_STRINGS_H
47 #include <strings.h>
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include <math.h>
53 #include <ctype.h>
54 #include <sys/stat.h> /* struct stat */
55 #ifdef HAVE_GETPWUID
56 #include <pwd.h>
57 #endif
58 #include <locale.h>
59
60 #include "fig2dev.h" /* includes bool.h and object.h */
61 //#include "object.h" /* NUMSHADES, NUMTINTS */
62 #include "bound.h"
63 #include "colors.h" /* lookup_X_color(), rgb2luminance() */
64 #include "creationdate.h"
65 #include "encode.h"
66 #include "messages.h"
67 #include "pi.h"
68 #include "psfonts.h"
69 #include "readpics.h"
70 #include "xtmpfile.h"
71
72 /* include the PostScript preamble, patterns etc */
73 #include "psprolog.h"
74
75 extern int v2_flag, v21_flag, v30_flag; /* read.c */
76 #ifdef I18N
77 extern bool support_i18n; /* fig2dev.c */
78 #endif
79
80 /* exported symbols */
81 bool epsflag = false; /* to distinguish PS and EPS */
82 bool pdfflag = false; /* to distinguish PDF and PS/EPS */
83
84 /*
85 * The procedures to embed image files into ps code are defined in a number of
86 * source files (readgif.c, readjpg.c, readeps.c,...). These procedures could
87 * simply be included here in genps.c, which would result in an overwhelmingly
88 * big file. Reading procedures are separated into their respective files, but
89 * since they are used only here, the functions are declared here and separate
90 * header files are not written.
91 */
92 #define READ_SIGNATURE \
93 F_pic *pic, struct xfig_stream *restrict pic_stream, int *llx, int *lly
94 /* readeps.c */
95 extern int read_eps(READ_SIGNATURE);
96 extern int read_pdf(READ_SIGNATURE);
97 extern int append_epsi(FILE *in, const char *filename, FILE *out);
98 extern int pdftops(struct xfig_stream *restrict pic_stream, FILE *out);
99 /* readgif.c */
100 extern int read_gif(READ_SIGNATURE);
101 /* readjpg.c */
102 extern int read_jpg(READ_SIGNATURE);
103 extern void JPEGtoPS(FILE *f, FILE *PSfile);
104 /* readpcx.c */
105 extern int read_pcx(READ_SIGNATURE);
106 /* readpng.c */
107 #ifdef HAVE_PNG_H
108 extern int read_png(READ_SIGNATURE);
109 #endif
110 /* readppm.c */
111 extern int read_ppm(READ_SIGNATURE);
112 /* readtif.c */
113 extern int read_tif(READ_SIGNATURE);
114 /* readxbm.c */
115 extern int read_xbm(READ_SIGNATURE);
116 /* readxpm.c */
117 extern int read_xpm(READ_SIGNATURE);
118 #undef READ_SIGNATURE
119
120 #ifdef I18N
121 static bool enable_composite_font = false;
122 static bool append_find_composite(FILE *restrict out, FILE *restrict in);
123 #endif
124
125 #define POINT_PER_INCH 72
126 #define ULIMIT_FONT_SIZE 300
127 /* In order that gridlines have maximum depth */
128 #define MAXDEPTH 999
129 #define min(a, b) (((a) < (b)) ? (a) : (b))
130 #define SHADEVAL(F) 1.0*(F)/(NUMSHADES-1)
131 #define TINTVAL(F) 1.0*(F-NUMSHADES+1)/NUMTINTS
132 #define NEEDS_CLIPPING(obj) ((obj->for_arrow || obj->back_arrow) &&\
133 obj->thickness > 0)
134
135 /* variables obtained from command line options */
136 static bool anonymous = true;
137 static bool asciipreview = false; /* add ASCII preview? */
138 static bool tiffpreview = false; /* add a TIFF preview? */
139 static bool tiffcolor = false; /* color or b/w TIFF preview */
140 static int border_margin = 0;
141 static bool correct_font_size = false;
142 static int pagewidth = -1;
143 static int pageheight = -1;
144 static bool useabsolutecoo = false;
145 static int xoff=0;
146 static int yoff=0;
147
148 static FILE *saveofile; /* temp filename for eps when adding tiff preview */
149 static char tmpeps_buf[128] = "f2depsXXXXXX"; /* temp filename for
150 ASCII or tiff preview */
151 static char tmpprev_buf[128] = "f2dprevXXXXXX";
152 static char *tmpeps = tmpeps_buf;
153 static char *tmpprev = tmpprev_buf;
154 static int width, height;
155 static double cur_thickness = 0.0;
156 static int cur_joinstyle = 0;
157 static int cur_capstyle = 0;
158 static int pages;
159 static int no_obj = 0;
160 static float fllx, flly, furx, fury;
161 static double scalex, scaley;
162 static double origx, origy;
163 static double userorigx, userorigy;
164 static double userwidthx, userwidthy;
165
166 /* arrowhead arrays */
167 static F_pos bpoints[50], fpoints[50];
168 static int nbpoints, nfpoints;
169 static F_pos bfillpoints[50], ffillpoints[50], clippoints[50];
170 static int nbfillpoints, nffillpoints, nclippoints;
171 static int fpntx1, fpnty1; /* first point of object */
172 static int fpntx2, fpnty2; /* second point of object */
173 static int lpntx1, lpnty1; /* last point of object */
174 static int lpntx2, lpnty2; /* second-to-last point of object */
175 /*
176 * Static variables for variant methods:
177 * fig_number has the "current" figure number which has been created.
178 * last_depth remembers the last level number processed
179 * (we need a sufficiently large initial value)
180 */
181 static int fig_number = 0;
182 static int last_depth = MAXDEPTH + 4;
183
184 /* local procedures */
185 static int append(const char *restrict infilename, FILE *restrict outfile);
186 static void appendhex(char *infilename,FILE *outfile,int width,int height);
187 static bool approx_spline_exist(F_compound *ob);
188 static void do_split(int actual_depth);/* split different depths' objects */
189 /* but only as comment */
190 static void clip_arrows(F_line *obj, int objtype);
191 static void draw_arrow(F_arrow *arrow, F_pos *points, int npoints,
192 F_pos *fillpoints, int nfillpoints, int col);
193 static void draw_gridline(float x1, float y1, float x2, float y2);
194 static bool ellipse_exist(F_compound *ob);
195 static void encode_all_fonts(F_compound *ob);
196 static void fill_area(int fill, int pen_color, int fill_color);
197 static void genps_ctl_spline(F_spline *s);
198 static void genps_itp_spline(F_spline *s);
199 static void genps_std_colors(void);
200 static void genps_usr_colors(void);
201 static bool iso_text_exist(F_compound *ob);
202 static void putword(int word, FILE *file);
203 static void set_linewidth(double w);
204
205 /* define the standard 32 colors */
206 struct _rgb {
207 double r, g, b;
208 } rgbcols[NUM_STD_COLS] = {
209 {0.00, 0.00, 0.00}, /* black */
210 {0.00, 0.00, 1.00}, /* blue */
211 {0.00, 1.00, 0.00}, /* green */
212 {0.00, 1.00, 1.00}, /* cyan */
213 {1.00, 0.00, 0.00}, /* red */
214 {1.00, 0.00, 1.00}, /* magenta */
215 {1.00, 1.00, 0.00}, /* yellow */
216 {1.00, 1.00, 1.00}, /* white */
217 {0.00, 0.00, 0.56}, /* blue1 */
218 {0.00, 0.00, 0.69}, /* blue2 */
219 {0.00, 0.00, 0.82}, /* blue3 */
220 {0.53, 0.81, 1.00}, /* blue4 */
221 {0.00, 0.56, 0.00}, /* green1 */
222 {0.00, 0.69, 0.00}, /* green2 */
223 {0.00, 0.82, 0.00}, /* green3 */
224 {0.00, 0.56, 0.56}, /* cyan1 */
225 {0.00, 0.69, 0.69}, /* cyan2 */
226 {0.00, 0.82, 0.82}, /* cyan3 */
227 {0.56, 0.00, 0.00}, /* red1 */
228 {0.69, 0.00, 0.00}, /* red2 */
229 {0.82, 0.00, 0.00}, /* red3 */
230 {0.56, 0.00, 0.56}, /* magenta1 */
231 {0.69, 0.00, 0.69}, /* magenta2 */
232 {0.82, 0.00, 0.82}, /* magenta3 */
233 {0.50, 0.19, 0.00}, /* brown1 */
234 {0.63, 0.25, 0.00}, /* brown2 */
235 {0.75, 0.38, 0.00}, /* brown3 */
236 {1.00, 0.50, 0.50}, /* pink1 */
237 {1.00, 0.63, 0.63}, /* pink2 */
238 {1.00, 0.75, 0.75}, /* pink3 */
239 {1.00, 0.88, 0.88}, /* pink4 */
240 {1.00, 0.84, 0.00} /* gold */
241 };
242
243 static char *psfontnames[] = {
244 "Times-Roman", "Times-Roman", /* default */
245 "Times-Roman", /* roman */
246 "Times-Bold", /* bold */
247 "Times-Italic", /* italic */
248 "Helvetica", /* sans serif */
249 "Courier" /* typewriter */
250 };
251
252 #define PS_FONTNAMES(T) \
253 (((v2_flag&&!(v21_flag||v30_flag)) || \
254 psfont_text(T)) ? PSfontnames : psfontnames)
255
256 #define PSFONT(T) \
257 ((T->font) <= MAXFONT(T) ? PS_FONTNAMES(T)[T->font+1] : PS_FONTNAMES(T)[0])
258
259 #define PSFONTMAG(T) (((T->size) <= ULIMIT_FONT_SIZE ? \
260 T->size : ULIMIT_FONT_SIZE) \
261 * ppi/(correct_font_size? (metric ? 72*80/76.2 : 72): 80))
262
263 /* define the fill patterns */
264 static char *fill_def[NUMPATTERNS] = {
265 FILL_PAT01,FILL_PAT02,FILL_PAT03,FILL_PAT04,
266 FILL_PAT05,FILL_PAT06,FILL_PAT07,FILL_PAT08,
267 FILL_PAT09,FILL_PAT10,FILL_PAT11,FILL_PAT12,
268 FILL_PAT13,FILL_PAT14,FILL_PAT15,FILL_PAT16,
269 FILL_PAT17,FILL_PAT18,FILL_PAT19,FILL_PAT20,
270 FILL_PAT21,FILL_PAT22,
271 };
272
273 /* headers for various image files */
274 static struct hdr {
275 char *type;
276 char *bytes;
277 int (*readfunc)();
278 bool pipeok;
279 /* buf[12] below must be large enough for the file signature */
280 } headers[] = { {"GIF", "GIF", read_gif, false},
281 #ifdef V4_0
282 {"FIG", "#FIG", read_figure, true},
283 #endif /* V4_0 */
284 {"PCX", "\012\005\001", read_pcx, true},
285 {"EPS", "%!", read_eps, true},
286 {"EPSI", "\xc5\xd0\xd3\xc6", read_eps, true},
287 {"PDF", "%PDF", read_pdf, true},
288 {"PPM", "P3", read_ppm, true},
289 {"PPM", "P6", read_ppm, true},
290 {"TIFF", "II*\000", read_tif, false},
291 {"TIFF", "MM\000*", read_tif, false},
292 {"XBM", "#define", read_xbm, true},
293 #ifdef HAVE_PNG_H
294 {"PNG", "\211\120\116\107\015\012\032\012",
295 read_png, true},
296 #endif
297 {"JPEG", "\377\330\377\340", read_jpg, true},
298 {"JPEG", "\377\330\377\341", read_jpg, true},
299 {"XPM", "/* XPM */", read_xpm, false},
300 };
301
302 #define NUMHEADERS (sizeof(headers)/sizeof(headers[0]))
303
304
305 /******************************/
306 /* various methods start here */
307 /******************************/
308
309 static void
write_data(FILE * out,char * name,unsigned char * in,size_t len)310 write_data(FILE *out, char *name, unsigned char *in, size_t len)
311 {
312 #ifdef HAVE_ZLIB_H
313 if (deflate_ascii85encode(out, in, len)) {
314 put_msg("Could not compress image %s.", name);
315 exit(EXIT_FAILURE);
316 }
317 #else
318 if (ascii85encode(out, in, len)) {
319 put_msg("Could not embed image %s.", name);
320 exit(EXIT_FAILURE);
321 }
322 #endif
323 /* Output end of data marker for the ascii85 encoded stream */
324 fputs("~>\n", out);
325 }
326
327 /*
328 * the image dictionary string is needed twice,
329 * here and in indexed_image() below
330 */
331 #ifdef HAVE_ZLIB_H
332 #define DATASOURCE " /DataSource Data /FlateDecode filter\n"
333 #else
334 #define DATASOURCE " /DataSource Data\n"
335 #endif
336
337 static void
write_rgbimage(FILE * out,F_pic * pic)338 write_rgbimage(FILE *out, F_pic *pic)
339 {
340 fputs( "/Data currentfile /ASCII85Decode filter def\n"
341 "/DeviceRGB setcolorspace\n", out);
342
343 if (pic->num_transp == NO_TRANSPARENCY ||
344 /* != TRANSP_COLOR should not happen */
345 pic->num_transp != TRANSP_COLOR) {
346 fputs( " << /ImageType 1\n", out);
347 } else { /* transparency by color key masking */
348 fputs( " << /ImageType 4\n", out);
349 fprintf(out, " /MaskColor [ %d %d %d ]\n",
350 pic->transp_col[RED], pic->transp_col[GREEN],
351 pic->transp_col[BLUE]);
352 }
353 /* gcc warned: %1$d not ISO C */
354 fprintf(out, " /Width %d /Height %d\n"
355 " /ImageMatrix [ %d 0 0 -%d 0 %d ]\n",
356 pic->bit_size.x, pic->bit_size.y,
357 pic->bit_size.x, pic->bit_size.y, pic->bit_size.y);
358 fputs( DATASOURCE
359 " /BitsPerComponent 8 /Decode [0 1 0 1 0 1]\n"
360 " >> xfig_image\n", out);
361
362 write_data(out, pic->file, pic->bitmap,
363 (size_t)pic->bit_size.x * pic->bit_size.y * 3);
364 }
365
366 static void
indexed_image(FILE * out,F_pic * pic)367 indexed_image(FILE *out, F_pic *pic)
368 {
369 int i = 0;
370
371 fprintf(out,
372 "/Data currentfile /ASCII85Decode filter def\n"
373 "[ /Indexed /DeviceRGB %d\n <", pic->numcols - 1);
374 /* write the hex-encoded colormap */
375 fprintf(out, "%.2hhx%.2hhx%.2hhx", pic->cmap[RED][i],
376 pic->cmap[GREEN][i], pic->cmap[BLUE][i]);
377 for (i = 1; i < pic->numcols; ++i) {
378 if (i % 11 == 0)
379 fputs("\n ", out);
380 fprintf(out, " %.2hhx%.2hhx%.2hhx", pic->cmap[RED][i],
381 pic->cmap[GREEN][i], pic->cmap[BLUE][i]);
382 }
383 fputs( ">\n] setcolorspace\n", out);
384 /* continue with image dictionary */
385 if (pic->num_transp == NO_TRANSPARENCY ||
386 pic->num_transp == TRANSP_COLOR) { /* colormap only! */
387 fputs( " << /ImageType 1\n", out);
388 } else { /* transparent color */
389 fputs( " << /ImageType 4\n /MaskColor [ ", out);
390 for (i = 0; i < pic->num_transp; ++i)
391 fprintf(out, "%d ", pic->transp_cols[i]);
392 fputs("]\n", out);
393 }
394 fprintf(out, " /Width %d /Height %d\n"
395 " /ImageMatrix [ %d 0 0 -%d 0 %d ]\n",
396 pic->bit_size.x, pic->bit_size.y,
397 pic->bit_size.x, pic->bit_size.y, pic->bit_size.y);
398 fputs( DATASOURCE
399 " /BitsPerComponent 8 /Decode [0 255]\n"
400 " >> xfig_image\n", out);
401
402 write_data(out, pic->file, pic->bitmap,
403 (size_t)pic->bit_size.x * pic->bit_size.y);
404 }
405
406
407 /******************************/
408 /* main procedures start here */
409 /******************************/
410
411 void
geneps_option(char opt,char * optarg)412 geneps_option(char opt, char *optarg)
413 {
414 static bool init = false;
415 if (!init) {
416 init = true;
417 epsflag = true;
418 }
419 gen_ps_eps_option(opt, optarg);
420 }
421
422 void
genps_option(char opt,char * optarg)423 genps_option(char opt, char *optarg)
424 {
425 gen_ps_eps_option(opt, optarg);
426 }
427
428 void
gen_ps_eps_option(char opt,char * optarg)429 gen_ps_eps_option(char opt, char *optarg)
430 {
431 int i;
432
433 switch (opt) {
434
435 /* don't do anything for the following args (already parsed in main) */
436 case 'G': /* grid */
437 case 'L': /* language */
438 /* option parsed in genpdf_option(), genpdf.c */
439 case 'P': /* pagemode */
440 break;
441
442 case 'a': /* anonymous (don't output user name) */
443 anonymous = true;
444 break;
445
446 case 'A': /* add ASCII preview */
447 asciipreview = true;
448 break;
449
450 case 'b': /* border margin around figure */
451 sscanf(optarg,"%d",&border_margin);
452 break;
453
454 case 'B': /* bounding box in absolute coordinates */
455 if (epsflag) {
456 (void) strcpy (boundingbox, optarg);
457 boundingboxspec = true; /* user-specified */
458 useabsolutecoo = true;
459 }
460 break;
461
462 case 'C': /* add color TIFF preview (for MicroSloth) */
463 tiffpreview = true;
464 tiffcolor = true;
465 break;
466
467 case 'c': /* center figure */
468 if (!epsflag) {
469 center = true;
470 centerspec = true; /* user-specified */
471 }
472 break;
473
474 case 'e': /* don't center ('e' means edge) figure */
475 if (!epsflag) {
476 center = false;
477 centerspec = true; /* user-specified */
478 }
479 break;
480 case 'F': /* fontsize */
481 correct_font_size = true;
482 break;
483
484 case 'f': /* default font name */
485 for ( i = 1; i <= MAX_PSFONT; i++ )
486 if (!strcmp(optarg, PSfontnames[i]))
487 break;
488
489 if ( i > MAX_PSFONT )
490 fprintf(stderr, "warning: non-standard font name %s\n",
491 optarg);
492
493 psfontnames[0] = psfontnames[1] = optarg;
494 PSfontnames[0] = PSfontnames[1] = optarg;
495 break;
496
497 case 'g': /* background color */
498 if (lookup_X_color(optarg,&background) >= 0) {
499 bgspec = true;
500 } else {
501 fprintf(stderr,
502 "Can't parse color '%s', ignoring background option\n",
503 optarg);
504 }
505 break;
506
507 case 'l': /* landscape mode */
508 if (!epsflag) {
509 landscape = true; /* override the figure file setting */
510 orientspec = true; /* user-specified */
511 }
512 break;
513
514 case 'M': /* multi-page option */
515 if (!epsflag) {
516 multi_page = true;
517 multispec = true; /* user has overridden anything in file */
518 }
519 break;
520
521 case 'n': /* name to put in the "Title:" spec */
522 name = optarg;
523 break;
524
525 case 'N': /* convert colors to grayscale */
526 grayonly = true;
527 break;
528
529 case 'O': /* overlap multipage output */
530 if (!epsflag)
531 overlap = true;
532 break;
533
534 case 'o': /* turn off multi-page option */
535 if (!epsflag) {
536 multi_page = false;
537 multispec = true; /* user has overridden anything in file */
538 }
539 break;
540
541 case 'p': /* portrait mode */
542 if (!epsflag) {
543 landscape = false; /* override the figure file setting */
544 orientspec = true; /* user-specified */
545 }
546 break;
547
548 case 'R': /* boundingbox in relative coordinates */
549 if (epsflag) {
550 (void) strcpy (boundingbox, optarg);
551 boundingboxspec = true; /* user-specified */
552 }
553 break;
554
555 case 'T': /* add monochrome TIFF preview */
556 tiffpreview = true;
557 tiffcolor = false;
558 break;
559
560 case 'x': /* x offset on page */
561 if (!epsflag) {
562 xoff = atoi(optarg);
563 }
564 break;
565
566 case 'y': /* y offset on page */
567 if (!epsflag) {
568 yoff = atoi(optarg);
569 }
570 break;
571
572 case 'z': /* papersize */
573 if (!epsflag) {
574 (void) strcpy (papersize, optarg);
575 paperspec = true; /* user-specified */
576 }
577 break;
578
579 default:
580 put_msg(Err_badarg, opt, "ps");
581 exit(1);
582 }
583 }
584
585 void
genps_start(F_compound * objects)586 genps_start(F_compound *objects)
587 {
588 char host[256];
589 char date_buf[CREATION_TIME_LEN];
590 struct passwd *who;
591 int itmp, jtmp;
592 int i;
593 int cliplx, cliply, clipux, clipuy;
594 int userllx, userlly, userurx, userury;
595 const struct paperdef *pd;
596 char psize[20];
597
598 char *libdir;
599 char filename[512];
600
601 /* make sure user isn't asking for both TIFF and ASCII preview */
602 if (tiffpreview && asciipreview) {
603 put_msg("Only one type of preview allowed: -A or -T/-C");
604 exit(EXIT_FAILURE);
605 }
606
607 /* if the user wants a TIFF preview, route the eps file
608 to a temporary one */
609 if (tiffpreview) {
610 saveofile = tfp;
611 /* make name for temp output file */
612 if ((tfp = xtmpfile(&tmpeps, sizeof tmpeps_buf)) == NULL) {
613 put_msg("Can not create temporary file %s", tmpeps);
614 put_msg("No preview will be produced.");
615 if (tmpeps != tmpeps_buf)
616 free(tmpeps);
617 tfp = saveofile;
618 tiffpreview = false;
619 }
620 }
621
622 /* now that the file has been read,
623 turn off multipage mode if eps output */
624 if (epsflag)
625 multi_page = false;
626
627 scalex = scaley = mag * POINT_PER_INCH / ppi;
628
629 /* this seems to work around Solaris' cc optimizer bug */
630 /* the problem was that llx had garbage in it - this "fixes" it */
631 sprintf(host,"llx=%d\n",llx);
632
633 /* convert to point unit */
634 fllx = llx * scalex;
635 flly = lly * scaley;
636 furx = urx * scalex;
637 fury = ury * scaley;
638
639 /* adjust for any border margin */
640
641 fllx -= border_margin;
642 flly -= border_margin;
643 furx += border_margin;
644 fury += border_margin;
645
646 /* convert ledger (deprecated) to tabloid */
647 if (strcasecmp(papersize, "ledger") == 0)
648 strcpy(papersize, "tabloid");
649 for (pd = paperdef; pd->name != NULL; ++pd) {
650 if (strcasecmp(papersize, pd->name) == 0) {
651 pagewidth = pd->width;
652 pageheight = pd->height;
653 strcpy(papersize, pd->name); /* use the "nice" form */
654 break;
655 }
656 }
657
658 if (pagewidth < 0 || pageheight < 0) {
659 put_msg("Unknown paper size `%s'", papersize);
660 exit (1);
661 }
662
663 if (epsflag) {
664 /* shift figure to 0,0 */
665 origx = -fllx;
666 origy = fury;
667 if (boundingboxspec) {
668 jtmp = sscanf(boundingbox, "%lf %lf %lf %lf",
669 &userwidthx, &userwidthy,
670 &userorigx, &userorigy);
671 switch (jtmp) {
672 case 0:
673 userwidthx=(furx-fllx)/POINT_PER_INCH;
674 if (metric)
675 userwidthx *= 2.54;
676 /* the comment below silences gcc's
677 -Wimplicit-fallthrough warning */
678 /* intentionally fall through */
679 /* and set the other user... vars */
680 case 1:
681 userwidthy=(fury-flly)/POINT_PER_INCH;
682 if (metric)
683 userwidthy *= 2.54;
684 /* intentionally fall through */
685 /* and set the other user... vars */
686 case 2:
687 userorigx=0;
688 /* intentionally fall through */
689 /* and set the last user... var */
690 case 3:
691 userorigy=0;
692 }
693 if (userwidthx <= 0) {
694 userwidthx=(furx-fllx)/POINT_PER_INCH;
695 if (metric)
696 userwidthx *= 2.54;
697 }
698 if (userwidthy <= 0) {
699 userwidthy=(fury-flly)/POINT_PER_INCH;
700 if (metric)
701 userwidthy *= 2.54;
702 }
703
704 userorigx *= POINT_PER_INCH;
705 userorigy *= POINT_PER_INCH;
706 userwidthx *= POINT_PER_INCH;
707 userwidthy *= POINT_PER_INCH;
708
709 if (metric) {
710 userorigx /= 2.54;
711 userorigy /= 2.54;
712 userwidthx /= 2.54;
713 userwidthy /= 2.54;
714 }
715
716 userllx = (int) floor(userorigx);
717 userlly = (int) floor(userorigy);
718 userurx = (int) ceil(userorigx+userwidthx);
719 userury = (int) ceil(userorigy+userwidthy);
720
721 /* adjust for any border margin */
722 userllx -= border_margin;
723 userlly -= border_margin;
724 userurx += border_margin;
725 userury += border_margin;
726
727 if (useabsolutecoo) {
728 userllx += origx;
729 userurx += origx;
730 }
731 }
732 } else { /* postscript */
733 if (landscape) {
734 itmp = pageheight;
735 pageheight = pagewidth;
736 pagewidth = itmp;
737 }
738 if (center) {
739 origx = (pagewidth - furx - fllx)/2.0;
740 origy = (pageheight + fury + flly)/2.0;
741 } else {
742 origx = 0.0;
743 origy = pageheight;
744 }
745 }
746
747 /* finally, adjust by any offset the user wants */
748 if (!epsflag) {
749 origx += xoff;
750 origy += yoff;
751 }
752
753 if (epsflag)
754 fputs("%!PS-Adobe-3.0 EPSF-3.0\n", tfp);
755 else
756 fputs("%!PS-Adobe-3.0\n", tfp);
757
758 #ifdef HAVE_GETHOSTNAME
759 if (gethostname(host, sizeof(host)) == -1)
760 #endif
761 (void) strcpy(host, "unknown host");
762 fprintf(tfp, "%%%%Title: %s\n",
763 (name? name: ((from) ? from : "stdin")));
764 fprintf(tfp, "%%%%Creator: %s Version %s\n",
765 prog, PACKAGE_VERSION);
766 if (creation_date(date_buf))
767 fprintf(tfp, "%%%%CreationDate: %s\n", date_buf);
768 #ifdef HAVE_GETPWUID
769 if (!anonymous) {
770 who = getpwuid(getuid());
771 if (who)
772 fprintf(tfp, "%%%%For: %s@%s (%s)\n",
773 who->pw_name, host, who->pw_gecos);
774 }
775 #endif
776
777 /* calc initial clipping area to size of the bounding box
778 (this is needed for later clipping by arrowheads) */
779 cliplx = cliply = 0;
780 if (epsflag) {
781 clipux = (int) ceil(furx-fllx);
782 clipuy = (int) ceil(fury-flly);
783 pages = 1;
784 } else {
785 clipux = pagewidth;
786 clipuy = pageheight;
787 if (multi_page)
788 /* account for overlap */
789 pages = (int)(1.11111 * (furx - 0.1*pagewidth)
790 / pagewidth + 1) *
791 (int)(1.11111 * (fury - 0.1*pageheight)
792 / pageheight + 1);
793 else
794 pages = 1;
795 /*
796 * If the line %%Orientation: Landscape is included, then
797 * - evince displays the page rotated by -90 degrees,
798 * - the apple previewer (v8.1) displays it correctly,
799 * - gs displays the ps-file correctly, but
800 * - the pdf produced from this ps is rotated by -90 degrees
801 * Therefore, omit the %%Orientation comment. Although, I
802 * believe, evince and the pdf produced by gs do not get the
803 * %%Orientation comment right.
804 * The PostScript Language Document Structuring Conventions
805 * Specification, Version 3.0, says to %%Orientation:
806 * This comment indicates the orientation of the pages in the
807 * document. It can be used by previewing applications and
808 * post-processors to determine how to orient the viewing
809 * window. A portrait orientation indicates that the longest
810 * edge of the paper is parallel to the vertical (y) axis. A
811 * landscape orientation indicates that the longest edge of the
812 * paper is parallel to the horizontal (x) axis. If more than
813 * one orientation applies to the document, an individual page
814 * should specify its orientation by using the
815 * %%PageOrientation: comment.
816 if (landscape)
817 fputs("%%Orientation: Landscape\n", tfp);
818 else
819 fputs("%%Orientation: Portrait\n", tfp);
820 */
821 }
822 if (!epsflag) {
823 /* only print Pages if PostScript or PDF */
824 fprintf(tfp, "%%%%Pages: %d\n", pages );
825 }
826 if (!boundingboxspec) {
827 fprintf(tfp, "%%%%BoundingBox: %d %d %d %d\n",
828 cliplx, cliply, clipux, clipuy);
829 /* width for tiff preview */
830 width = clipux-cliplx+1;
831 height = clipuy-cliply+1;
832 } else {
833 fprintf(tfp, "%%%%BoundingBox: %d %d %d %d\n",
834 userllx, userlly, userurx, userury);
835 /* width for tiff preview */
836 width = userurx - userllx + 1;
837 height = userury - userlly + 1;
838 }
839
840 /* only include a pagesize command if PS */
841 if (!epsflag) {
842 /* add comment for ghostview to recognize the page size */
843 /* make sure to use the lowercase paper size name */
844 strcpy(psize,papersize);
845 for (i = strlen(psize)-1; i >= 0; --i)
846 psize[i] = tolower(psize[i]);
847 fprintf(tfp, "%%%%DocumentPaperSizes: %s\n", psize);
848 }
849
850 /* put in the magnification for information purposes */
851 fprintf(tfp, "%%%%Magnification: %.4f\n",metric? mag*76.2/80.0 : mag);
852 fputs("%%EndComments\n", tfp);
853
854 /* This %%BeginSetup .. %%EndSetup has to occur after
855 * %%EndComments even though it includes comments, they are
856 * not header comments. The header comment block must be
857 * contiguous, with no non-comment lines in it.
858 */
859 if (!epsflag && !pdfflag) {
860 fputs("%%BeginSetup\n", tfp);
861 fputs("[{\n", tfp);
862 fprintf(tfp, "%%%%BeginFeature: *PageSize %s\n", papersize);
863 fprintf(tfp, "<</PageSize [%d %d]>> setpagedevice\n",
864 pagewidth, pageheight);
865 fputs("%%EndFeature\n", tfp);
866 fputs("} stopped cleartomark\n", tfp);
867 fputs("%%EndSetup\n", tfp);
868 } else if (pdfflag) {
869 /* set the page size for PDF to the figure size */
870 fprintf(tfp, "<< /PageSize [%d %d] >> setpagedevice\n",
871 clipux - cliplx, clipuy - cliply);
872 }
873
874 /* if the user wants an ASCII preview,
875 route the rest of the eps to a temp file */
876 if (asciipreview) {
877 saveofile = tfp;
878 /* make name for temp output file */
879 if ((tfp = xtmpfile(&tmpeps, sizeof tmpeps_buf)) == NULL) {
880 fprintf(stderr, "Can not create temporary file %s.\n", tmpeps);
881 fputs("No preview will be produced.\n", stderr);
882 if (tmpeps != tmpeps_buf)
883 free(tmpeps);
884 asciipreview = false;
885 tfp = saveofile;
886 }
887 }
888
889 /* print any whole-figure comments prefixed with "%" */
890 if (objects->comments) {
891 fputs("%\n", tfp);
892 print_comments("% ",objects->comments, "");
893 fputs("%\n", tfp);
894 }
895
896 /* insert PostScript codes to select paper size, if exist */
897 libdir = getenv("FIG2DEV_LIBDIR");
898 #ifdef I18N_DATADIR
899 if (libdir == NULL)
900 libdir = I18N_DATADIR;
901 #endif
902 if (libdir != NULL) {
903 sprintf(filename, "%s/%s.ps", libdir, papersize);
904 /* get filename like "/usr/local/lib/fig2dev/A3.ps" and
905 prepend it to the postscript code;
906 do not mind, if it does not work */
907 (void)append(filename, tfp);
908 }
909
910 fputs("%%BeginProlog\n", tfp);
911 if (pats_used)
912 fprintf(tfp,"/MyAppDict 100 dict dup begin def\n");
913 fprintf(tfp, "%s", BEGIN_PROLOG1);
914 /* define the standard colors */
915 genps_std_colors();
916 /* define the user colors */
917 genps_usr_colors();
918 fputs("\nend\n", tfp);
919
920 /* fill the Background now if specified */
921 if (bgspec) {
922 fprintf(tfp, "%% Fill background color\n");
923 fprintf(tfp, "%d %d moveto %d %d lineto ",
924 cliplx, cliply, clipux, cliply);
925 fprintf(tfp, "%d %d lineto %d %d lineto\n",
926 clipux, clipuy, cliplx, clipuy);
927 if (grayonly)
928 fprintf(tfp, "closepath %.2f setgray fill\n\n",
929 rgb2luminance(background.red/65535.0,
930 background.green/65535.0,
931 background.blue/65535.0));
932 else
933 fprintf(tfp,
934 "closepath %.2f %.2f %.2f setrgbcolor fill\n\n",
935 background.red/65535.0,
936 background.green/65535.0,
937 background.blue/65535.0);
938 }
939
940 /* translate (in multi-page mode this is done at end of this proc) */
941 /* (rotation and y flipping is done in %%BeginPageSetup area */
942 if (pats_used) {
943 int i;
944 /* only define the patterns that are used */
945 for (i=0; i<NUMPATTERNS; i++)
946 if (pattern_used[i])
947 fprintf(tfp, "\n%s", fill_def[i]);
948 }
949 fprintf(tfp, "\n%s", BEGIN_PROLOG2);
950 if (iso_text_exist(objects)) {
951 fprintf(tfp, "%s%s%s",
952 SPECIAL_CHAR_1, SPECIAL_CHAR_2, SPECIAL_CHAR_3);
953 encode_all_fonts(objects);
954 }
955 if (ellipse_exist(objects))
956 fprintf(tfp, "%s\n", ELLIPSE_PS);
957 if (approx_spline_exist(objects))
958 fprintf(tfp, "%s\n", SPLINE_PS);
959 #ifdef I18N
960 if (support_i18n && iso_text_exist(objects)) {
961 char *libdir, *locale;
962 char localefile_buf[128];
963 char *localefile = localefile_buf;
964 FILE *fp;
965 libdir = getenv("FIG2DEV_LIBDIR");
966 #ifdef I18N_DATADIR
967 if (libdir == NULL)
968 libdir = I18N_DATADIR;
969 #endif
970 locale = setlocale(LC_CTYPE, NULL);
971 if (locale == NULL) {
972 fprintf(stderr,
973 "fig2dev: LANG not defined; assuming C locale\n");
974 locale = "C";
975 }
976 if (strlen(libdir) + strlen(locale) + 5 > sizeof localefile_buf)
977 localefile = malloc(strlen(libdir) + strlen(locale) + 5);
978 if (localefile != NULL) {
979 sprintf(localefile, "%s/%s.ps", libdir, locale);
980 /* get filename like
981 ``/usr/local/lib/fig2dev/japanese.ps'' */
982 fp = fopen(localefile, "rb");
983 if (fp == NULL) {
984 fprintf(stderr, "fig2dev: can not open file: %s\n",
985 localefile);
986 } else {
987 enable_composite_font =
988 append_find_composite(tfp, fp);
989
990 if (ferror(tfp)) {
991 fputs("Error writing output file.\n",
992 stderr);
993 exit(EXIT_FAILURE);
994 }
995 if (ferror(fp)) {
996 fprintf(stderr,
997 "Error reading file %s.\n"
998 "The output might be broken.\n",
999 localefile);
1000 }
1001 fclose(fp);
1002 }
1003 }
1004 if (localefile != localefile_buf)
1005 free(localefile);
1006 }
1007 #endif /* I18N */
1008
1009 fprintf(tfp, "%s\n", END_PROLOG);
1010
1011 fputs("/pageheader {\n", tfp);
1012
1013 /* must specify translation/rotation
1014 before definition of fill patterns */
1015 fputs("sa\n", tfp);
1016
1017 /* now make the clipping path for the BoundingBox */
1018 fprintf(tfp, "n %d %d m %d %d l %d %d l %d %d l cp clip\n",
1019 cliplx,clipuy, cliplx,cliply, clipux,cliply, clipux,clipuy);
1020 if (!multi_page) {
1021 fprintf(tfp, "%.1f %.1f tr\n", origx, origy);
1022 if (epsflag)
1023 /* increasing y goes down */
1024 fprintf(tfp, "1 -1 sc\n");
1025 }
1026
1027 fputs("$F2psBegin\n", tfp);
1028
1029 fputs("10 setmiterlimit\n", tfp); /* make like X server (11 degrees) */
1030 /* set initial join style to miter and cap to butt */
1031 fputs("0 slj 0 slc\n", tfp);
1032 if( !multi_page)
1033 fprintf(tfp, " %.5f %.5f sc\n", scalex, scaley );
1034 fputs("} bind def\n", tfp);
1035
1036
1037 fputs("/pagefooter {\n", tfp);
1038 fputs("$F2psEnd\n", tfp);
1039 fputs("restore\n", tfp);
1040 fputs("} bind def\n", tfp);
1041
1042
1043 if (multi_page) {
1044 /* reset the matrix for multipage mode */
1045 fputs("initmatrix\n", tfp);
1046 } else {
1047 fputs("%%EndProlog\n", tfp);
1048 if (!epsflag) {
1049 fputs("%%Page: 1 1\n", tfp);
1050 fputs("%%BeginPageSetup\n", tfp);
1051 fputs("pageheader\n", tfp);
1052 /* increasing y goes down */
1053 fputs("1 -1 scale\n", tfp);
1054 fputs("%%EndPageSetup\n", tfp);
1055 } else {
1056 fputs("pageheader\n", tfp);
1057 }
1058 }
1059
1060 fputs("%\n", tfp);
1061 fputs("% Fig objects follow\n", tfp);
1062 fputs("%\n", tfp);
1063 }
1064
1065 /* Draw a grid on the figure */
1066
1067 void
genps_grid(float major,float minor)1068 genps_grid(float major, float minor)
1069 {
1070 float lx, ly, ux, uy;
1071 float x, y;
1072 double thick, thin;
1073 int itick, ntick;
1074 float m;
1075
1076 /* see if grid specified */
1077 if (minor == 0.0 && major == 0.0)
1078 return;
1079
1080 /* In case of multi postscript gridlines should be the
1081 figure with maximum depth */
1082 do_split(MAXDEPTH+2);
1083
1084 m = minor;
1085 if (minor == 0.0)
1086 m = major;
1087
1088 /* start here */
1089 if (epsflag) {
1090 /* for eps, only do bounding area of figure */
1091 lx = floor((fllx / scalex) / m) * m;
1092 ly = floor((flly / scaley) / m) * m;
1093 ux = furx / scalex;
1094 uy = fury / scaley;
1095 } else {
1096 /* for pdf and PostScript, grid the whole page */
1097 lx = 0.0;
1098 ly = 0.0;
1099 ux = pagewidth / scalex;
1100 uy = pageheight / scaley;
1101 }
1102 thin = THICK_SCALE;
1103 thick = THICK_SCALE * 2.5;
1104
1105 fputs("% Grid\n", tfp);
1106 fputs("0.5 setgray\n", tfp);
1107 /* adjust scale for difference in xfig/actual scale in metric mode */
1108 if (metric)
1109 fprintf(tfp,"gs 450 472 div dup scale\n");
1110 /* first the vertical lines */
1111 fputs("% Vertical\n", tfp);
1112 for (x = lx; x <= ux; x += m) {
1113 if (major > 0.0) {
1114 itick = (int)(x/major)*major;
1115 /* if on a major tick, or if next minor tick is beyond
1116 major tick, make a major tick */
1117 if (itick == x)
1118 set_linewidth(thick);
1119 else {
1120 /* not exactly on a major tick, see if next
1121 minor would be beyond a major */
1122 ntick = (int)((x+minor)/major)*major;
1123 if (ntick < x+minor) {
1124 /* yes, draw the major */
1125 set_linewidth(thick);
1126 draw_gridline((float)ntick, ly,
1127 (float)ntick, uy);
1128 }
1129 /* reset to draw the thin grid line */
1130 set_linewidth(thin);
1131 }
1132 } else {
1133 set_linewidth(thin);
1134 }
1135 draw_gridline(x, ly, x, uy);
1136 }
1137 /* now the horizontal */
1138 fputs("% Horizontal\n", tfp);
1139 for (y = ly; y <= uy; y += m) {
1140 if (major > 0.0) {
1141 itick = (int)(y/major)*major;
1142 /* if on a major tick, or if next minor tick is beyond
1143 major tick, make a major tick */
1144 if (itick == y)
1145 set_linewidth(thick);
1146 else {
1147 /* not exactly on a major tick, see if next
1148 minor would be beyond a major */
1149 ntick = (int)((y+minor)/major)*major;
1150 if (ntick < y+minor) {
1151 /* yes, draw the major */
1152 set_linewidth(thick);
1153 draw_gridline(lx, (float)ntick, ux,
1154 (float)ntick);
1155 }
1156 /* reset to draw the thin grid line */
1157 set_linewidth(thin);
1158 }
1159 } else {
1160 set_linewidth(thin);
1161 }
1162 draw_gridline(lx, y, ux, y);
1163 }
1164 /* restore original scale */
1165 if (metric)
1166 fprintf(tfp,"gr\n");
1167 }
1168
1169 static void
draw_gridline(float x1,float y1,float x2,float y2)1170 draw_gridline(float x1, float y1, float x2, float y2)
1171 {
1172 fprintf(tfp, "n %.1f %.1f m %.1f %.1f l s\n", x1, y1, x2, y2);
1173 }
1174
1175
1176 int
genps_end(void)1177 genps_end(void)
1178 {
1179 double dx, dy, mul;
1180 int i, page;
1181 const int h = pageheight, w = pagewidth;
1182 int epslen, tiflen;
1183 struct stat fstat;
1184
1185 /* for multipage, translate and output objects for each page */
1186 if (multi_page) {
1187 fputs("%%EndProlog\n", tfp);
1188 page = 1;
1189 if (overlap)
1190 mul = 0.9;
1191 else
1192 mul = 1.0;
1193
1194 for (dy=0; (dy < (fury-h*0.1)) || (page == 1); dy += h*mul) {
1195 for (dx=0; (dx < (furx-w*0.1)) || (page == 1);
1196 dx += w*mul) {
1197 fprintf(tfp, "%%%%Page: %d %d\n", page, page);
1198
1199 fputs("pageheader\n", tfp);
1200 /* do page rotation here */
1201 fputs("%%BeginPageSetup\n", tfp);
1202 /* increasing y goes down */
1203 fputs(" 1 -1 sc\n", tfp);
1204 fputs("%%EndPageSetup\n", tfp);
1205
1206 fputs("gs\n", tfp);
1207 fprintf(tfp, "%.1f %.1f tr\n", -dx,-(dy+h*mul));
1208 fprintf(tfp, " %.3f %.3f sc\n", scalex, scaley);
1209 for (i=0; i<no_obj; ++i) {
1210 fprintf(tfp, "o%d ", i);
1211 if (!(i%20))
1212 fputc('\n', tfp);
1213 }
1214 fputs("gr\n", tfp);
1215 fputs("pagefooter\n", tfp);
1216 fputs("showpage\n", tfp);
1217 ++page;
1218 }
1219 }
1220 }
1221 /* Close the (last) figure */
1222 do_split(-10);
1223
1224 /* add showpage if requested */
1225 if (!multi_page) {
1226 fputs("pagefooter\n", tfp);
1227 fputs("showpage\n", tfp);
1228 }
1229
1230 /* does the user want an ASCII or TIFF preview? */
1231 if (tiffpreview || asciipreview) {
1232 /* close temp eps file */
1233 fclose(tfp);
1234 /* revert original file back to tfp */
1235 tfp = saveofile;
1236
1237 /* make name for temp output file */
1238 if ((saveofile = xtmpfile(&tmpprev, sizeof tmpprev_buf)) ==
1239 NULL) {
1240 put_msg("Can not create temporary file %s.", tmpprev);
1241 put_msg("No preview will be produced.");
1242 if (tmpprev != tmpprev_buf)
1243 free(tmpprev);
1244 /* Output the eps stored in tmpeps */
1245 if (append(tmpeps, tfp) == -1) {
1246 put_msg("Cannot open temp file %s.", tmpeps);
1247 remove(tmpeps);
1248 /* unnecessary:
1249 if (tmpeps != tmpeps_buf) free(tmpeps); */
1250 exit(EXIT_FAILURE);
1251 }
1252 remove(tmpeps);
1253 if (tmpeps != tmpeps_buf)
1254 free(tmpeps);
1255 asciipreview = tiffpreview = false;
1256 } else {
1257 #ifdef GSEXE
1258 /* make the ghostscript command to generate the ASCII
1259 or TIFF file from the temp eps file */
1260 sprintf(gscom, "%s -q -dSAFER -sDEVICE=%s -r72 -g%dx%d "
1261 "-o \'%s\' %s",
1262 GSEXE, asciipreview ? "bit" :
1263 (tiffcolor ? "tiff24nc" : "tifflzw"),
1264 width, height, tmpprev, tmpeps);
1265 if (system(gscom) != 0) {
1266 fprintf(stderr,
1267 "Error calling ghostscript: %s\n",
1268 gscom);
1269 #else
1270 fputs("Ghostscript not available. ", stderr);
1271 #endif
1272 fprintf(stderr,"No preview will be produced\n");
1273 remove(tmpprev);
1274 if (tmpprev != tmpprev_buf)
1275 free(tmpprev);
1276 /* append the eps */
1277 if (append(tmpeps, tfp) == -1) {
1278 put_msg("Cannot open temp file %s.",
1279 tmpeps);
1280 remove(tmpeps);
1281 exit(EXIT_FAILURE);
1282 }
1283 remove(tmpeps);
1284 if (tmpeps != tmpeps_buf)
1285 free(tmpeps);
1286 /* and cancel the preview */
1287 asciipreview = tiffpreview = false;
1288 #ifdef GSEXE
1289 }
1290 #endif
1291 fclose(saveofile);
1292 }
1293 if (asciipreview) {
1294 --width;
1295 --height;
1296 /* now attach the preview after the prolog
1297 then attach the rest of the eps */
1298 fprintf(tfp, "%%%%BeginPreview: %d %d %d %d\n",
1299 width, height, 1, height);
1300 appendhex(tmpprev, tfp, width, height);
1301 remove(tmpprev);
1302 fputs("%%EndPreview\n", tfp);
1303 if (append(tmpeps, tfp) == -1) {
1304 put_msg("Cannot open temp file %s.", tmpeps);
1305 remove(tmpeps);
1306 exit(EXIT_FAILURE);
1307 }
1308 remove(tmpeps);
1309
1310 } else if (tiffpreview) {
1311 /* now make the binary header in the final output file
1312 and append the eps and tiff files */
1313
1314 stat(tmpeps, &fstat);
1315 epslen = fstat.st_size; /* size of eps file */
1316
1317 stat(tmpprev, &fstat);
1318 tiflen = fstat.st_size; /* size of tif file */
1319
1320 /* write header ident C5D0D3C6 */
1321 putc(0xC5, tfp);
1322 putc(0xD0, tfp);
1323 putc(0xD3, tfp);
1324 putc(0xC6, tfp);
1325 /* put byte offset of the EPS part
1326 (always 30 - immediately after the header) */
1327 putword(30, tfp);
1328 /* now size of eps part */
1329 putword(epslen, tfp);
1330 /* no Metafile */
1331 putword(0, tfp);
1332 putword(0, tfp);
1333 /* byte offset of TIFF part */
1334 putword(epslen+30, tfp);
1335 /* and length of TIFF part */
1336 putword(tiflen, tfp);
1337 /* finally, FFFF (no checksum) */
1338 putc(0xFF, tfp);
1339 putc(0xFF, tfp);
1340 /* now copy eps out */
1341 if (append(tmpeps, tfp) == -1) {
1342 put_msg("Cannot open temp file %s.", tmpeps);
1343 remove(tmpprev);
1344 remove(tmpeps);
1345 exit(EXIT_FAILURE);
1346 }
1347 remove(tmpeps);
1348 /* and finally, the tiff file */
1349 if (append(tmpprev, tfp) == -1) {
1350 put_msg("Cannot open temp file %s.", tmpprev);
1351 remove(tmpprev);
1352 remove(tmpeps);
1353 exit(EXIT_FAILURE);
1354 }
1355 remove(tmpprev);
1356 putc('\n', tfp);
1357
1358 }
1359 if (tmpeps != tmpeps_buf)
1360 free(tmpeps);
1361 if (tmpprev != tmpprev_buf)
1362 free(tmpprev);
1363 }
1364 /* put any cleanup between %%Trailer and %EOF */
1365 fputs("%%Trailer\n", tfp);
1366 if (pats_used)
1367 fputs("end\n", tfp); /* close off MyAppDict */
1368 /* final DSC comment for eps output (EOF = end of document) */
1369 fputs("%EOF\n", tfp);
1370
1371 /* all ok */
1372 return 0;
1373 }
1374
1375 /* write a 32-bit value LSB first to file */
1376
1377 static void
putword(int word,FILE * file)1378 putword(int word, FILE *file)
1379 {
1380 register int i;
1381
1382 for (i=0; i<4; i++) {
1383 putc((unsigned char) word & 0xff, file);
1384 word >>= 8;
1385 }
1386 }
1387
1388 /*
1389 * append file named in "infilename" to already open FILE "outfile"
1390 * Return 0 on sucess, -1 if "infilename" cannot be opened.
1391 */
1392
1393 static int
append(const char * restrict infilename,FILE * outfile)1394 append(const char *restrict infilename, FILE *outfile)
1395 {
1396 FILE *infile;
1397 char buf[BUFSIZ];
1398 size_t buf_len = sizeof buf;
1399 size_t chars;
1400
1401 if ((infile = fopen(infilename, "rb")) == 0)
1402 return -1;
1403
1404 while ((chars = fread(buf, (size_t)1, buf_len, infile)) == buf_len &&
1405 buf_len == fwrite(buf, (size_t)1, buf_len, outfile))
1406 ;
1407 if (!ferror(outfile) && chars > 0)
1408 fwrite(buf, (size_t)1, chars, outfile);
1409
1410 fclose(infile);
1411 return 0;
1412 }
1413
1414 #ifdef I18N
1415 /*
1416 * Append open file in to open file out while searching for the string
1417 * "CompositeRoman". Return true if found, false otherwise.
1418 */
1419 static bool
append_find_composite(FILE * restrict out,FILE * restrict in)1420 append_find_composite(FILE *restrict out, FILE *restrict in)
1421 {
1422 /*
1423 * Initially, the needle was passed as a function parameter. However,
1424 * Visual Studio cannot create an array of a size depending on a
1425 * function parameter (str[], below). Therefore, use the fixed needle
1426 * "CompositeRoman". Moreover, Visual Studio does not accept a const
1427 * qualified parameter as array size, but "sizeof ...".
1428 */
1429 bool found = false;
1430 const char needle[] = "CompositeRoman";
1431 char str[BUFSIZ + sizeof needle];
1432 const size_t needle_len = sizeof needle - 1;
1433 const size_t str_len = (size_t)BUFSIZ;
1434 size_t chars;
1435
1436 /* The needle could be split up between two consecutive buffers.
1437 Keep some margin and initialize it with spaces. */
1438 for (chars = 0; chars < needle_len; ++chars)
1439 str[chars] = ' ';
1440 /* 0-terminate str, otherwise strstr() scans into unknown territory. */
1441 str[BUFSIZ + needle_len] = '\0';
1442
1443 while ((chars = fread(str + needle_len, (size_t)1, str_len, in)) ==
1444 str_len) {
1445 if (!found && strstr(str, needle))
1446 found = true;
1447 memcpy(str, str + str_len, needle_len);
1448 if (fwrite(str + needle_len, (size_t)1, str_len, out) !=
1449 str_len)
1450 break;
1451 }
1452 /* Copy the last, incomplete read. */
1453 if (!ferror(out) && chars > 0) {
1454 if (!found) {
1455 str[needle_len + chars] = '\0';
1456 if (strstr(str, needle))
1457 found = true;
1458 }
1459 fwrite(str + needle_len, (size_t)1, chars, out);
1460 }
1461 return found;
1462 }
1463 #endif /* I18N */
1464
1465
1466 /* read file named in "infilename", converting the binary to hex and
1467 append to already open FILE "outfile".
1468 width is the number of hex values per line that should be written
1469 and height is the number of lines total. */
1470
1471 static void
appendhex(char * infilename,FILE * outfile,int width,int height)1472 appendhex(char *infilename, FILE *outfile, int width, int height)
1473 {
1474 FILE *infile;
1475 unsigned char byte;
1476 int len, i, j;
1477
1478 if ((infile = fopen(infilename, "r")) == 0) {
1479 fprintf(stderr, "Can't open temp file %s\n", infilename);
1480 exit(1);
1481 }
1482 len = (width+7)/8;
1483 for (j=0; j<height; ++j) {
1484 fputs("% ", outfile);
1485 for (i=0; i<len; ++i) {
1486 if (fread(&byte, 1, 1, infile) == 0)
1487 break;
1488 fprintf(outfile, "%02X", byte);
1489 }
1490 fputc('\n', outfile);
1491 }
1492 fclose(infile);
1493 }
1494
1495
1496 static void
set_style(int s,double v)1497 set_style(int s, double v)
1498 {
1499 v /= 80.0 / ppi;
1500 if (s == DASH_LINE) {
1501 if (v > 0.0) fprintf(tfp, " [%d] 0 sd\n", round(v));
1502 } else if (s == DOTTED_LINE) {
1503 if (v > 0.0) fprintf(tfp, " [%d %d] %d sd\n",
1504 round(ppi/80.0), round(v), round(v));
1505 } else if (s == DASH_DOT_LINE) {
1506 if (v > 0.0) fprintf(tfp, " [%d %d %d %d] 0 sd\n",
1507 round(v), round(v*0.5),
1508 round(ppi/80.0), round(v*0.5));
1509 } else if (s == DASH_2_DOTS_LINE) {
1510 if (v > 0.0) fprintf(tfp, " [%d %d %d %d %d %d] 0 sd\n",
1511 round(v), round(v*0.45),
1512 round(ppi/80.0), round(v*0.333),
1513 round(ppi/80.0), round(v*0.45));
1514 } else if (s == DASH_3_DOTS_LINE) {
1515 if (v > 0.0) fprintf(tfp,
1516 " [%d %d %d %d %d %d %d %d ] 0 sd\n",
1517 round(v), round(v*0.4),
1518 round(ppi/80.0), round(v*0.3),
1519 round(ppi/80.0), round(v*0.3),
1520 round(ppi/80.0), round(v*0.4));
1521 }
1522 }
1523
1524 static void
reset_style(int s,double v)1525 reset_style(int s, double v)
1526 {
1527 if (v > 0.0 && s >= DASH_LINE && s <= DASH_3_DOTS_LINE)
1528 fputs(" [] 0 sd\n", tfp);
1529 }
1530
1531 static void
set_linejoin(int j)1532 set_linejoin(int j)
1533 {
1534 if (j != cur_joinstyle) {
1535 cur_joinstyle = j;
1536 fprintf(tfp, "%d slj\n", cur_joinstyle);
1537 }
1538 }
1539
1540 static void
set_linecap(int j)1541 set_linecap(int j)
1542 {
1543 if (j != cur_capstyle) {
1544 cur_capstyle = j;
1545 fprintf(tfp, "%d slc\n", cur_capstyle);
1546 }
1547 }
1548
1549 static void
set_linewidth(double w)1550 set_linewidth(double w)
1551 {
1552 if (w != cur_thickness) {
1553 cur_thickness = w;
1554 fprintf(tfp, "%.3f slw\n", /* make lines a little thinner */
1555 cur_thickness <= THICK_SCALE ?
1556 0.5* cur_thickness :
1557 cur_thickness - THICK_SCALE);
1558 }
1559 }
1560
1561 void
genps_line(F_line * l)1562 genps_line(F_line *l)
1563 {
1564 F_point *p, *q;
1565 int radius;
1566 int i;
1567 int xmin,xmax,ymin,ymax;
1568 int pic_w, pic_h, img_w, img_h;
1569 float hf_wid;
1570
1571 do_split(l->depth);
1572
1573 if (multi_page)
1574 fprintf(tfp, "/o%d {", no_obj++);
1575
1576 /* print any comments prefixed with "%" */
1577 print_comments("% ",l->comments, "");
1578
1579 fputs("% Polyline\n", tfp);
1580 if (l->type != T_PIC_BOX) { /* pic object has no line thickness */
1581 set_linejoin(l->join_style);
1582 set_linecap(l->cap_style);
1583 set_linewidth((double)l->thickness);
1584 }
1585 p = l->points;
1586 q = p->next;
1587 if (q == NULL) { /* A single point line */
1588 if (l->cap_style > 0)
1589 hf_wid = 1.0;
1590 else if (l->thickness <= THICK_SCALE)
1591 hf_wid = l->thickness/4.0;
1592 else
1593 hf_wid = (l->thickness-THICK_SCALE)/2.0;
1594 fprintf(tfp, "n %d %d m %d %d l gs col%d s gr\n",
1595 round(p->x-hf_wid), p->y, round(p->x+hf_wid),
1596 p->y, l->pen_color);
1597 if (multi_page)
1598 fputs("} bind def\n", tfp);
1599 return;
1600 }
1601 if (l->type != T_PIC_BOX) {
1602 set_style(l->style, l->style_val);
1603 }
1604
1605 xmin = xmax = p->x;
1606 ymin = ymax = p->y;
1607 while (p->next != NULL) { /* find lower left and upper right corners */
1608 p=p->next;
1609 if (xmin > p->x)
1610 xmin = p->x;
1611 else if (xmax < p->x)
1612 xmax = p->x;
1613 if (ymin > p->y)
1614 ymin = p->y;
1615 else if (ymax < p->y)
1616 ymax = p->y;
1617 }
1618
1619 if (l->type == T_ARC_BOX) {
1620 /* ARC BOX */
1621 radius = l->radius; /* radius of the corner */
1622 /* limit the radius to the smaller of the two sides or
1623 postscript crashes; from T.Sato */
1624 if ((xmax - xmin) / 2 < radius)
1625 radius = (xmax - xmin) / 2;
1626 if ((ymax - ymin) / 2 < radius)
1627 radius = (ymax - ymin) / 2;
1628 fprintf(tfp, "n %d %d m",xmin+radius, ymin);
1629 fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat\n",
1630 xmin, ymin, xmin, ymax-radius, radius);
1631 /* arc through bl to br */
1632 fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat\n",
1633 xmin, ymax, xmax-radius, ymax, radius);
1634 /* arc through br to tr */
1635 fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat\n",
1636 xmax, ymax, xmax, ymin+radius, radius);
1637 /* arc through tr to tl */
1638 fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat\n",
1639 xmax, ymin, xmin+radius, ymin, radius);
1640 } else if (l->type == T_PIC_BOX) { /* imported picture */
1641 /* PICTURE OBJECT */
1642 int dx, dy, rotation;
1643 int pllx, plly, purx, pury;
1644 int i, j;
1645 char buf[12];
1646 FILE *picf;
1647 struct xfig_stream pic_stream;
1648
1649 dx = l->points->next->next->x - l->points->x;
1650 dy = l->points->next->next->y - l->points->y;
1651 rotation = 0;
1652 if (dx < 0 && dy < 0)
1653 rotation = 180;
1654 else if (dx < 0 && dy >= 0)
1655 rotation = 90;
1656 else if (dy < 0 && dx >= 0)
1657 rotation = 270;
1658
1659 fputs("%\n", tfp);
1660
1661 fputs("% pen to black in case this eps object doesn't set "
1662 "color first\n", tfp);
1663 if (grayonly)
1664 fputs("0 setgray\n", tfp);
1665 else
1666 fputs("0 0 0 setrgbcolor\n", tfp);
1667
1668 init_stream(&pic_stream);
1669
1670 /* open the file and read a few bytes of the header
1671 to see what it is */
1672 if ((picf = open_stream(l->pic->file, &pic_stream)) == NULL) {
1673 put_msg("No such picture file: %s", l->pic->file);
1674 free_stream(&pic_stream);
1675 return;
1676 }
1677
1678 for (i = 0; i < (int)(sizeof buf); ++i) {
1679 int c;
1680 if ((c = getc(picf)) == EOF)
1681 break;
1682 buf[i] = (char)c;
1683 }
1684
1685 /* now find which header it is */
1686 for (i = 0; i < (int)(sizeof(headers)/sizeof(headers[0])); ++i)
1687 if (!memcmp(buf, headers[i].bytes,
1688 strlen(headers[i].bytes)))
1689 break;
1690
1691 if (i == sizeof(headers) / sizeof(headers[0])) {
1692 /* not found */
1693 put_msg("%s: Unknown image format", l->pic->file);
1694 close_stream(&pic_stream);
1695 free_stream(&pic_stream);
1696 return;
1697 }
1698 /* found */
1699 /*
1700 * readfunc() expects an open file stream, positioned not at the
1701 * start of the stream. The stream remains open after returning.
1702 */
1703 if (!headers[i].readfunc(l->pic, &pic_stream, &pllx, &plly)) {
1704 put_msg("%s: Bad %s format", l->pic->file,
1705 headers[i].type);
1706 close_stream(&pic_stream);
1707 free_stream(&pic_stream);
1708 return;
1709 }
1710
1711 /* width, height of image bits (unrotated) */
1712 img_w = l->pic->bit_size.x;
1713 img_h = l->pic->bit_size.y;
1714
1715 /* calc upper-right from size and lower-left */
1716 /* pllx, plly may not be (0,0) from some image formats */
1717
1718 purx = img_w+pllx;
1719 pury = img_h+plly;
1720
1721 fputs("n gs\n", tfp);
1722
1723 /* pic_w, pic_h are the width, height of the Fig pic object,
1724 possibly rotated */
1725 if (((rotation == 90 || rotation == 270) && !l->pic->flipped) ||
1726 (rotation != 90 && rotation != 270 && l->pic->flipped)) {
1727 pic_w = pury - plly;
1728 pic_h = purx - pllx;
1729 } else {
1730 pic_w = purx - pllx;
1731 pic_h = pury - plly;
1732 }
1733
1734 /* translate the pic stuff to the right spot on the page */
1735 fprintf(tfp, "%d %d tr\n", xmin, ymin);
1736
1737 /* scale the pic stuff to fit into the bounding box */
1738 /* Note: the origin for fig is in the upper-right corner;
1739 * for postscript its in the lower right hand corner.
1740 * To fix it, we use a "negative"-y scale factor, then
1741 * translate the image up on the page
1742 */
1743 fprintf(tfp, "%f %f sc\n", fabs((double)(xmax-xmin)/pic_w),
1744 -1.0*(double)(ymax-ymin)/pic_h);
1745
1746 /* flip the pic stuff. Always translate it back so that the
1747 * lower-left corner is at the origin.
1748 * note: fig measures rotation clockwise;
1749 * postscript is counter-clockwise
1750 */
1751 switch (rotation) {
1752 case 0:
1753 if (l->pic->flipped) {
1754 fprintf(tfp, "%d 0 tr\n", pic_w);
1755 fprintf(tfp, "%d rot\n", 270);
1756 fputs("1 -1 sc\n", tfp);
1757 } else {
1758 fprintf(tfp, "0 %d tr\n", -pic_h);
1759 }
1760 break;
1761 case 90:
1762 if (l->pic->flipped) {
1763 fprintf(tfp, "%d %d tr\n", pic_w, -pic_h);
1764 fputs("-1 1 sc\n", tfp);
1765 } else {
1766 fprintf(tfp, "%d rot\n", 270);
1767 }
1768 break;
1769 case 180:
1770 if (l->pic->flipped) {
1771 fprintf(tfp, "0 %d tr\n", -pic_h);
1772 fprintf(tfp, "%d rot\n", 270);
1773 fputs("-1 1 sc\n", tfp);
1774 } else {
1775 fprintf(tfp, "%d 0 tr\n", pic_w);
1776 fprintf(tfp, "%d rot\n", 180);
1777 }
1778 break;
1779 case 270:
1780 if (l->pic->flipped) {
1781 fputs("1 -1 sc\n", tfp);
1782 } else {
1783 fprintf(tfp, "%d %d tr\n", pic_w, -pic_h);
1784 fprintf(tfp, "%d rot\n", 90);
1785 }
1786 break;
1787 }
1788
1789 /* translate the pic stuff so that the lower-left corner is at
1790 the origin */
1791 fprintf(tfp, "%d %d tr\n", -pllx, -plly);
1792 /* save vm so pic file won't change anything */
1793 fputs("sa\n", tfp);
1794
1795 /* if PIC object is EPS file, set up clipping rectangle to BB
1796 * and prepare to clean up stacks and dicts of included EPS file
1797 */
1798 if (l->pic->subtype == P_EPS) {
1799 fprintf(tfp,
1800 "n %d %d m %d %d l %d %d l %d %d l cp clip n\n",
1801 pllx,plly, purx,plly, purx,pury, pllx,pury);
1802 fputs("countdictstack\n", tfp);
1803 fputs("mark\n", tfp);
1804 /* if user wants grayscale (-N) then redefine
1805 setrgbcolor to setgray in imported figure */
1806 if (grayonly)
1807 fputs("/setrgbcolor { 0.11 mul exch 0.59 mul "
1808 "add exch 0.3 mul add setgray} def\n",
1809 tfp);
1810
1811 /* undefine showpage - and setpagedevice. Some ps-files,
1812 * e.g., produced by latex, may be included this way
1813 */
1814 fputs("/showpage {} def\n/setpagedevice {pop} def\n",
1815 tfp);
1816 }
1817
1818
1819 /* embed the image */
1820 if (l->pic->subtype == P_XBM) {
1821 unsigned char *bit;
1822 int cwid;
1823
1824 fprintf(tfp, "col%d\n ", l->pen_color);
1825 fputs("% Bitmap image follows:\n", tfp);
1826 /* scale for size in bits */
1827 fprintf(tfp, "%d %d sc\n", purx, pury);
1828 fprintf(tfp, "/pix %d string def\n", (int)((purx+7)/8));
1829 /* width, height and paint 0 bits */
1830 fprintf(tfp, "%d %d false\n", purx, pury);
1831 /* transformation matrix */
1832 fprintf(tfp, "[%d 0 0 %d 0 %d]\n", purx, -pury, pury);
1833 /* function for reading bits */
1834 fputs("{currentfile pix readhexstring pop}\n", tfp);
1835 /* use imagemask to draw in color */
1836 fputs("imagemask\n", tfp);
1837 bit = l->pic->bitmap;
1838 cwid = 0;
1839 for (i=0; i<pury; ++i) { /* for each row */
1840 /* for each byte */
1841 for (j=0; j<(int)((purx+7)/8); ++j) {
1842 fprintf(tfp,"%02x",
1843 (unsigned char) ~(*bit++));
1844 cwid+=2;
1845 if (cwid >= 80) {
1846 fputs("\n", tfp);
1847 cwid=0;
1848 }
1849 }
1850 fputs("\n", tfp);
1851 }
1852
1853 } else if (l->pic->subtype == P_GIF || l->pic->subtype == P_PNG
1854 || l->pic->subtype == P_JPEG
1855 || l->pic->subtype == P_PCX
1856 || l->pic->subtype == P_PPM
1857 || l->pic->subtype == P_XPM) {
1858 if (l->pic->subtype == P_GIF)
1859 fputs("% GIF", tfp);
1860 else if (l->pic->subtype == P_PNG)
1861 fputs("% PNG", tfp);
1862 else if (l->pic->subtype == P_JPEG)
1863 fputs("% JPEG", tfp);
1864 else if (l->pic->subtype == P_PCX)
1865 fputs("% PCX", tfp);
1866 else if (l->pic->subtype == P_XPM)
1867 fputs("% XPM", tfp);
1868 else
1869 fputs("% PPM", tfp);
1870
1871 fputs(" image follows:\n", tfp);
1872 /* scale for size in bits */
1873 fprintf(tfp, "%d %d sc\n", purx, pury);
1874 if (l->pic->subtype == P_JPEG) {
1875 /* read and format the jpeg file for PS */
1876 rewind_stream(&pic_stream);
1877 JPEGtoPS(pic_stream.fp, tfp);
1878 } else {
1879 if (l->pic->numcols > 256)
1880 write_rgbimage(tfp, l->pic);
1881 else
1882 indexed_image(tfp, l->pic);
1883 }
1884
1885 /* EPS file */
1886 } else if (l->pic->subtype == P_EPS &&
1887 strcmp(headers[i].type, "PDF")) {
1888 fputs("% EPS file follows:\n", tfp);
1889 if (!rewind_stream(&pic_stream)) {
1890 err_msg("Unable to open EPS file '%s'");
1891 fputs("gr\n", tfp);
1892 return;
1893 }
1894
1895 /* flush buffer first */
1896 fflush(tfp);
1897 if (strcmp(headers[i].type, "EPSI") == 0) {
1898 /* currently, if append_epsi() returns with
1899 an error, it did not write anything */
1900 if (append_epsi(pic_stream.fp, l->pic->file, tfp))
1901 put_msg("Could not embed EPSI file %s.",
1902 l->pic->file);
1903 } else {
1904 size_t len;
1905 char buffer[BUFSIZ];
1906
1907 while ((len = fread(buffer, 1, sizeof buffer,
1908 pic_stream.fp)))
1909 fwrite(buffer, 1, len, tfp);
1910 }
1911 } else if (!strcmp(headers[i].type, "PDF")) {
1912 fputs("% PDF file converted to EPS follows:\n", tfp);
1913 fflush(tfp);
1914 pdftops(&pic_stream, tfp);
1915 }
1916
1917 close_stream(&pic_stream);
1918 free_stream(&pic_stream);
1919
1920 /* if PIC object is EPS file, clean up stacks and dicts
1921 * before 'restore'ing vm
1922 */
1923 if (l->pic->subtype == P_EPS) {
1924 fputs("\ncleartomark\n", tfp);
1925 fputs("countdictstack exch sub { end } repeat\n", tfp);
1926 }
1927
1928 /* restore vm and gsave */
1929 fputs("rs gr\n", tfp);
1930 fputs("%\n", tfp);
1931 fprintf(tfp, "%% End Imported PIC File: %s\n", l->pic->file);
1932 if (l->pic->subtype == P_EPS)
1933 fputs("%%EndDocument\n", tfp);
1934 fputs("%\n", tfp);
1935 } else {
1936 /* POLYLINE */
1937 p = l->points;
1938 q = p->next;
1939 /* first point */
1940 fpntx1 = p->x;
1941 fpnty1 = p->y;
1942 /* second point */
1943 fpntx2 = q->x;
1944 fpnty2 = q->y;
1945 /* go through the points to get the last two */
1946 while (q->next != NULL) {
1947 p = q;
1948 q = q->next;
1949 }
1950 /* next to last point */
1951 lpntx2 = p->x;
1952 lpnty2 = p->y;
1953 /* last point */
1954 lpntx1 = q->x;
1955 lpnty1 = q->y;
1956 /* set clipping for any arrowheads */
1957 if (NEEDS_CLIPPING(l)) {
1958 fprintf(tfp, "gs ");
1959 clip_arrows(l, OBJ_POLYLINE);
1960 }
1961
1962 /* now output the points */
1963 p = l->points;
1964 q = p->next;
1965 fprintf(tfp, "n %d %d m", p->x, p->y);
1966 i=1;
1967 while (q->next != NULL) {
1968 p = q;
1969 q = q->next;
1970 fprintf(tfp, " %d %d l", p->x, p->y);
1971 if (i%5 == 0)
1972 fputs("\n", tfp);
1973 ++i;
1974 }
1975 fputs("\n", tfp);
1976 }
1977
1978 /* now fill it, draw the line and/or draw arrow heads */
1979 if (l->type != T_PIC_BOX) { /* make sure it isn't a picture object */
1980 if (l->type == T_POLYLINE) {
1981 fprintf(tfp, " %d %d l ", q->x, q->y);
1982 if (fpntx1==lpntx1 && fpnty1==lpnty1)
1983 fputs(" cp ", tfp);
1984 /* endpoints are coincident, close path
1985 so that line join is used */
1986 } else {
1987 fputs(" cp ", tfp); /* polygon, close path */
1988 }
1989 /* fill it if there is a fill style */
1990 if (l->fill_style != UNFILLED)
1991 fill_area(l->fill_style, l->pen_color, l->fill_color);
1992 /* stroke if there is a line thickness */
1993 if (l->thickness > 0)
1994 fprintf(tfp, "gs col%d s gr ", l->pen_color);
1995
1996 /* reset clipping */
1997 if (l->type == T_POLYLINE && NEEDS_CLIPPING(l))
1998 fputs("gr\n", tfp);
1999 reset_style(l->style, l->style_val);
2000
2001 if (l->back_arrow && l->thickness > 0)
2002 draw_arrow(l->back_arrow, bpoints, nbpoints,
2003 bfillpoints, nbfillpoints,l->pen_color);
2004 if (l->for_arrow && l->thickness > 0)
2005 draw_arrow(l->for_arrow, fpoints, nfpoints, ffillpoints,
2006 nffillpoints, l->pen_color);
2007 }
2008 if (multi_page)
2009 fputs("} bind def\n", tfp);
2010 }
2011
2012 void
genps_spline(F_spline * s)2013 genps_spline(F_spline *s)
2014 {
2015 do_split(s->depth);
2016
2017 if (multi_page)
2018 fprintf(tfp, "/o%d {", no_obj++);
2019
2020 /* print any comments prefixed with "%" */
2021 print_comments("% ",s->comments, "");
2022
2023 if (closed_spline(s)) {
2024 if (s->style == DOTTED_LINE)
2025 set_linecap(1); /* round dots for dotted line */
2026 } else { /* open splines can explicitely set capstyle */
2027 set_linecap(s->cap_style);
2028 }
2029 /* set the line thickness */
2030 set_linewidth((double)s->thickness);
2031 if (int_spline(s))
2032 genps_itp_spline(s);
2033 else
2034 genps_ctl_spline(s);
2035 if (multi_page)
2036 fputs("} bind def\n", tfp);
2037 }
2038
2039 static void
genps_itp_spline(F_spline * s)2040 genps_itp_spline(F_spline *s)
2041 {
2042 F_point *p, *q;
2043 F_control *a, *b;
2044 int xmin, ymin;
2045
2046 fprintf(tfp, "%% Interp Spline\n");
2047
2048 a = s->controls;
2049 p = s->points;
2050 /* first point */
2051 fpntx1 = p->x;
2052 fpnty1 = p->y;
2053 /* second point */
2054 fpntx2 = round(a->rx);
2055 fpnty2 = round(a->ry);
2056 /* go through the points to find the last two */
2057 for (q = p->next; q != NULL; p = q, q = q->next) {
2058 b = a->next;
2059 a = b;
2060 }
2061 /* next to last point */
2062 lpntx2 = round(b->lx);
2063 lpnty2 = round(b->ly);
2064 /* last point */
2065 lpntx1 = p->x;
2066 lpnty1 = p->y;
2067 /* set clipping for any arrowheads */
2068 if (NEEDS_CLIPPING(s)) {
2069 fprintf(tfp, "gs ");
2070 clip_arrows((F_line *)s, OBJ_SPLINE);
2071 }
2072
2073 a = s->controls;
2074 p = s->points;
2075 set_style(s->style, s->style_val);
2076 fprintf(tfp, "n %d %d m\n", p->x, p->y);
2077 xmin = 999999;
2078 ymin = 999999;
2079 for (q = p->next; q != NULL; p = q, q = q->next) {
2080 xmin = min(xmin, p->x);
2081 ymin = min(ymin, p->y);
2082 b = a->next;
2083 fprintf(tfp, "\t%.1f %.1f %.1f %.1f %d %d curveto\n",
2084 a->rx, a->ry, b->lx, b->ly, q->x, q->y);
2085 a = b;
2086 }
2087 if (closed_spline(s)) fprintf(tfp, " cp ");
2088 if (s->fill_style != UNFILLED)
2089 fill_area(s->fill_style, s->pen_color, s->fill_color);
2090 if (s->thickness > 0) {
2091 fprintf(tfp, " gs col%d s gr\n", s->pen_color);
2092 /* reset clipping */
2093 if (NEEDS_CLIPPING(s))
2094 fprintf(tfp," gr\n");
2095 }
2096 reset_style(s->style, s->style_val);
2097
2098 /* draw arrowheads after spline for open arrow */
2099 if (s->back_arrow && s->thickness > 0)
2100 draw_arrow(s->back_arrow, bpoints, nbpoints,
2101 bfillpoints, nbfillpoints, s->pen_color);
2102
2103 if (s->for_arrow && s->thickness > 0)
2104 draw_arrow(s->for_arrow, fpoints, nfpoints,
2105 ffillpoints, nffillpoints, s->pen_color);
2106 }
2107
2108 static void
genps_ctl_spline(F_spline * s)2109 genps_ctl_spline(F_spline *s)
2110 {
2111 double a, b, c, d, x1, y1, x2, y2, x3, y3;
2112 F_point *p, *q;
2113 int xmin, ymin;
2114
2115 if (closed_spline(s))
2116 fprintf(tfp, "%% Closed spline\n");
2117 else
2118 fprintf(tfp, "%% Open spline\n");
2119
2120 p = s->points;
2121 x1 = p->x;
2122 y1 = p->y;
2123 p = p->next;
2124 c = p->x;
2125 d = p->y;
2126 x3 = a = (x1 + c) / 2;
2127 y3 = b = (y1 + d) / 2;
2128
2129 /* first point */
2130 fpntx1 = round(x1);
2131 fpnty1 = round(y1);
2132 /* second point */
2133 fpntx2 = round(x3);
2134 fpnty2 = round(y3);
2135
2136 /* in case there are only two points in this spline */
2137 x2=x1; y2=y1;
2138 /* go through the points to find the last two */
2139 for (q = p->next; q != NULL; p = q, q = q->next) {
2140 x1 = x3;
2141 y1 = y3;
2142 x2 = c;
2143 y2 = d;
2144 c = q->x;
2145 d = q->y;
2146 x3 = (x2 + c) / 2;
2147 y3 = (y2 + d) / 2;
2148 }
2149 /* next to last point */
2150 lpntx2 = round(x2);
2151 lpnty2 = round(y2);
2152 /* last point */
2153 lpntx1 = round(c);
2154 lpnty1 = round(d);
2155 /* set clipping for any arrowheads */
2156 if (NEEDS_CLIPPING(s)) {
2157 fprintf(tfp, "gs ");
2158 clip_arrows((F_line *)s, OBJ_SPLINE);
2159 }
2160
2161 /* now output the points */
2162 set_style(s->style, s->style_val);
2163 xmin = 999999;
2164 ymin = 999999;
2165
2166 p = s->points;
2167 x1 = p->x;
2168 y1 = p->y;
2169 p = p->next;
2170 c = p->x;
2171 d = p->y;
2172 x3 = a = (x1 + c) / 2;
2173 y3 = b = (y1 + d) / 2;
2174 /* in case there are only two points in this spline */
2175 x2=x1; y2=y1;
2176 if (closed_spline(s))
2177 fprintf(tfp, "n %.1f %.1f m\n", a, b);
2178 else
2179 fprintf(tfp, "n %.1f %.1f m %.1f %.1f l\n", x1, y1, x3, y3);
2180
2181 for (q = p->next; q != NULL; p = q, q = q->next) {
2182 xmin = min(xmin, p->x);
2183 ymin = min(ymin, p->y);
2184 x1 = x3;
2185 y1 = y3;
2186 x2 = c;
2187 y2 = d;
2188 c = q->x;
2189 d = q->y;
2190 x3 = (x2 + c) / 2;
2191 y3 = (y2 + d) / 2;
2192 fprintf(tfp,
2193 "\t%.1f %.1f %.1f %.1f %.1f %.1f DrawSplineSection\n",
2194 x1, y1, x2, y2, x3, y3);
2195 }
2196 /*
2197 * At this point, (x2,y2) and (c,d) are the position of the
2198 * next-to-last and last point respectively, in the point list
2199 */
2200 if (closed_spline(s)) {
2201 fprintf(tfp, "\t%.1f %.1f %.1f %.1f %.1f %.1f DrawSplineSection"
2202 " closepath ", x3, y3, c, d, a, b);
2203 } else {
2204 fprintf(tfp, "\t%.1f %.1f l ", c, d);
2205 }
2206 if (s->fill_style != UNFILLED)
2207 fill_area(s->fill_style, s->pen_color, s->fill_color);
2208 if (s->thickness > 0) {
2209 fprintf(tfp, " gs col%d s gr\n", s->pen_color);
2210 /* reset clipping */
2211 if (NEEDS_CLIPPING(s))
2212 fprintf(tfp," gr\n");
2213 }
2214 reset_style(s->style, s->style_val);
2215
2216 /* draw arrowheads after spline */
2217 if (s->back_arrow && s->thickness > 0)
2218 draw_arrow(s->back_arrow, bpoints, nbpoints,
2219 bfillpoints, nbfillpoints, s->pen_color);
2220 if (s->for_arrow && s->thickness > 0)
2221 draw_arrow(s->for_arrow, fpoints, nfpoints,
2222 ffillpoints, nffillpoints, s->pen_color);
2223 }
2224
2225 void
genps_arc(F_arc * a)2226 genps_arc(F_arc *a)
2227 {
2228 double angle1, angle2, dx, dy, radius;
2229 double cx, cy, sx, sy, ex, ey;
2230 int direction;
2231
2232 do_split(a->depth);
2233
2234 /* print any comments prefixed with "%" */
2235 print_comments("% ",a->comments, "");
2236
2237 fprintf(tfp, "%% Arc\n");
2238
2239 if (multi_page)
2240 fprintf(tfp, "/o%d {", no_obj++);
2241
2242 cx = a->center.x; cy = a->center.y;
2243 sx = a->point[0].x; sy = a->point[0].y;
2244 ex = a->point[2].x; ey = a->point[2].y;
2245
2246 direction = a->direction;
2247 set_linewidth((double)a->thickness);
2248 set_linecap(a->cap_style);
2249 dx = cx - sx;
2250 dy = cy - sy;
2251 radius = sqrt(dx*dx+dy*dy);
2252 if (cx==sx)
2253 angle1 = (sy-cy > 0? 90.0: -90.0);
2254 else
2255 angle1 = atan2(sy-cy, sx-cx) * 180.0 / M_PI;
2256 if (cx==ex)
2257 angle2 = (ey-cy > 0? 90.0: -90.0);
2258 else
2259 angle2 = atan2(ey-cy, ex-cx) * 180.0 / M_PI;
2260
2261 /* workaround for arcs with start point = end point;
2262 make angles slightly different */
2263 if (fabs(angle1 - angle2) < 0.001)
2264 angle2 = angle1 + 0.01;
2265
2266 if (a->type == T_OPEN_ARC && NEEDS_CLIPPING(a)) {
2267 /* set clipping for any arrowheads */
2268 fprintf(tfp, "gs ");
2269 if (a->for_arrow || a->back_arrow)
2270 clip_arrows((F_line *)a, OBJ_ARC);
2271 }
2272
2273 set_style(a->style, a->style_val);
2274
2275 /* draw the arc now */
2276 /* direction = 1 -> Counterclockwise */
2277 fprintf(tfp, "n %.1f %.1f %.1f %.4f %.4f %s\n",
2278 cx, cy, radius, angle1, angle2,
2279 ((direction == 1) ? "arcn" : "arc"));
2280
2281 if (a->type == T_PIE_WEDGE_ARC)
2282 fprintf(tfp,"%.1f %.1f l %.1f %.1f l ",cx,cy,sx,sy);
2283
2284 /****** The upper-left values (dx, dy) aren't really correct so *****/
2285 /****** the fill pattern alignment between a filled arc and other *****/
2286 /****** filled objects will not be correct *****/
2287 if (a->fill_style != UNFILLED)
2288 fill_area(a->fill_style, a->pen_color, a->fill_color);
2289 if (a->thickness > 0)
2290 fprintf(tfp, "gs col%d s gr\n", a->pen_color);
2291
2292 if (a->type == T_OPEN_ARC && NEEDS_CLIPPING(a)) {
2293 /* reset clipping */
2294 fprintf(tfp," gr\n");
2295 }
2296 reset_style(a->style, a->style_val);
2297
2298 /* now draw the arrowheads, if any */
2299 if (a->type == T_OPEN_ARC) {
2300 if (a->back_arrow && a->thickness > 0)
2301 draw_arrow(a->back_arrow, bpoints, nbpoints,
2302 bfillpoints, nbfillpoints,a->pen_color);
2303 if (a->for_arrow && a->thickness > 0)
2304 draw_arrow(a->for_arrow, fpoints, nfpoints,
2305 ffillpoints, nffillpoints,a->pen_color);
2306 }
2307 if (multi_page)
2308 fprintf(tfp, "} bind def\n");
2309 }
2310
2311 void
genps_ellipse(F_ellipse * e)2312 genps_ellipse(F_ellipse *e)
2313 {
2314 do_split(e->depth);
2315
2316 fprintf(tfp, "%% Ellipse\n");
2317
2318 /* print any comments prefixed with "%" */
2319 print_comments("% ",e->comments, "");
2320
2321 if (multi_page)
2322 fprintf(tfp, "/o%d {", no_obj++);
2323
2324 set_linewidth((double)e->thickness);
2325 set_style(e->style, e->style_val);
2326 if (e->style == DOTTED_LINE)
2327 set_linecap(1); /* round dots */
2328 else
2329 set_linecap(0);
2330 if (e->angle == 0) {
2331 fprintf(tfp, "n %d %d %d %d 0 360 DrawEllipse ",
2332 e->center.x, e->center.y, e->radiuses.x,
2333 e->radiuses.y);
2334 } else {
2335 fprintf(tfp, "gs\n");
2336 fprintf(tfp, "%d %d tr\n",e->center.x, e->center.y);
2337 fprintf(tfp, "%6.3f rot\n",-e->angle*180.0/M_PI);
2338 fprintf(tfp, "n 0 0 %d %d 0 360 DrawEllipse ",
2339 e->radiuses.x, e->radiuses.y);
2340 /* rotate back so any fill pattern will come out correct */
2341 fprintf(tfp, "%6.3f rot\n",e->angle*180.0/M_PI);
2342 }
2343 if (e->fill_style != UNFILLED)
2344 fill_area(e->fill_style, e->pen_color, e->fill_color);
2345 if (e->thickness > 0)
2346 fprintf(tfp, "gs col%d s gr\n", e->pen_color);
2347 if (e->angle != 0)
2348 fprintf(tfp, "gr\n");
2349 reset_style(e->style, e->style_val);
2350 if (multi_page)
2351 fprintf(tfp, "} bind def\n");
2352 }
2353
2354
2355 #define TEXT_PS "\
2356 /%s%s ff %.2f scf sf\n\
2357 "
2358 void
genps_text(F_text * t)2359 genps_text(F_text *t)
2360 {
2361 unsigned char *cp;
2362 #ifdef I18N
2363 #define LINE_LENGTH_LIMIT 200
2364 bool composite = false;
2365 bool state_gr = false;
2366 int chars = 0;
2367 int gr_chars = 0;
2368 unsigned char ch;
2369 #endif /* I18N */
2370
2371 do_split(t->depth);
2372
2373 /* ignore hidden text (new for xfig3.2.3/fig2dev3.2.3) */
2374 if (hidden_text(t))
2375 return;
2376
2377 if (multi_page)
2378 fprintf(tfp, "/o%d {", no_obj++);
2379
2380 /* print any comments prefixed with "%" */
2381 print_comments("% ",t->comments, "");
2382
2383 #ifdef I18N
2384 if (enable_composite_font && ((t->flags & PSFONT_TEXT) ?
2385 (t->font <= 0 || t->font == 2) :
2386 (t->font <= 2))) {
2387 composite = true;
2388 if (t->font <= 0)
2389 fprintf(tfp, TEXT_PS, "CompositeRoman", "",
2390 PSFONTMAG(t));
2391 else
2392 fprintf(tfp, TEXT_PS, "CompositeBold", "",PSFONTMAG(t));
2393 } else
2394 #endif /* I18N */
2395 if (PSisomap[t->font+1] == true)
2396 fprintf(tfp, TEXT_PS, PSFONT(t), "-iso", PSFONTMAG(t));
2397 else
2398 fprintf(tfp, TEXT_PS, PSFONT(t), "", PSFONTMAG(t));
2399
2400 fprintf(tfp, "%d %d m\ngs ", t->base_x, t->base_y);
2401 fprintf(tfp, "1 -1 sc ");
2402
2403 if (t->angle != 0.0)
2404 fprintf(tfp, " %.1f rot ", t->angle*180.0/M_PI);
2405 /* this loop escapes characters '(', ')', and '\' */
2406 fputc('(', tfp);
2407 #ifdef I18N
2408 for(cp = (unsigned char *)t->cstring; *cp; cp++) {
2409 if (LINE_LENGTH_LIMIT < chars) {
2410 fputs("\\\n", tfp);
2411 chars = 0;
2412 }
2413 ch = *cp;
2414 if (enable_composite_font && composite) {
2415 if (ch & 0x80) { /* GR */
2416 if (!state_gr) {
2417 fprintf(tfp, "\\377\\001");
2418 chars += 8;
2419 state_gr = true;
2420 gr_chars = 0;
2421 }
2422 gr_chars++;
2423 } else { /* GL */
2424 if (state_gr) {
2425 if (gr_chars % 2) {
2426 put_msg("warning: incomplete "
2427 "multi-byte text: %s",
2428 t->cstring);
2429 fputc('?', tfp);
2430 }
2431 fprintf(tfp, "\\377\\000");
2432 chars += 8;
2433 state_gr = false;
2434 }
2435 }
2436 }
2437 if (strchr("()\\", ch)) {
2438 fputc('\\', tfp);
2439 chars += 1;
2440 }
2441 if (ch>=0x80) {
2442 fprintf(tfp,"\\%o", ch);
2443 chars += 4;
2444 } else {
2445 fputc(ch, tfp);
2446 chars += 1;
2447 }
2448 }
2449 if (enable_composite_font && composite && state_gr) {
2450 if (gr_chars % 2) {
2451 put_msg("warning: incomplete multi-byte text: %s",
2452 t->cstring);
2453 fputc('?', tfp);
2454 }
2455 }
2456 #else
2457 for(cp = (unsigned char *)t->cstring; *cp; cp++) {
2458 if (strchr("()\\", *cp))
2459 fputc('\\', tfp);
2460 if (*cp>=0x80)
2461 fprintf(tfp,"\\%o", *cp);
2462 else
2463 fputc(*cp, tfp);
2464 }
2465 #endif /* I18N */
2466 fputc(')', tfp);
2467
2468 if ((t->type == T_CENTER_JUSTIFIED) || (t->type == T_RIGHT_JUSTIFIED)){
2469
2470 fprintf(tfp, " dup sw pop ");
2471 if (t->type == T_CENTER_JUSTIFIED) fprintf(tfp, "2 div ");
2472 fprintf(tfp, "neg 0 rm ");
2473 }
2474
2475 else if ((t->type != T_LEFT_JUSTIFIED) && (t->type != DEFAULT))
2476 fprintf(stderr, "Text incorrectly positioned\n");
2477
2478 fprintf(tfp, " col%d sh gr\n", t->color);
2479
2480 if (multi_page)
2481 fprintf(tfp, "} bind def\n");
2482 }
2483
2484 /* draw arrow from the points array */
2485
2486 static void
draw_arrow(F_arrow * arrow,F_pos * points,int npoints,F_pos * fillpoints,int nfillpoints,int col)2487 draw_arrow(F_arrow *arrow, F_pos *points, int npoints,
2488 F_pos *fillpoints, int nfillpoints, int col)
2489 {
2490 int i, type;
2491
2492 fprintf(tfp,"%% arrowhead\n");
2493 set_linecap(0); /* butt line cap for arrowheads */
2494 set_linejoin(0); /* miter join for sharp points */
2495 set_linewidth(arrow->thickness);
2496 fprintf(tfp, "n ");
2497 for (i=0; i<npoints; i++) {
2498 fprintf(tfp, "%d %d ",points[i].x,points[i].y);
2499 if (i==0)
2500 fprintf(tfp, "m ");
2501 else
2502 fprintf(tfp, "l ");
2503 if ((i+1)%5 == 0)
2504 fprintf(tfp,"\n");
2505 }
2506
2507 type = arrow->type;
2508 if (type != 0 && type != 6 && type < 13) /* old heads, close the path */
2509 fprintf(tfp, " cp ");
2510 if (type == 0) {
2511 /* stroke */
2512 fprintf(tfp, " col%d s\n",col);
2513 } else {
2514 if (arrow->style == 0 && nfillpoints == 0) {
2515 /* hollow, fill with white */
2516 fill_area(NUMSHADES-1, WHITE_COLOR, WHITE_COLOR);
2517 /* stroke */
2518 fprintf(tfp, " col%d s\n",col);
2519 } else {
2520 if (nfillpoints == 0) {
2521 if (type < 13) {
2522 if (arrow->style == 0)
2523 /* fill with white */
2524 fill_area(NUMSHADES-1,
2525 WHITE_COLOR,
2526 WHITE_COLOR);
2527 else
2528 /* fill with color */
2529 fill_area(NUMSHADES-1, col,col);
2530 }
2531 /* stroke */
2532 fprintf(tfp, " col%d s\n",col);
2533 } else {
2534 /* special fill, first fill whole head
2535 with white */
2536 fill_area(NUMSHADES-1, WHITE_COLOR,WHITE_COLOR);
2537 /* stroke */
2538 fprintf(tfp, " col%d s\n",col);
2539 /* now describe the special fill area */
2540 fprintf(tfp, "n ");
2541 for (i=0; i<nfillpoints; i++) {
2542 fprintf(tfp, "%d %d ", fillpoints[i].x,
2543 fillpoints[i].y);
2544 if (i==0)
2545 fprintf(tfp, "m ");
2546 else
2547 fprintf(tfp, "l ");
2548 if ((i+1)%5 == 0)
2549 fprintf(tfp,"\n");
2550 }
2551 /* then fill special fill area */
2552 fill_area(NUMSHADES-1, col, col);
2553 }
2554 }
2555 }
2556 }
2557
2558 /****************************************************************
2559
2560 clip_arrows - calculate a clipping region which is the current
2561 clipping area minus the polygons at the arrowheads.
2562
2563 This will prevent the object (line, spline etc.) from protruding
2564 on either side of the arrowhead Also calculate the arrowheads
2565 themselves and put the polygons in fpoints[nfpoints] for forward
2566 arrow and bpoints[nbpoints] for backward arrow.
2567 The calling routine should first do a "gs" (graphics state save)
2568 so that it can restore the original clip area later.
2569
2570 ****************************************************************/
2571
2572 static void
clip_arrows(F_line * obj,int objtype)2573 clip_arrows(F_line *obj, int objtype)
2574 {
2575 int i;
2576
2577 /* get current clip area */
2578 fprintf(tfp," clippath\n");
2579 /* get points for any forward arrowhead */
2580 if (obj->for_arrow) {
2581 if (objtype == OBJ_ARC) {
2582 F_arc *a = (F_arc *) obj;
2583 /* last point */
2584 lpntx1 = a->point[2].x;
2585 lpnty1 = a->point[2].y;
2586 compute_arcarrow_angle(a->center.x, a->center.y,
2587 (double)lpntx1, (double)lpnty1,
2588 a->direction, a->for_arrow,
2589 &lpntx2, &lpnty2);
2590 }
2591 calc_arrow(lpntx2, lpnty2, lpntx1, lpnty1, obj->thickness,
2592 obj->for_arrow, fpoints, &nfpoints, ffillpoints,
2593 &nffillpoints, clippoints, &nclippoints);
2594 /* set the clipping area */
2595 for (i=nclippoints-1; i>=0; i--) {
2596 fprintf(tfp,"%d %d %c ", clippoints[i].x,
2597 clippoints[i].y,
2598 i == nclippoints - 1 ? 'm' : 'l');
2599 }
2600 fprintf(tfp, "cp\n");
2601 }
2602
2603 /* get points for any backward arrowhead */
2604 if (obj->back_arrow) {
2605 if (objtype == OBJ_ARC) {
2606 F_arc *a = (F_arc *) obj;
2607 /* first point */
2608 fpntx1 = a->point[0].x;
2609 fpnty1 = a->point[0].y;
2610 compute_arcarrow_angle(a->center.x, a->center.y,
2611 (double)fpntx1, (double)fpnty1,
2612 a->direction ^ 1, a->back_arrow,
2613 &fpntx2, &fpnty2);
2614 }
2615 calc_arrow(fpntx2, fpnty2, fpntx1, fpnty1, obj->thickness,
2616 obj->back_arrow, bpoints, &nbpoints,bfillpoints,
2617 &nbfillpoints, clippoints, &nclippoints);
2618 /* set the clipping area */
2619 for (i=nclippoints-1; i>=0; i--) {
2620 fprintf(tfp,"%d %d %c ",clippoints[i].x,clippoints[i].y,
2621 i == nclippoints - 1 ? 'm' : 'l');
2622 }
2623 fprintf(tfp, "cp\n");
2624 }
2625 /* intersect the arrowhead clip path(s) with current clip path */
2626 /* use eoclip so that the intersection with the current path
2627 guarantees the correct clip path */
2628 fprintf(tfp, "eoclip\n");
2629 }
2630
2631 /* uses eofill (even/odd rule fill) */
2632 /* ulx and uly define the upper-left corner of the object for pattern alignment */
2633
2634 static void
fill_area(int fill,int pen_color,int fill_color)2635 fill_area(int fill, int pen_color, int fill_color)
2636 {
2637 double pen_r, pen_g, pen_b, fill_r, fill_g, fill_b;
2638
2639 /* get the rgb values for the fill pattern (if necessary) */
2640 if (fill_color < NUM_STD_COLS) {
2641 fill_r=rgbcols[fill_color>0? fill_color: 0].r;
2642 fill_g=rgbcols[fill_color>0? fill_color: 0].g;
2643 fill_b=rgbcols[fill_color>0? fill_color: 0].b;
2644 } else {
2645 fill_r=user_colors[fill_color-NUM_STD_COLS].r/255.0;
2646 fill_g=user_colors[fill_color-NUM_STD_COLS].g/255.0;
2647 fill_b=user_colors[fill_color-NUM_STD_COLS].b/255.0;
2648 }
2649 if (pen_color < NUM_STD_COLS) {
2650 pen_r=rgbcols[pen_color>0? pen_color: 0].r;
2651 pen_g=rgbcols[pen_color>0? pen_color: 0].g;
2652 pen_b=rgbcols[pen_color>0? pen_color: 0].b;
2653 } else {
2654 pen_r=user_colors[pen_color-NUM_STD_COLS].r/255.0;
2655 pen_g=user_colors[pen_color-NUM_STD_COLS].g/255.0;
2656 pen_b=user_colors[pen_color-NUM_STD_COLS].b/255.0;
2657 }
2658
2659 if (fill_color <= 0 && fill < NUMSHADES+NUMTINTS)
2660 /* use gray levels for default and black shades and tints */
2661 fprintf(tfp, "gs %.2f setgray ef gr ", 1.0 - SHADEVAL(fill));
2662
2663 else if (fill < NUMSHADES)
2664 /* a shaded color (not black) */
2665 fprintf(tfp, "gs col%d %.2f shd ef gr ", fill_color,
2666 SHADEVAL(fill));
2667
2668 else if (fill < NUMSHADES+NUMTINTS)
2669 /* a tint */
2670 fprintf(tfp, "gs col%d %.2f tnt ef gr ", fill_color,
2671 TINTVAL(fill));
2672
2673 else {
2674 /* one of the patterns */
2675 int patnum = fill-NUMSHADES-NUMTINTS+1;
2676 char colorspace[13], pencolor[25], fillcolor[25];
2677
2678 if (grayonly) {
2679 double grayfill, graypen;
2680 grayfill = rgb2luminance(fill_r, fill_g, fill_b);
2681 graypen = rgb2luminance(pen_r, pen_g, pen_b);
2682 sprintf(colorspace, "/DeviceGray");
2683 sprintf(fillcolor, "%.2f", grayfill);
2684 sprintf(pencolor, "%.2f", graypen);
2685 } else {
2686 sprintf(colorspace, "/DeviceRGB");
2687 sprintf(fillcolor, "%.2f %.2f %.2f",
2688 fill_r, fill_g, fill_b);
2689 sprintf(pencolor, "%.2f %.2f %.2f",pen_r, pen_g, pen_b);
2690 }
2691
2692 fprintf(tfp, "\n%% Fill with pattern background color\n");
2693 fprintf(tfp, "gs %s setcolorspace %s setcolor fill gr\n",
2694 colorspace, fillcolor);
2695 fprintf(tfp, "\n%% Fill with pattern pen color\n");
2696 fprintf(tfp,"gs %s setcolorspace %s P%d setpattern fill gr\n\n",
2697 colorspace, pencolor, patnum);
2698 }
2699 }
2700
2701 /* define standard colors as "col##" where ## is the number */
2702 static void
genps_std_colors(void)2703 genps_std_colors(void)
2704 {
2705 int i;
2706 for (i=0; i<NUM_STD_COLS; i++) {
2707 /* hollow arrows are filled with white */
2708 if (i == WHITE_COLOR || std_color_used[i]) {
2709 if (grayonly)
2710 fprintf(tfp, "/col%d {%.3f setgray} bind def\n",
2711 i, rgb2luminance(rgbcols[i].r,
2712 rgbcols[i].g,
2713 rgbcols[i].b));
2714 else
2715 fprintf(tfp, "/col%d {%.3f %.3f %.3f srgb} "
2716 "bind def\n", i, rgbcols[i].r,
2717 rgbcols[i].g, rgbcols[i].b);
2718 }
2719 }
2720 }
2721
2722 /* define user colors as "col##" where ## is the number */
2723 static void
genps_usr_colors(void)2724 genps_usr_colors(void)
2725 {
2726 int i;
2727 for (i=0; i<num_usr_cols; i++) {
2728 if (grayonly)
2729 fprintf(tfp, "/col%d {%.3f setgray} bind def\n",
2730 i+NUM_STD_COLS,
2731 rgb2luminance(user_colors[i].r/255.0,
2732 user_colors[i].g/255.0,
2733 user_colors[i].b/255.0));
2734 else
2735 fprintf(tfp, "/col%d {%.3f %.3f %.3f srgb} bind def\n",
2736 i+NUM_STD_COLS, user_colors[i].r/255.0,
2737 user_colors[i].g/255.0,
2738 user_colors[i].b/255.0);
2739 }
2740 }
2741
2742 static bool
iso_text_exist(F_compound * ob)2743 iso_text_exist(F_compound *ob)
2744 {
2745 F_compound *c;
2746 F_text *t;
2747 unsigned char *s;
2748
2749 if (ob->texts != NULL) {
2750 for (t = ob->texts; t != NULL; t = t->next) {
2751 /* look for any ISO (non-ASCII) chars in
2752 non-special text except for pstex */
2753 if (!strcmp(lang,"pstex") && special_text(t))
2754 continue;
2755 for (s = (unsigned char*)t->cstring; *s != '\0'; s++) {
2756 /* look for characters >= 128 or ASCII '-' */
2757 if ((*s>127) || (*s=='-'))
2758 return true;
2759 }
2760 }
2761 }
2762
2763 for (c = ob->compounds; c != NULL; c = c->next) {
2764 if (iso_text_exist(c))
2765 return true;
2766 }
2767 return false;
2768 }
2769
2770 static void
encode_all_fonts(F_compound * ob)2771 encode_all_fonts(F_compound *ob)
2772 {
2773 F_compound *c;
2774 F_text *t;
2775
2776 if (ob->texts != NULL) {
2777 for (t = ob->texts; t != NULL; t = t->next)
2778 if (PSisomap[t->font+1] == false) {
2779 fprintf(tfp, "/%s /%s-iso isovec ReEncode\n",
2780 PSFONT(t), PSFONT(t));
2781 PSisomap[t->font+1] = true;
2782 }
2783 }
2784
2785 for (c = ob->compounds; c != NULL; c = c->next) {
2786 encode_all_fonts(c);
2787 }
2788 }
2789
2790 static bool
ellipse_exist(F_compound * ob)2791 ellipse_exist(F_compound *ob)
2792 {
2793 F_compound *c;
2794
2795 if (NULL != ob->ellipses)
2796 return true;
2797
2798 for (c = ob->compounds; c != NULL; c = c->next) {
2799 if (ellipse_exist(c))
2800 return true;
2801 }
2802
2803 return false;
2804 }
2805
2806 static bool
approx_spline_exist(F_compound * ob)2807 approx_spline_exist(F_compound *ob)
2808 {
2809 F_spline *s;
2810 F_compound *c;
2811
2812 for (s = ob->splines; s != NULL; s = s->next) {
2813 if (approx_spline(s))
2814 return true;
2815 }
2816
2817 for (c = ob->compounds; c != NULL; c = c->next) {
2818 if (approx_spline_exist(c))
2819 return true;
2820 }
2821
2822 return false;
2823 }
2824
2825 /*
2826 * We must start new figure if the current
2827 * depth and the last_depth differ by more than one.
2828 * Depths will be seen with decreasing values.
2829 * Only comments will be output */
2830 static void
do_split(int actual_depth)2831 do_split(int actual_depth)
2832 {
2833 if (actual_depth+1 < last_depth) {
2834 /* depths differ by more than one */
2835 if (fig_number > 0) {
2836 /* end the current figure, if we already had one */
2837 fprintf(tfp,"%% here ends figure;\n");
2838 }
2839 if (actual_depth >= 0) {
2840 /* start a new figure with a comment */
2841 fprintf(tfp,"%% \n");
2842 fprintf(tfp,"%% here starts figure with depth %d\n",
2843 actual_depth);
2844 fig_number++;
2845 /* reset cur_values for multi-postscript. So a new
2846 image gets values being set */
2847 /* This forces the procs that emit the codes to reset
2848 * their current values because these sections of code
2849 * may be rearranged */
2850 cur_thickness = -1;
2851 cur_capstyle = -1;
2852 cur_joinstyle = -1;
2853 }
2854 }
2855 last_depth = actual_depth;
2856 }
2857
2858 /* driver defs */
2859
2860 struct
2861 driver dev_ps = {
2862 genps_option,
2863 genps_start,
2864 genps_grid,
2865 genps_arc,
2866 genps_ellipse,
2867 genps_line,
2868 genps_spline,
2869 genps_text,
2870 genps_end,
2871 INCLUDE_TEXT
2872 };
2873
2874 /* eps is just like ps except with no: pages, pagesize, orientation, offset */
2875
2876 struct
2877 driver dev_eps = {
2878 geneps_option,
2879 genps_start,
2880 genps_grid,
2881 genps_arc,
2882 genps_ellipse,
2883 genps_line,
2884 genps_spline,
2885 genps_text,
2886 genps_end,
2887 INCLUDE_TEXT
2888 };
2889