PLplot: ps.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
ps.c
Go to the documentation of this file.
1 // $Id: ps.c 12874 2013-12-17 05:32:16Z airwin $
2 //
3 // PLplot PostScript device driver.
4 //
5 // Copyright (C) 1992, 2001 Geoffrey Furnish
6 // Copyright (C) 1992, 1993, 1994, 1995, 2001 Maurice LeBrun
7 // Copyright (C) 2000-2010 Alan W. Irwin
8 // Copyright (C) 2001, 2002 Joao Cardoso
9 // Copyright (C) 2001, 2003, 2004 Rafael Laboissiere
10 // Copyright (C) 2004, 2005 Thomas J. Duck
11 // Copyright (C) 2005 Andrew Ross
12 //
13 // This file is part of PLplot.
14 //
15 // PLplot is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU Library General Public License as published
17 // by the Free Software Foundation; either version 2 of the License, or
18 // (at your option) any later version.
19 //
20 // PLplot is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU Library General Public License for more details.
24 //
25 // You should have received a copy of the GNU Library General Public License
26 // along with PLplot; if not, write to the Free Software
27 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 //
29 //
30
31 #include "plDevs.h"
32
33 #define DEBUG
34
35 #ifdef PLD_ps
36 #define NEED_PLDEBUG
37 #include "plplotP.h"
38 #include "drivers.h"
39 #include "ps.h"
40
41 #include <string.h>
42 #include <time.h>
43 #include "plunicode-type1.h"
44 #include "plfci-type1.h"
45
46 // Define macro to truncate small values to zero - prevents
47 // printf printing -0.000
48 #define TRMFLT( a ) ( ( fabs( a ) < 5.0e-4 ) ? 0.0 : ( a ) )
49
50 // Device info
51
52 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_ps =
53 "ps:PostScript File (monochrome):0:ps:29:psm\n"
54 "psc:PostScript File (color):0:ps:30:psc\n";
55
56
57 // Prototypes for functions in this file.
58
59 void plD_dispatch_init_psm( PLDispatchTable *pdt );
60 void plD_dispatch_init_psc( PLDispatchTable *pdt );
61
62 static char *ps_getdate( void );
63 static void ps_init( PLStream * );
64 static void fill_polygon( PLStream *pls );
65 static void proc_str( PLStream *, EscText * );
66 static void esc_purge( unsigned char *, unsigned char * );
67
68 #define OUTBUF_LEN 128
69 static char outbuf[OUTBUF_LEN];
70 static int text = 1;
71 static int color;
72 static int hrshsym = 1;
73
74 static DrvOpt ps_options[] = { { "text", DRV_INT, &text, "Use Postscript text (text=0|1)" },
75 { "color", DRV_INT, &color, "Use color (color=0|1)" },
76 { "hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)" },
77 { NULL, DRV_INT, NULL, NULL } };
78
79 static unsigned char
80 plunicode2type1( const PLUNICODE index,
81 const Unicode_to_Type1_table lookup[],
82 const int number_of_entries );
83
84 static const char *
85 get_font( PSDev* dev, PLUNICODE fci );
86
87 // text > 0 uses some postscript tricks, namely a transformation matrix
88 // that scales, rotates (with slanting) and offsets text strings.
89 // It has yet some bugs for 3d plots.
90
91
92 static void ps_dispatch_init_helper( PLDispatchTable *pdt,
93 const char *menustr, const char *devnam,
94 int type, int seq, plD_init_fp init )
95 {
96 #ifndef ENABLE_DYNDRIVERS
97 pdt->pl_MenuStr = (char *) menustr;
98 pdt->pl_DevName = (char *) devnam;
99 #else
100 (void) menustr; // Cast to void to silence compiler warnings about unused parameters
101 (void) devnam;
102 #endif
103 pdt->pl_type = type;
104 pdt->pl_seq = seq;
105 pdt->pl_init = init;
106 pdt->pl_line = (plD_line_fp) plD_line_ps;
107 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_ps;
108 pdt->pl_eop = (plD_eop_fp) plD_eop_ps;
109 pdt->pl_bop = (plD_bop_fp) plD_bop_ps;
110 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_ps;
111 pdt->pl_state = (plD_state_fp) plD_state_ps;
112 pdt->pl_esc = (plD_esc_fp) plD_esc_ps;
113 }
114
115 void plD_dispatch_init_psm( PLDispatchTable *pdt )
116 {
117 ps_dispatch_init_helper( pdt,
118 "PostScript File (monochrome)", "ps",
119 plDevType_FileOriented, 29,
120 (plD_init_fp) plD_init_psm );
121 }
122
123 void plD_dispatch_init_psc( PLDispatchTable *pdt )
124 {
125 ps_dispatch_init_helper( pdt,
126 "PostScript File (color)", "psc",
127 plDevType_FileOriented, 30,
128 (plD_init_fp) plD_init_psc );
129 }
130
131 //--------------------------------------------------------------------------
132 // plD_init_ps()
133 //
134 // Initialize device.
135 //--------------------------------------------------------------------------
136
137 void
138 plD_init_psm( PLStream *pls )
139 {
140 color = 0;
141 pls->color = 0; // Not a color device
142
143 plParseDrvOpts( ps_options );
144 if ( color )
145 pls->color = 1; // But user wants color
146 ps_init( pls );
147 }
148
149 void
150 plD_init_psc( PLStream *pls )
151 {
152 color = 1;
153 pls->color = 1; // Is a color device
154 plParseDrvOpts( ps_options );
155
156 if ( !color )
157 pls->color = 0; // But user does not want color
158 ps_init( pls );
159 }
160
161 static void
162 ps_init( PLStream *pls )
163 {
164 PSDev *dev;
165
166 PLFLT pxlx, pxly;
167
168 // Set default values - 7.5 x 10 [inches] (72 points = 1 inch)
169 if ( pls->xlength <= 0 || pls->ylength <= 0 )
170 {
171 pls->xlength = 540;
172 pls->ylength = 720;
173 pls->xoffset = 32;
174 pls->yoffset = 32;
175 }
176 if ( pls->xdpi <= 0 )
177 pls->xdpi = 72.;
178 if ( pls->ydpi <= 0 )
179 pls->ydpi = 72.;
180
181 pxlx = YPSSIZE / LPAGE_X;
182 pxly = XPSSIZE / LPAGE_Y;
183
184 if ( text )
185 {
186 pls->dev_text = 1; // want to draw text
187 pls->dev_unicode = 1; // want unicode
188 if ( hrshsym )
189 pls->dev_hrshsym = 1; // want Hershey symbols
190 }
191
192 pls->dev_fill0 = 1; // Can do solid fills
193
194 // Initialize family file info
195
196 plFamInit( pls );
197
198 // Prompt for a file name if not already set
199
200 plOpenFile( pls );
201
202 // Allocate and initialize device-specific data
203
204 if ( pls->dev != NULL )
205 free( (void *) pls->dev );
206
207 pls->dev = calloc( 1, (size_t) sizeof ( PSDev ) );
208 if ( pls->dev == NULL )
209 plexit( "ps_init: Out of memory." );
210
211 dev = (PSDev *) pls->dev;
212
213 dev->xold = PL_UNDEFINED;
214 dev->yold = PL_UNDEFINED;
215
216 plP_setpxl( pxlx, pxly );
217
218 dev->llx = XPSSIZE;
219 dev->lly = YPSSIZE;
220 dev->urx = 0;
221 dev->ury = 0;
222 dev->ptcnt = 0;
223
224 // Rotate by 90 degrees since portrait mode addressing is used
225
226 dev->xmin = 0;
227 dev->ymin = 0;
228 dev->xmax = PSY;
229 dev->ymax = PSX;
230 dev->xlen = dev->xmax - dev->xmin;
231 dev->ylen = dev->ymax - dev->ymin;
232
233 plP_setphy( dev->xmin, dev->xmax, dev->ymin, dev->ymax );
234
235 // If portrait mode is specified, then set up an additional rotation
236 // transformation with aspect ratio allowed to adjust via freeaspect.
237 // Default orientation is landscape (ORIENTATION == 3 or 90 deg rotation
238 // counter-clockwise from portrait). (Legacy PLplot used seascape
239 // which was equivalent to ORIENTATION == 1 or 90 deg clockwise rotation
240 // from portrait.)
241
242 if ( pls->portrait )
243 {
244 plsdiori( (PLFLT) ( 4 - ORIENTATION ) );
245 pls->freeaspect = 1;
246 }
247
248 // Header comments into PostScript file
249
250 fprintf( OF, "%%!PS-Adobe-2.0 EPSF-2.0\n" );
251 fprintf( OF, "%%%%BoundingBox: \n" );
252 fprintf( OF, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" );
253
254 fprintf( OF, "%%%%Title: PLplot Graph\n" );
255 fprintf( OF, "%%%%Creator: PLplot Version %s\n", PLPLOT_VERSION );
256 fprintf( OF, "%%%%CreationDate: %s\n", ps_getdate() );
257 fprintf( OF, "%%%%Pages: (atend)\n" );
258 fprintf( OF, "%%%%EndComments\n\n" );
259
260 // Definitions
261 // Save VM state
262
263 fprintf( OF, "/PSSave save def\n" );
264
265 // Define a dictionary and start using it
266
267 fprintf( OF, "/PSDict 200 dict def\n" );
268 fprintf( OF, "PSDict begin\n" );
269
270 fprintf( OF, "/@restore /restore load def\n" );
271 fprintf( OF, "/restore\n" );
272 fprintf( OF, " {vmstatus pop\n" );
273 fprintf( OF, " dup @VMused lt {pop @VMused} if\n" );
274 fprintf( OF, " exch pop exch @restore /@VMused exch def\n" );
275 fprintf( OF, " } def\n" );
276 fprintf( OF, "/@pri\n" );
277 fprintf( OF, " {\n" );
278 fprintf( OF, " ( ) print\n" );
279 fprintf( OF, " ( ) cvs print\n" );
280 fprintf( OF, " } def\n" );
281
282 // n @copies -
283
284 fprintf( OF, "/@copies\n" );
285 fprintf( OF, " {\n" );
286 fprintf( OF, " /#copies exch def\n" );
287 fprintf( OF, " } def\n" );
288
289 // - @start - -- start everything
290
291 fprintf( OF, "/@start\n" );
292 fprintf( OF, " {\n" );
293 fprintf( OF, " vmstatus pop /@VMused exch def pop\n" );
294 fprintf( OF, " } def\n" );
295
296 // - @end - -- finished
297
298 fprintf( OF, "/@end\n" );
299 fprintf( OF, " {flush\n" );
300 fprintf( OF, " end\n" );
301 fprintf( OF, " PSSave restore\n" );
302 fprintf( OF, " } def\n" );
303
304 // bop - -- begin a new page
305 // Only fill background if we are using color and if the bg isn't white
306
307 fprintf( OF, "/bop\n" );
308 fprintf( OF, " {\n" );
309 fprintf( OF, " /SaveImage save def\n" );
310 fprintf( OF, " } def\n" );
311
312 // - eop - -- end a page
313
314 fprintf( OF, "/eop\n" );
315 fprintf( OF, " {\n" );
316 fprintf( OF, " showpage\n" );
317 fprintf( OF, " SaveImage restore\n" );
318 fprintf( OF, " } def\n" );
319
320 // Set line parameters
321
322 fprintf( OF, "/@line\n" );
323 fprintf( OF, " {0 setlinecap\n" );
324 fprintf( OF, " 0 setlinejoin\n" );
325 fprintf( OF, " 1 setmiterlimit\n" );
326 fprintf( OF, " } def\n" );
327
328 // d @hsize - horizontal clipping dimension
329
330 fprintf( OF, "/@hsize {/hs exch def} def\n" );
331 fprintf( OF, "/@vsize {/vs exch def} def\n" );
332
333 // d @hoffset - shift for the plots
334
335 fprintf( OF, "/@hoffset {/ho exch def} def\n" );
336 fprintf( OF, "/@voffset {/vo exch def} def\n" );
337
338 // Set line width
339
340 fprintf( OF, "/lw %d def\n", (int) (
341 ( pls->width < MIN_WIDTH ) ? DEF_WIDTH :
342 ( pls->width > MAX_WIDTH ) ? MAX_WIDTH : pls->width ) );
343
344 // Setup user specified offsets, scales, sizes for clipping
345
346 fprintf( OF, "/@SetPlot\n" );
347 fprintf( OF, " {\n" );
348 fprintf( OF, " ho vo translate\n" );
349 fprintf( OF, " XScale YScale scale\n" );
350 fprintf( OF, " lw setlinewidth\n" );
351 fprintf( OF, " } def\n" );
352
353 // Setup x & y scales
354
355 fprintf( OF, "/XScale\n" );
356 fprintf( OF, " {hs %d div} def\n", YPSSIZE );
357 fprintf( OF, "/YScale\n" );
358 fprintf( OF, " {vs %d div} def\n", XPSSIZE );
359
360 // Macro definitions of common instructions, to keep output small
361
362 fprintf( OF, "/M {moveto} def\n" );
363 fprintf( OF, "/D {lineto} def\n" );
364 fprintf( OF, "/A {0.5 0 360 arc} def\n" );
365 fprintf( OF, "/S {stroke} def\n" );
366 fprintf( OF, "/Z {stroke newpath} def\n" );
367 // Modify to use fill and stroke for better output with
368 // anti-aliasing
369 //fprintf(OF, "/F {fill} def\n");
370 if ( pls->dev_eofill )
371 fprintf( OF, "/F {closepath gsave eofill grestore stroke} def " );
372 else
373 fprintf( OF, "/F {closepath gsave fill grestore stroke} def " );
374 fprintf( OF, "/N {newpath} def" );
375 fprintf( OF, "/C {setrgbcolor} def\n" );
376 fprintf( OF, "/G {setgray} def\n" );
377 fprintf( OF, "/W {setlinewidth} def\n" );
378 fprintf( OF, "/SF {selectfont} def\n" );
379 fprintf( OF, "/R {rotate} def\n" );
380 fprintf( OF, "/SW {stringwidth 2 index mul exch 2 index mul exch rmoveto pop} bind def\n" );
381 fprintf( OF, "/B {Z %d %d M %d %d D %d %d D %d %d D %d %d closepath} def\n",
382 XMIN, YMIN, XMIN, YMAX, XMAX, YMAX, XMAX, YMIN, XMIN, YMIN );
383 fprintf( OF, "/CL {newpath M D D D closepath clip} def\n" );
384
385 // End of dictionary definition
386
387 fprintf( OF, "end\n\n" );
388
389 // Set up the plots
390
391 fprintf( OF, "PSDict begin\n" );
392 fprintf( OF, "@start\n" );
393 fprintf( OF, "%d @copies\n", COPIES );
394 fprintf( OF, "@line\n" );
395 fprintf( OF, "%d @hsize\n", YSIZE );
396 fprintf( OF, "%d @vsize\n", XSIZE );
397 fprintf( OF, "%d @hoffset\n", YOFFSET );
398 fprintf( OF, "%d @voffset\n", XOFFSET );
399
400 fprintf( OF, "@SetPlot\n\n" );
401 }
402
403 //--------------------------------------------------------------------------
404 // plD_line_ps()
405 //
406 // Draw a line in the current color from (x1,y1) to (x2,y2).
407 //--------------------------------------------------------------------------
408
409 void
410 plD_line_ps( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
411 {
412 PSDev *dev = (PSDev *) pls->dev;
413 PLINT x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
414
415 // Rotate by 90 degrees
416
417 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x1, &y1 );
418 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x2, &y2 );
419
420 if ( x1 == dev->xold && y1 == dev->yold && dev->ptcnt < 40 )
421 {
422 if ( pls->linepos + 12 > LINELENGTH )
423 {
424 putc( '\n', OF );
425 pls->linepos = 0;
426 }
427 else
428 putc( ' ', OF );
429
430 snprintf( outbuf, OUTBUF_LEN, "%d %d D", x2, y2 );
431 dev->ptcnt++;
432 pls->linepos += 12;
433 }
434 else
435 {
436 fprintf( OF, " Z\n" );
437 pls->linepos = 0;
438
439 if ( x1 == x2 && y1 == y2 ) // must be a single dot, draw a circle
440 snprintf( outbuf, OUTBUF_LEN, "%d %d A", x1, y1 );
441 else
442 snprintf( outbuf, OUTBUF_LEN, "%d %d M %d %d D", x1, y1, x2, y2 );
443 dev->llx = MIN( dev->llx, x1 );
444 dev->lly = MIN( dev->lly, y1 );
445 dev->urx = MAX( dev->urx, x1 );
446 dev->ury = MAX( dev->ury, y1 );
447 dev->ptcnt = 1;
448 pls->linepos += 24;
449 }
450 dev->llx = MIN( dev->llx, x2 );
451 dev->lly = MIN( dev->lly, y2 );
452 dev->urx = MAX( dev->urx, x2 );
453 dev->ury = MAX( dev->ury, y2 );
454
455 fprintf( OF, "%s", outbuf );
456 pls->bytecnt += 1 + (PLINT) strlen( outbuf );
457 dev->xold = x2;
458 dev->yold = y2;
459 }
460
461 //--------------------------------------------------------------------------
462 // plD_polyline_ps()
463 //
464 // Draw a polyline in the current color.
465 //--------------------------------------------------------------------------
466
467 void
468 plD_polyline_ps( PLStream *pls, short *xa, short *ya, PLINT npts )
469 {
470 PLINT i;
471
472 for ( i = 0; i < npts - 1; i++ )
473 plD_line_ps( pls, xa[i], ya[i], xa[i + 1], ya[i + 1] );
474 }
475
476 //--------------------------------------------------------------------------
477 // plD_eop_ps()
478 //
479 // End of page.
480 //--------------------------------------------------------------------------
481
482 void
483 plD_eop_ps( PLStream *pls )
484 {
485 fprintf( OF, " S\neop\n" );
486 }
487
488 //--------------------------------------------------------------------------
489 // plD_bop_ps()
490 //
491 // Set up for the next page.
492 // Advance to next family file if necessary (file output).
493 //--------------------------------------------------------------------------
494
495 void
496 plD_bop_ps( PLStream *pls )
497 {
498 PSDev *dev = (PSDev *) pls->dev;
499
500 dev->xold = PL_UNDEFINED;
501 dev->yold = PL_UNDEFINED;
502
503 if ( !pls->termin )
504 plGetFam( pls );
505
506 pls->page++;
507
508 if ( pls->family )
509 fprintf( OF, "%%%%Page: %d %d\n", (int) pls->page, 1 );
510 else
511 fprintf( OF, "%%%%Page: %d %d\n", (int) pls->page, (int) pls->page );
512
513 fprintf( OF, "bop\n" );
514 if ( pls->color )
515 {
516 PLFLT r, g, b;
517 if ( pls->cmap0[0].r != 0xFF ||
518 pls->cmap0[0].g != 0xFF ||
519 pls->cmap0[0].b != 0xFF )
520 {
521 r = ( (PLFLT) pls->cmap0[0].r ) / 255.;
522 g = ( (PLFLT) pls->cmap0[0].g ) / 255.;
523 b = ( (PLFLT) pls->cmap0[0].b ) / 255.;
524
525 fprintf( OF, "B %.4f %.4f %.4f C F\n", r, g, b );
526 }
527 }
528 pls->linepos = 0;
529
530 // This ensures the color and line width are set correctly at the beginning of
531 // each page
532
533 plD_state_ps( pls, PLSTATE_COLOR0 );
534 plD_state_ps( pls, PLSTATE_WIDTH );
535 }
536
537 //--------------------------------------------------------------------------
538 // plD_tidy_ps()
539 //
540 // Close graphics file or otherwise clean up.
541 //--------------------------------------------------------------------------
542
543 void
544 plD_tidy_ps( PLStream *pls )
545 {
546 PSDev *dev = (PSDev *) pls->dev;
547
548 fprintf( OF, "\n%%%%Trailer\n" );
549
550 dev->llx /= ENLARGE;
551 dev->lly /= ENLARGE;
552 dev->urx /= ENLARGE;
553 dev->ury /= ENLARGE;
554 dev->llx += XOFFSET;
555 dev->lly += YOFFSET;
556 dev->urx += XOFFSET;
557 dev->ury += YOFFSET;
558
559 // changed for correct Bounding boundaries Jan Thorbecke okt 1993
560 // occurs from the integer truncation -- postscript uses fp arithmetic
561
562 dev->urx += 1;
563 dev->ury += 1;
564
565 if ( pls->family )
566 fprintf( OF, "%%%%Pages: %d\n", (int) 1 );
567 else
568 fprintf( OF, "%%%%Pages: %d\n", (int) pls->page );
569
570 fprintf( OF, "@end\n" );
571 fprintf( OF, "%%%%EOF\n" );
572
573 // Backtrack to write the BoundingBox at the beginning
574 // Some applications don't like it atend
575
576 rewind( OF );
577 fprintf( OF, "%%!PS-Adobe-2.0 EPSF-2.0\n" );
578 fprintf( OF, "%%%%BoundingBox: %d %d %d %d\n",
579 dev->llx, dev->lly, dev->urx, dev->ury );
580 plCloseFile( pls );
581 }
582
583 //--------------------------------------------------------------------------
584 // plD_state_ps()
585 //
586 // Handle change in PLStream state (color, pen width, fill attribute, etc).
587 //--------------------------------------------------------------------------
588
589 void
590 plD_state_ps( PLStream *pls, PLINT op )
591 {
592 PSDev *dev = (PSDev *) pls->dev;
593
594 switch ( op )
595 {
596 case PLSTATE_WIDTH: {
597 int width = (int) (
598 ( pls->width < MIN_WIDTH ) ? DEF_WIDTH :
599 ( pls->width > MAX_WIDTH ) ? MAX_WIDTH : pls->width );
600
601 fprintf( OF, " S\n%d W", width );
602
603 dev->xold = PL_UNDEFINED;
604 dev->yold = PL_UNDEFINED;
605 break;
606 }
607 case PLSTATE_COLOR0:
608 if ( !pls->color )
609 {
610 fprintf( OF, " S\n%.4f G", ( pls->icol0 ? 0.0 : 1.0 ) );
611 break;
612 }
613 // else fallthrough
614 case PLSTATE_COLOR1:
615 if ( pls->color )
616 {
617 PLFLT r = ( (PLFLT) pls->curcolor.r ) / 255.0;
618 PLFLT g = ( (PLFLT) pls->curcolor.g ) / 255.0;
619 PLFLT b = ( (PLFLT) pls->curcolor.b ) / 255.0;
620
621 fprintf( OF, " S\n%.4f %.4f %.4f C", r, g, b );
622 }
623 else
624 {
625 PLFLT r = ( (PLFLT) pls->curcolor.r ) / 255.0;
626 fprintf( OF, " S\n%.4f G", 1.0 - r );
627 }
628 break;
629 }
630
631 // Reinitialize current point location.
632
633 if ( dev->xold != PL_UNDEFINED && dev->yold != PL_UNDEFINED )
634 {
635 fprintf( OF, " %d %d M \n", (int) dev->xold, (int) dev->yold );
636 }
637 }
638
639 //--------------------------------------------------------------------------
640 // plD_esc_ps()
641 //
642 // Escape function.
643 //--------------------------------------------------------------------------
644
645 void
646 plD_esc_ps( PLStream *pls, PLINT op, void *ptr )
647 {
648 switch ( op )
649 {
650 case PLESC_FILL:
651 fill_polygon( pls );
652 break;
653 case PLESC_HAS_TEXT:
654 proc_str( pls, (EscText *) ptr );
655 break;
656 }
657 }
658
659 //--------------------------------------------------------------------------
660 // fill_polygon()
661 //
662 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
663 // Only solid color fill supported.
664 //--------------------------------------------------------------------------
665
666 static void
667 fill_polygon( PLStream *pls )
668 {
669 PSDev *dev = (PSDev *) pls->dev;
670 PLINT n, ix = 0, iy = 0;
671 PLINT x, y;
672
673 fprintf( OF, " Z\n" );
674
675 for ( n = 0; n < pls->dev_npts; n++ )
676 {
677 x = pls->dev_x[ix++];
678 y = pls->dev_y[iy++];
679
680 // Rotate by 90 degrees
681
682 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x, &y );
683
684 // First time through start with a x y moveto
685
686 if ( n == 0 )
687 {
688 snprintf( outbuf, OUTBUF_LEN, "N %d %d M", x, y );
689 dev->llx = MIN( dev->llx, x );
690 dev->lly = MIN( dev->lly, y );
691 dev->urx = MAX( dev->urx, x );
692 dev->ury = MAX( dev->ury, y );
693 fprintf( OF, "%s", outbuf );
694 pls->bytecnt += (PLINT) strlen( outbuf );
695 continue;
696 }
697
698 if ( pls->linepos + 21 > LINELENGTH )
699 {
700 putc( '\n', OF );
701 pls->linepos = 0;
702 }
703 else
704 putc( ' ', OF );
705
706 pls->bytecnt++;
707
708 snprintf( outbuf, OUTBUF_LEN, "%d %d D", x, y );
709 dev->llx = MIN( dev->llx, x );
710 dev->lly = MIN( dev->lly, y );
711 dev->urx = MAX( dev->urx, x );
712 dev->ury = MAX( dev->ury, y );
713
714 fprintf( OF, "%s", outbuf );
715 pls->bytecnt += (PLINT) strlen( outbuf );
716 pls->linepos += 21;
717 }
718 dev->xold = PL_UNDEFINED;
719 dev->yold = PL_UNDEFINED;
720 fprintf( OF, " F " );
721 }
722
723 //--------------------------------------------------------------------------
724 // ps_getdate()
725 //
726 // Get the date and time
727 //--------------------------------------------------------------------------
728
729 static char *
730 ps_getdate( void )
731 {
732 int len;
733 time_t t;
734 char *p;
735
736 t = time( (time_t *) 0 );
737 p = ctime( &t );
738 len = (int) strlen( p );
739 *( p + len - 1 ) = '\0'; // zap the newline character
740 return p;
741 }
742
743
744 // 0.8 should mimic the offset of first superscript/subscript level
745 // implemented in plstr (plsym.c) for Hershey fonts. However, when
746 // comparing with -dev xwin and -dev xcairo results changing this
747 // factor to 0.6 appears to offset the centers of the letters
748 // appropriately while 0.8 gives much poorer agreement with the
749 // other devices.
750 # define RISE_FACTOR 0.6
751
752 //--------------------------------------------------------------------------
753 // proc_str()
754 //
755 // Prints postscript strings.
756 // N.B. Now unicode only, no string access!
757 //
758 //--------------------------------------------------------------------------
759
760 void
761 proc_str( PLStream *pls, EscText *args )
762 {
763 PLFLT *t = args->xform, tt[4]; // Transform matrices
764 PLFLT theta, shear, stride; // Rotation angle and shear from the matrix
765 PLFLT ft_ht, offset; // Font height and offset
766 PLFLT cs, sn, l1, l2;
767 PSDev *dev = (PSDev *) pls->dev;
768 const char *font;
769 char esc;
770 // Be generous. Used to store lots of font changes which take
771 // 3 characters per change.
772 #define PROC_STR_STRING_LENGTH 1000
773 unsigned char *strp, str[PROC_STR_STRING_LENGTH], *cur_strp,
774 cur_str[PROC_STR_STRING_LENGTH];
775 float font_factor = 1.4f;
776 PLINT clxmin, clxmax, clymin, clymax; // Clip limits
777 PLINT clipx[4], clipy[4]; // Current clip limits
778
779 PLFLT scale = 1., up = 0.; // Font scaling and shifting parameters
780
781 int i = 0; // String index
782
783 // unicode only! so test for it.
784 if ( args->unicode_array_len > 0 )
785 {
786 int j, s, f;
787 const char *fonts[PROC_STR_STRING_LENGTH];
788 const PLUNICODE *cur_text;
789 PLUNICODE fci, fci_save;
790 PLFLT old_sscale, sscale, old_soffset, soffset, ddup;
791 PLINT level = 0;
792 // translate from unicode into type 1 font index.
793 //
794 // Choose the font family, style, variant, and weight using
795 // the FCI (font characterization integer).
796 //
797
798 plgesc( &esc );
799 plgfci( &fci );
800 fci_save = fci;
801 font = get_font( dev, fci );
802 cur_text = args->unicode_array;
803 for ( f = s = j = 0; j < args->unicode_array_len; j++ )
804 {
805 if ( cur_text[j] & PL_FCI_MARK )
806 {
807 // process an FCI by saving it and escaping cur_str
808 // with an escff to make it a 2-character escape
809 // that is not used in legacy Hershey code
810 //
811 if ( ( f < PROC_STR_STRING_LENGTH ) && ( s + 3 < PROC_STR_STRING_LENGTH ) )
812 {
813 fci_save = cur_text[j];
814 fonts[f++] = get_font( dev, fci_save );
815 cur_str[s++] = (unsigned char) esc;
816 cur_str[s++] = 'f';
817 cur_str[s++] = 'f';
818 }
819 }
820 else if ( s + 4 < PROC_STR_STRING_LENGTH )
821 {
822 #undef PL_TEST_TYPE1
823 #ifdef PL_TEST_TYPE1
824 // Use this test case only to conveniently view Type1 font
825 // possibilities (as in test_type1.py example).
826 // This functionality is useless other than for this test case.
827 PLINT ifamily, istyle, iweight;
828 plgfont( &ifamily, &istyle, &iweight );
829 if ( 0 <= cur_text[j] && cur_text[j] < 256 )
830 cur_str[s++] = cur_text[j];
831 else
832 cur_str[s++] = 32;
833 // Overwrite font just for this special case.
834 if ( ifamily == PL_FCI_SYMBOL )
835 font = get_font( dev, 0 );
836 else
837 font = get_font( dev, fci );
838 #else
839 cur_str[s] = plunicode2type1( cur_text[j], dev->lookup, dev->nlookup );
840 if ( cur_text[j] != ' ' && cur_str[s] == ' ' )
841 {
842 // failed lookup.
843 if ( !dev->if_symbol_font )
844 {
845 // failed standard font lookup. Use symbol
846 // font instead which will return a blank if
847 // that fails as well.
848 fonts[f++] = get_font( dev, 0 );
849 cur_str[s++] = (unsigned char) esc;
850 cur_str[s++] = 'f';
851 cur_str[s++] = 'f';
852 cur_str[s++] = plunicode2type1( cur_text[j], dev->lookup, dev->nlookup );
853 }
854 else
855 {
856 // failed symbol font lookup. Use last standard
857 // font instead which will return a blank if
858 // that fails as well.
859 fonts[f++] = get_font( dev, fci_save );
860 cur_str[s++] = (unsigned char) esc;
861 cur_str[s++] = 'f';
862 cur_str[s++] = 'f';
863 cur_str[s++] = plunicode2type1( cur_text[j], dev->lookup, dev->nlookup );
864 }
865 }
866 else
867 {
868 // lookup succeeded.
869 s++;
870 }
871 #endif
872 pldebug( "proc_str", "unicode = 0x%x, type 1 code = %d\n",
873 cur_text[j], cur_str[s - 1] );
874 }
875 }
876 cur_str[s] = '\0';
877
878 // finish previous polyline
879
880 dev->xold = PL_UNDEFINED;
881 dev->yold = PL_UNDEFINED;
882
883 // Determine the font height
884 ft_ht = pls->chrht * 72.0 / 25.4; // ft_ht in points, ht is in mm
885
886
887 // The transform matrix has only rotations and shears; extract them
888 plRotationShear( t, &theta, &shear, &stride );
889 cs = cos( theta );
890 sn = sin( theta );
891 tt[0] = t[0] * cs + t[2] * sn;
892 tt[1] = t[1] * cs + t[3] * sn;
893 tt[2] = -t[0] * sn + t[2] * cs;
894 tt[3] = -t[1] * sn + t[3] * cs;
895
896 //
897 // Reference point conventions:
898 // If base = 0, it is aligned with the center of the text box
899 // If base = 1, it is aligned with the baseline of the text box
900 // If base = 2, it is aligned with the top of the text box
901 //
902 // Currently plplot only uses base=0
903 // Postscript uses base=1
904 //
905 // We must calculate the difference between the two and apply the offset.
906 //
907
908 if ( args->base == 2 ) // not supported by plplot
909 offset = ENLARGE * ft_ht / 2.; // half font height
910 else if ( args->base == 1 )
911 offset = 0.;
912 else
913 offset = -ENLARGE * ft_ht / 2.;
914
915 // Determine the adjustment for page orientation
916 theta -= PI / 2. * pls->diorot;
917 args->y += (PLINT) ( offset * cos( theta ) );
918 args->x -= (PLINT) ( offset * sin( theta ) );
919
920 // ps driver is rotated by default
921 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
922 &( args->x ), &( args->y ) );
923
924 // Correct for the fact ps driver uses landscape by default
925 theta += PI / 2.;
926
927 // Output
928 // Set clipping
929 clipx[0] = pls->clpxmi;
930 clipx[2] = pls->clpxma;
931 clipy[0] = pls->clpymi;
932 clipy[2] = pls->clpyma;
933 clipx[1] = clipx[2];
934 clipy[1] = clipy[0];
935 clipx[3] = clipx[0];
936 clipy[3] = clipy[2];
937 difilt( clipx, clipy, 4, &clxmin, &clxmax, &clymin, &clymax );
938 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
939 &clipx[0], &clipy[0] );
940 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
941 &clipx[1], &clipy[1] );
942 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
943 &clipx[2], &clipy[2] );
944 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
945 &clipx[3], &clipy[3] );
946 fprintf( OF, " gsave %d %d %d %d %d %d %d %d CL\n", clipx[0], clipy[0], clipx[1], clipy[1], clipx[2], clipy[2], clipx[3], clipy[3] );
947
948 // move to string reference point
949 fprintf( OF, " %d %d M\n", args->x, args->y );
950
951 // Save the current position and set the string rotation
952 fprintf( OF, "gsave %.3f R\n", TRMFLT( theta * 180. / PI ) );
953
954 // Purge escape sequences from string, so that postscript can find it's
955 // length. The string length is computed with the current font, and can
956 // thus be wrong if there are font change escape sequences in the string
957 //
958
959 esc_purge( str, cur_str );
960
961 fprintf( OF, "/%s %.3f SF\n", font, TRMFLT( font_factor * ENLARGE * ft_ht ) );
962
963 // Output string, while escaping the '(', ')' and '\' characters.
964 // this string is output for measurement purposes only.
965 //
966 fprintf( OF, "%.3f (", TRMFLT( -args->just ) );
967 while ( str[i] != '\0' )
968 {
969 if ( str[i] == '(' || str[i] == ')' || str[i] == '\\' )
970 fprintf( OF, "\\%c", str[i] );
971 else
972 fprintf( OF, "%c", str[i] );
973 i++;
974 }
975 fprintf( OF, ") SW\n" );
976
977
978 // Parse string for PLplot escape sequences and print everything out
979
980 cur_strp = cur_str;
981 f = 0;
982 do
983 {
984 strp = str;
985
986 if ( *cur_strp == esc )
987 {
988 cur_strp++;
989
990 if ( *cur_strp == esc ) // <esc><esc>
991 {
992 *strp++ = *cur_strp++;
993 }
994 else if ( *cur_strp == 'f' )
995 {
996 cur_strp++;
997 if ( *cur_strp++ != 'f' )
998 {
999 // escff occurs because of logic above. But any suffix
1000 // other than "f" should never happen.
1001 plabort( "proc_str, internal PLplot logic error;"
1002 "wrong escf escape sequence" );
1003 return;
1004 }
1005 font = fonts[f++];
1006 pldebug( "proc_str", "string-specified fci = 0x%x, font name = %s\n", fci, font );
1007 continue;
1008 }
1009 else
1010 switch ( *cur_strp++ )
1011 {
1012 case 'd': //subscript
1013 case 'D':
1014 plP_script_scale( FALSE, &level,
1015 &old_sscale, &sscale, &old_soffset, &soffset );
1016 scale = sscale;
1017 // The correction for the difference in magnitude
1018 // between the baseline and middle coordinate systems
1019 // for subscripts should be
1020 // -0.5*(base font size - superscript/subscript font size).
1021 ddup = -0.5 * ( 1.0 - sscale );
1022 up = -font_factor * ENLARGE * ft_ht * ( RISE_FACTOR * soffset + ddup );
1023 break;
1024
1025 case 'u': //superscript
1026 case 'U':
1027 plP_script_scale( TRUE, &level,
1028 &old_sscale, &sscale, &old_soffset, &soffset );
1029 scale = sscale;
1030 // The correction for the difference in magnitude
1031 // between the baseline and middle coordinate systems
1032 // for superscripts should be
1033 // 0.5*(base font size - superscript/subscript font size).
1034 ddup = 0.5 * ( 1.0 - sscale );
1035 up = font_factor * ENLARGE * ft_ht * ( RISE_FACTOR * soffset + ddup );
1036 break;
1037
1038 // ignore the next sequences
1039
1040 case '+':
1041 case '-':
1042 case 'b':
1043 case 'B':
1044 plwarn( "'+', '-', and 'b/B' text escape sequences not processed." );
1045 break;
1046 }
1047 }
1048
1049 // copy from current to next token, adding a postscript escape
1050 // char '\' if necessary
1051 //
1052 while ( *cur_strp && *cur_strp != esc )
1053 {
1054 if ( *cur_strp == '(' || *cur_strp == ')' || *cur_strp == '\\' )
1055 *strp++ = '\\';
1056 *strp++ = *cur_strp++;
1057 }
1058 *strp = '\0';
1059
1060 if ( fabs( up ) < 0.001 )
1061 up = 0.; // Watch out for small differences
1062
1063 // Apply the scaling and the shear
1064 fprintf( OF, "/%s [%.3f %.3f %.3f %.3f 0 0] SF\n",
1065 font,
1066 TRMFLT( tt[0] * font_factor * ENLARGE * ft_ht * scale ),
1067 TRMFLT( tt[2] * font_factor * ENLARGE * ft_ht * scale ),
1068 TRMFLT( tt[1] * font_factor * ENLARGE * ft_ht * scale ),
1069 TRMFLT( tt[3] * font_factor * ENLARGE * ft_ht * scale ) );
1070
1071 // if up/down escape sequences, save current point and adjust baseline;
1072 // take the shear into account
1073 if ( up != 0. )
1074 fprintf( OF, "gsave %.3f %.3f rmoveto\n", TRMFLT( up * tt[1] ), TRMFLT( up * tt[3] ) );
1075
1076 // print the string
1077 fprintf( OF, "(%s) show\n", str );
1078
1079 // back to baseline
1080 if ( up != 0. )
1081 fprintf( OF, "grestore (%s) stringwidth rmoveto\n", str );
1082 } while ( *cur_strp );
1083
1084 fprintf( OF, "grestore\n" );
1085 fprintf( OF, "grestore\n" );
1086
1087 //
1088 // keep driver happy -- needed for background and orientation.
1089 // arghhh! can't calculate it, as I only have the string reference
1090 // point, not its extent!
1091 // Still a hack - but at least it takes into account the string
1092 // length and justification. Character width is assumed to be
1093 // 0.6 * character height. Add on an extra 1.5 * character height
1094 // for safety.
1095 //
1096 cs = cos( theta );
1097 sn = sin( theta );
1098 l1 = -i * args->just;
1099 l2 = i * ( 1. - args->just );
1100 // Factor of 0.6 is an empirical fudge to convert character
1101 // height to average character width
1102 l1 *= 0.6;
1103 l2 *= 0.6;
1104
1105 dev->llx = (int) ( MIN( dev->llx, args->x + ( MIN( l1 * cs, l2 * cs ) - 1.5 ) * font_factor * ft_ht * ENLARGE ) );
1106 dev->lly = (int) ( MIN( dev->lly, args->y + ( MIN( l1 * sn, l2 * sn ) - 1.5 ) * font_factor * ft_ht * ENLARGE ) );
1107 dev->urx = (int) ( MAX( dev->urx, args->x + ( MAX( l1 * cs, l2 * cs ) + 1.5 ) * font_factor * ft_ht * ENLARGE ) );
1108 dev->ury = (int) ( MAX( dev->ury, args->y + ( MAX( l1 * sn, l2 * sn ) + 1.5 ) * font_factor * ft_ht * ENLARGE ) );
1109 }
1110 }
1111
1112 static void
1113 esc_purge( unsigned char *dstr, unsigned char *sstr )
1114 {
1115 char esc;
1116
1117 plgesc( &esc );
1118
1119 while ( *sstr )
1120 {
1121 if ( *sstr != esc )
1122 {
1123 *dstr++ = *sstr++;
1124 continue;
1125 }
1126
1127 sstr++;
1128 if ( *sstr == esc )
1129 {
1130 *dstr++ = *sstr++;
1131 continue;
1132 }
1133
1134 else
1135 {
1136 switch ( *sstr++ )
1137 {
1138 case 'f':
1139 sstr++;
1140 break; // two chars sequence
1141
1142 default:
1143 break; // single char escape
1144 }
1145 }
1146 }
1147 *dstr = '\0';
1148 }
1149
1150 //--------------------------------------------------------------------------
1151 // unsigned char plunicode2type1 (const PLUNICODE index,
1152 // const Unicode_to_Type1_table lookup[], const int number_of_entries)
1153 //
1154 // Function takes an input unicode index, looks through the lookup
1155 // table (which must be sorted by PLUNICODE Unicode), then returns the
1156 // corresponding Type1 code in the lookup table. If the Unicode index is
1157 // not present the returned value is 32 (which is normally a blank
1158 // for Type 1 fonts).
1159 //--------------------------------------------------------------------------
1160
1161 static unsigned char
1162 plunicode2type1( const PLUNICODE index,
1163 const Unicode_to_Type1_table lookup[],
1164 const int nlookup )
1165 {
1166 int jlo = -1, jmid, jhi = nlookup;
1167 while ( jhi - jlo > 1 )
1168 {
1169 // Note that although jlo or jhi can be just outside valid
1170 // range (see initialization above) because of while condition
1171 // jlo < jmid < jhi and jmid must be in valid range.
1172 //
1173 jmid = ( jlo + jhi ) / 2;
1174 if ( index > lookup[jmid].Unicode )
1175 jlo = jmid;
1176 else if ( index < lookup[jmid].Unicode )
1177 jhi = jmid;
1178 else
1179 // We have found it!
1180 // index == lookup[jmid].Unicode
1181 //
1182 return ( lookup[jmid].Type1 );
1183 }
1184 // jlo is invalid or it is valid and index > lookup[jlo].Unicode.
1185 // jhi is invalid or it is valid and index < lookup[jhi].Unicode.
1186 // All these conditions together imply index cannot be found in lookup.
1187 // Mark with ' ' (which is normally the index for blank in type 1 fonts).
1188 //
1189 return ( ' ' );
1190 }
1191
1192 //--------------------------------------------------------------------------
1193 // get_font( PSDev* dev, PLUNICODE fci )
1194 //
1195 // Sets the Type1 font.
1196 //--------------------------------------------------------------------------
1197 static const char *
1198 get_font( PSDev* dev, PLUNICODE fci )
1199 {
1200 const char *font;
1201 // fci = 0 is a special value indicating the Type 1 Symbol font
1202 // is desired. This value cannot be confused with a normal FCI value
1203 // because it doesn't have the PL_FCI_MARK.
1204 if ( fci == 0 )
1205 {
1206 font = "Symbol";
1207 dev->nlookup = number_of_entries_in_unicode_to_symbol_table;
1208 dev->lookup = unicode_to_symbol_lookup_table;
1209 dev->if_symbol_font = 1;
1210 }
1211 else
1212 {
1213 // convert the fci to Base14/Type1 font information
1214 font = plP_FCI2FontName( fci, Type1Lookup, N_Type1Lookup );
1215 dev->nlookup = number_of_entries_in_unicode_to_standard_table;
1216 dev->lookup = unicode_to_standard_lookup_table;
1217 dev->if_symbol_font = 0;
1218 }
1219 pldebug( "set_font", "fci = 0x%x, font name = %s\n", fci, font );
1220 return ( font );
1221 }
1222
1223 #else
1224 int
1225 pldummy_ps()
1226 {
1227 return 0;
1228 }
1229
1230 #endif // PLD_ps