PLplot
5.10.0
|
00001 // PLplot PostScript device driver. 00002 // 00003 // Copyright (C) 1992, 2001 Geoffrey Furnish 00004 // Copyright (C) 1992, 1993, 1994, 1995, 2001 Maurice LeBrun 00005 // Copyright (C) 2000-2014 Alan W. Irwin 00006 // Copyright (C) 2001, 2002 Joao Cardoso 00007 // Copyright (C) 2001, 2003, 2004 Rafael Laboissiere 00008 // Copyright (C) 2004, 2005 Thomas J. Duck 00009 // Copyright (C) 2005 Andrew Ross 00010 // 00011 // This file is part of PLplot. 00012 // 00013 // PLplot is free software; you can redistribute it and/or modify 00014 // it under the terms of the GNU Library General Public License as published 00015 // by the Free Software Foundation; either version 2 of the License, or 00016 // (at your option) any later version. 00017 // 00018 // PLplot is distributed in the hope that it will be useful, 00019 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00021 // GNU Library General Public License for more details. 00022 // 00023 // You should have received a copy of the GNU Library General Public License 00024 // along with PLplot; if not, write to the Free Software 00025 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00026 // 00027 // 00028 00029 #include "plDevs.h" 00030 00031 #define DEBUG 00032 00033 #ifdef PLD_ps 00034 #define NEED_PLDEBUG 00035 #include "plplotP.h" 00036 #include "drivers.h" 00037 #include "ps.h" 00038 00039 #include <string.h> 00040 #include <time.h> 00041 #include "plunicode-type1.h" 00042 #include "plfci-type1.h" 00043 00044 // Define macro to truncate small values to zero - prevents 00045 // printf printing -0.000 00046 #define TRMFLT( a ) ( ( fabs( a ) < 5.0e-4 ) ? 0.0 : ( a ) ) 00047 00048 // Device info 00049 00050 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_ps = 00051 "ps:PostScript File (monochrome):0:ps:29:psm\n" 00052 "psc:PostScript File (color):0:ps:30:psc\n"; 00053 00054 00055 // Prototypes for functions in this file. 00056 00057 void plD_dispatch_init_psm( PLDispatchTable *pdt ); 00058 void plD_dispatch_init_psc( PLDispatchTable *pdt ); 00059 00060 static char *ps_getdate( void ); 00061 static void ps_init( PLStream * ); 00062 static void fill_polygon( PLStream *pls ); 00063 static void proc_str( PLStream *, EscText * ); 00064 static void esc_purge( unsigned char *, unsigned char * ); 00065 00066 #define OUTBUF_LEN 128 00067 static char outbuf[OUTBUF_LEN]; 00068 static int text = 1; 00069 static int color; 00070 static int hrshsym = 1; 00071 00072 static DrvOpt ps_options[] = { { "text", DRV_INT, &text, "Use Postscript text (text=0|1)" }, 00073 { "color", DRV_INT, &color, "Use color (color=0|1)" }, 00074 { "hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)" }, 00075 { NULL, DRV_INT, NULL, NULL } }; 00076 00077 static unsigned char 00078 plunicode2type1( const PLUNICODE index, 00079 const Unicode_to_Type1_table lookup[], 00080 const int number_of_entries ); 00081 00082 static const char * 00083 get_font( PSDev* dev, PLUNICODE fci ); 00084 00085 // text > 0 uses some postscript tricks, namely a transformation matrix 00086 // that scales, rotates (with slanting) and offsets text strings. 00087 // It has yet some bugs for 3d plots. 00088 00089 00090 static void ps_dispatch_init_helper( PLDispatchTable *pdt, 00091 const char *menustr, const char *devnam, 00092 int type, int seq, plD_init_fp init ) 00093 { 00094 #ifndef ENABLE_DYNDRIVERS 00095 pdt->pl_MenuStr = (char *) menustr; 00096 pdt->pl_DevName = (char *) devnam; 00097 #else 00098 (void) menustr; // Cast to void to silence compiler warnings about unused parameters 00099 (void) devnam; 00100 #endif 00101 pdt->pl_type = type; 00102 pdt->pl_seq = seq; 00103 pdt->pl_init = init; 00104 pdt->pl_line = (plD_line_fp) plD_line_ps; 00105 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_ps; 00106 pdt->pl_eop = (plD_eop_fp) plD_eop_ps; 00107 pdt->pl_bop = (plD_bop_fp) plD_bop_ps; 00108 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_ps; 00109 pdt->pl_state = (plD_state_fp) plD_state_ps; 00110 pdt->pl_esc = (plD_esc_fp) plD_esc_ps; 00111 } 00112 00113 void plD_dispatch_init_psm( PLDispatchTable *pdt ) 00114 { 00115 ps_dispatch_init_helper( pdt, 00116 "PostScript File (monochrome)", "ps", 00117 plDevType_FileOriented, 29, 00118 (plD_init_fp) plD_init_psm ); 00119 } 00120 00121 void plD_dispatch_init_psc( PLDispatchTable *pdt ) 00122 { 00123 ps_dispatch_init_helper( pdt, 00124 "PostScript File (color)", "psc", 00125 plDevType_FileOriented, 30, 00126 (plD_init_fp) plD_init_psc ); 00127 } 00128 00129 //-------------------------------------------------------------------------- 00130 // plD_init_ps() 00131 // 00132 // Initialize device. 00133 //-------------------------------------------------------------------------- 00134 00135 void 00136 plD_init_psm( PLStream *pls ) 00137 { 00138 color = 0; 00139 pls->color = 0; // Not a color device 00140 00141 plParseDrvOpts( ps_options ); 00142 if ( color ) 00143 pls->color = 1; // But user wants color 00144 ps_init( pls ); 00145 } 00146 00147 void 00148 plD_init_psc( PLStream *pls ) 00149 { 00150 color = 1; 00151 pls->color = 1; // Is a color device 00152 plParseDrvOpts( ps_options ); 00153 00154 if ( !color ) 00155 pls->color = 0; // But user does not want color 00156 ps_init( pls ); 00157 } 00158 00159 static void 00160 ps_init( PLStream *pls ) 00161 { 00162 PSDev *dev; 00163 00164 PLFLT pxlx, pxly; 00165 00166 // Set default values - 7.5 x 10 [inches] (72 points = 1 inch) 00167 if ( pls->xlength <= 0 || pls->ylength <= 0 ) 00168 { 00169 pls->xlength = 540; 00170 pls->ylength = 720; 00171 pls->xoffset = 32; 00172 pls->yoffset = 32; 00173 } 00174 if ( pls->xdpi <= 0 ) 00175 pls->xdpi = 72.; 00176 if ( pls->ydpi <= 0 ) 00177 pls->ydpi = 72.; 00178 00179 pxlx = YPSSIZE / LPAGE_X; 00180 pxly = XPSSIZE / LPAGE_Y; 00181 00182 if ( text ) 00183 { 00184 pls->dev_text = 1; // want to draw text 00185 pls->dev_unicode = 1; // want unicode 00186 if ( hrshsym ) 00187 pls->dev_hrshsym = 1; // want Hershey symbols 00188 } 00189 00190 pls->dev_fill0 = 1; // Can do solid fills 00191 00192 // Initialize family file info 00193 00194 plFamInit( pls ); 00195 00196 // Prompt for a file name if not already set 00197 00198 plOpenFile( pls ); 00199 00200 // Allocate and initialize device-specific data 00201 00202 if ( pls->dev != NULL ) 00203 free( (void *) pls->dev ); 00204 00205 pls->dev = calloc( 1, (size_t) sizeof ( PSDev ) ); 00206 if ( pls->dev == NULL ) 00207 plexit( "ps_init: Out of memory." ); 00208 00209 dev = (PSDev *) pls->dev; 00210 00211 dev->xold = PL_UNDEFINED; 00212 dev->yold = PL_UNDEFINED; 00213 00214 plP_setpxl( pxlx, pxly ); 00215 00216 dev->llx = XPSSIZE; 00217 dev->lly = YPSSIZE; 00218 dev->urx = 0; 00219 dev->ury = 0; 00220 dev->ptcnt = 0; 00221 00222 // Rotate by 90 degrees since portrait mode addressing is used 00223 00224 dev->xmin = 0; 00225 dev->ymin = 0; 00226 dev->xmax = PSY; 00227 dev->ymax = PSX; 00228 dev->xlen = dev->xmax - dev->xmin; 00229 dev->ylen = dev->ymax - dev->ymin; 00230 00231 plP_setphy( dev->xmin, dev->xmax, dev->ymin, dev->ymax ); 00232 00233 // If portrait mode is specified, then set up an additional rotation 00234 // transformation with aspect ratio allowed to adjust via freeaspect. 00235 // Default orientation is landscape (ORIENTATION == 3 or 90 deg rotation 00236 // counter-clockwise from portrait). (Legacy PLplot used seascape 00237 // which was equivalent to ORIENTATION == 1 or 90 deg clockwise rotation 00238 // from portrait.) 00239 00240 if ( pls->portrait ) 00241 { 00242 plsdiori( (PLFLT) ( 4 - ORIENTATION ) ); 00243 pls->freeaspect = 1; 00244 } 00245 00246 // Header comments into PostScript file 00247 00248 fprintf( OF, "%%!PS-Adobe-2.0 EPSF-2.0\n" ); 00249 fprintf( OF, "%%%%BoundingBox: \n" ); 00250 fprintf( OF, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" ); 00251 00252 fprintf( OF, "%%%%Title: PLplot Graph\n" ); 00253 fprintf( OF, "%%%%Creator: PLplot Version %s\n", PLPLOT_VERSION ); 00254 fprintf( OF, "%%%%CreationDate: %s\n", ps_getdate() ); 00255 fprintf( OF, "%%%%Pages: (atend)\n" ); 00256 fprintf( OF, "%%%%EndComments\n\n" ); 00257 00258 // Definitions 00259 // Save VM state 00260 00261 fprintf( OF, "/PSSave save def\n" ); 00262 00263 // Define a dictionary and start using it 00264 00265 fprintf( OF, "/PSDict 200 dict def\n" ); 00266 fprintf( OF, "PSDict begin\n" ); 00267 00268 fprintf( OF, "/@restore /restore load def\n" ); 00269 fprintf( OF, "/restore\n" ); 00270 fprintf( OF, " {vmstatus pop\n" ); 00271 fprintf( OF, " dup @VMused lt {pop @VMused} if\n" ); 00272 fprintf( OF, " exch pop exch @restore /@VMused exch def\n" ); 00273 fprintf( OF, " } def\n" ); 00274 fprintf( OF, "/@pri\n" ); 00275 fprintf( OF, " {\n" ); 00276 fprintf( OF, " ( ) print\n" ); 00277 fprintf( OF, " ( ) cvs print\n" ); 00278 fprintf( OF, " } def\n" ); 00279 00280 // n @copies - 00281 00282 fprintf( OF, "/@copies\n" ); 00283 fprintf( OF, " {\n" ); 00284 fprintf( OF, " /#copies exch def\n" ); 00285 fprintf( OF, " } def\n" ); 00286 00287 // - @start - -- start everything 00288 00289 fprintf( OF, "/@start\n" ); 00290 fprintf( OF, " {\n" ); 00291 fprintf( OF, " vmstatus pop /@VMused exch def pop\n" ); 00292 fprintf( OF, " } def\n" ); 00293 00294 // - @end - -- finished 00295 00296 fprintf( OF, "/@end\n" ); 00297 fprintf( OF, " {flush\n" ); 00298 fprintf( OF, " end\n" ); 00299 fprintf( OF, " PSSave restore\n" ); 00300 fprintf( OF, " } def\n" ); 00301 00302 // bop - -- begin a new page 00303 // Only fill background if we are using color and if the bg isn't white 00304 00305 fprintf( OF, "/bop\n" ); 00306 fprintf( OF, " {\n" ); 00307 fprintf( OF, " /SaveImage save def\n" ); 00308 fprintf( OF, " } def\n" ); 00309 00310 // - eop - -- end a page 00311 00312 fprintf( OF, "/eop\n" ); 00313 fprintf( OF, " {\n" ); 00314 fprintf( OF, " showpage\n" ); 00315 fprintf( OF, " SaveImage restore\n" ); 00316 fprintf( OF, " } def\n" ); 00317 00318 // Set line parameters 00319 00320 fprintf( OF, "/@line\n" ); 00321 fprintf( OF, " {0 setlinecap\n" ); 00322 fprintf( OF, " 0 setlinejoin\n" ); 00323 fprintf( OF, " 1 setmiterlimit\n" ); 00324 fprintf( OF, " } def\n" ); 00325 00326 // d @hsize - horizontal clipping dimension 00327 00328 fprintf( OF, "/@hsize {/hs exch def} def\n" ); 00329 fprintf( OF, "/@vsize {/vs exch def} def\n" ); 00330 00331 // d @hoffset - shift for the plots 00332 00333 fprintf( OF, "/@hoffset {/ho exch def} def\n" ); 00334 fprintf( OF, "/@voffset {/vo exch def} def\n" ); 00335 00336 // Set line width 00337 00338 fprintf( OF, "/lw %d def\n", (int) ( 00339 ( pls->width < MIN_WIDTH ) ? DEF_WIDTH : 00340 ( pls->width > MAX_WIDTH ) ? MAX_WIDTH : pls->width ) ); 00341 00342 // Setup user specified offsets, scales, sizes for clipping 00343 00344 fprintf( OF, "/@SetPlot\n" ); 00345 fprintf( OF, " {\n" ); 00346 fprintf( OF, " ho vo translate\n" ); 00347 fprintf( OF, " XScale YScale scale\n" ); 00348 fprintf( OF, " lw setlinewidth\n" ); 00349 fprintf( OF, " } def\n" ); 00350 00351 // Setup x & y scales 00352 00353 fprintf( OF, "/XScale\n" ); 00354 fprintf( OF, " {hs %d div} def\n", YPSSIZE ); 00355 fprintf( OF, "/YScale\n" ); 00356 fprintf( OF, " {vs %d div} def\n", XPSSIZE ); 00357 00358 // Macro definitions of common instructions, to keep output small 00359 00360 fprintf( OF, "/M {moveto} def\n" ); 00361 fprintf( OF, "/D {lineto} def\n" ); 00362 fprintf( OF, "/A {0.5 0 360 arc} def\n" ); 00363 fprintf( OF, "/S {stroke} def\n" ); 00364 fprintf( OF, "/Z {stroke newpath} def\n" ); 00365 // Modify to use fill and stroke for better output with 00366 // anti-aliasing 00367 //fprintf(OF, "/F {fill} def\n"); 00368 if ( pls->dev_eofill ) 00369 fprintf( OF, "/F {closepath gsave eofill grestore stroke} def " ); 00370 else 00371 fprintf( OF, "/F {closepath gsave fill grestore stroke} def " ); 00372 fprintf( OF, "/N {newpath} def" ); 00373 fprintf( OF, "/C {setrgbcolor} def\n" ); 00374 fprintf( OF, "/G {setgray} def\n" ); 00375 fprintf( OF, "/W {setlinewidth} def\n" ); 00376 fprintf( OF, "/SF {selectfont} def\n" ); 00377 fprintf( OF, "/R {rotate} def\n" ); 00378 fprintf( OF, "/SW {stringwidth 2 index mul exch 2 index mul exch rmoveto pop} bind def\n" ); 00379 fprintf( OF, "/B {Z %d %d M %d %d D %d %d D %d %d D %d %d closepath} def\n", 00380 XMIN, YMIN, XMIN, YMAX, XMAX, YMAX, XMAX, YMIN, XMIN, YMIN ); 00381 fprintf( OF, "/CL {newpath M D D D closepath clip} def\n" ); 00382 00383 // End of dictionary definition 00384 00385 fprintf( OF, "end\n\n" ); 00386 00387 // Set up the plots 00388 00389 fprintf( OF, "PSDict begin\n" ); 00390 fprintf( OF, "@start\n" ); 00391 fprintf( OF, "%d @copies\n", COPIES ); 00392 fprintf( OF, "@line\n" ); 00393 fprintf( OF, "%d @hsize\n", YSIZE ); 00394 fprintf( OF, "%d @vsize\n", XSIZE ); 00395 fprintf( OF, "%d @hoffset\n", YOFFSET ); 00396 fprintf( OF, "%d @voffset\n", XOFFSET ); 00397 00398 fprintf( OF, "@SetPlot\n\n" ); 00399 } 00400 00401 //-------------------------------------------------------------------------- 00402 // plD_line_ps() 00403 // 00404 // Draw a line in the current color from (x1,y1) to (x2,y2). 00405 //-------------------------------------------------------------------------- 00406 00407 void 00408 plD_line_ps( PLStream *pls, short x1a, short y1a, short x2a, short y2a ) 00409 { 00410 PSDev *dev = (PSDev *) pls->dev; 00411 PLINT x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a; 00412 00413 // Rotate by 90 degrees 00414 00415 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x1, &y1 ); 00416 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x2, &y2 ); 00417 00418 if ( x1 == dev->xold && y1 == dev->yold && dev->ptcnt < 40 ) 00419 { 00420 if ( pls->linepos + 12 > LINELENGTH ) 00421 { 00422 putc( '\n', OF ); 00423 pls->linepos = 0; 00424 } 00425 else 00426 putc( ' ', OF ); 00427 00428 snprintf( outbuf, OUTBUF_LEN, "%d %d D", x2, y2 ); 00429 dev->ptcnt++; 00430 pls->linepos += 12; 00431 } 00432 else 00433 { 00434 fprintf( OF, " Z\n" ); 00435 pls->linepos = 0; 00436 00437 if ( x1 == x2 && y1 == y2 ) // must be a single dot, draw a circle 00438 snprintf( outbuf, OUTBUF_LEN, "%d %d A", x1, y1 ); 00439 else 00440 snprintf( outbuf, OUTBUF_LEN, "%d %d M %d %d D", x1, y1, x2, y2 ); 00441 dev->llx = MIN( dev->llx, x1 ); 00442 dev->lly = MIN( dev->lly, y1 ); 00443 dev->urx = MAX( dev->urx, x1 ); 00444 dev->ury = MAX( dev->ury, y1 ); 00445 dev->ptcnt = 1; 00446 pls->linepos += 24; 00447 } 00448 dev->llx = MIN( dev->llx, x2 ); 00449 dev->lly = MIN( dev->lly, y2 ); 00450 dev->urx = MAX( dev->urx, x2 ); 00451 dev->ury = MAX( dev->ury, y2 ); 00452 00453 fprintf( OF, "%s", outbuf ); 00454 pls->bytecnt += 1 + (PLINT) strlen( outbuf ); 00455 dev->xold = x2; 00456 dev->yold = y2; 00457 } 00458 00459 //-------------------------------------------------------------------------- 00460 // plD_polyline_ps() 00461 // 00462 // Draw a polyline in the current color. 00463 //-------------------------------------------------------------------------- 00464 00465 void 00466 plD_polyline_ps( PLStream *pls, short *xa, short *ya, PLINT npts ) 00467 { 00468 PLINT i; 00469 00470 for ( i = 0; i < npts - 1; i++ ) 00471 plD_line_ps( pls, xa[i], ya[i], xa[i + 1], ya[i + 1] ); 00472 } 00473 00474 //-------------------------------------------------------------------------- 00475 // plD_eop_ps() 00476 // 00477 // End of page. 00478 //-------------------------------------------------------------------------- 00479 00480 void 00481 plD_eop_ps( PLStream *pls ) 00482 { 00483 fprintf( OF, " S\neop\n" ); 00484 } 00485 00486 //-------------------------------------------------------------------------- 00487 // plD_bop_ps() 00488 // 00489 // Set up for the next page. 00490 // Advance to next family file if necessary (file output). 00491 //-------------------------------------------------------------------------- 00492 00493 void 00494 plD_bop_ps( PLStream *pls ) 00495 { 00496 PSDev *dev = (PSDev *) pls->dev; 00497 00498 dev->xold = PL_UNDEFINED; 00499 dev->yold = PL_UNDEFINED; 00500 00501 if ( !pls->termin ) 00502 plGetFam( pls ); 00503 00504 pls->page++; 00505 00506 if ( pls->family ) 00507 fprintf( OF, "%%%%Page: %d %d\n", (int) pls->page, 1 ); 00508 else 00509 fprintf( OF, "%%%%Page: %d %d\n", (int) pls->page, (int) pls->page ); 00510 00511 fprintf( OF, "bop\n" ); 00512 if ( pls->color ) 00513 { 00514 PLFLT r, g, b; 00515 if ( pls->cmap0[0].r != 0xFF || 00516 pls->cmap0[0].g != 0xFF || 00517 pls->cmap0[0].b != 0xFF ) 00518 { 00519 r = ( (PLFLT) pls->cmap0[0].r ) / 255.; 00520 g = ( (PLFLT) pls->cmap0[0].g ) / 255.; 00521 b = ( (PLFLT) pls->cmap0[0].b ) / 255.; 00522 00523 fprintf( OF, "B %.4f %.4f %.4f C F\n", r, g, b ); 00524 } 00525 } 00526 pls->linepos = 0; 00527 00528 // This ensures the color and line width are set correctly at the beginning of 00529 // each page 00530 00531 plD_state_ps( pls, PLSTATE_COLOR0 ); 00532 plD_state_ps( pls, PLSTATE_WIDTH ); 00533 } 00534 00535 //-------------------------------------------------------------------------- 00536 // plD_tidy_ps() 00537 // 00538 // Close graphics file or otherwise clean up. 00539 //-------------------------------------------------------------------------- 00540 00541 void 00542 plD_tidy_ps( PLStream *pls ) 00543 { 00544 PSDev *dev = (PSDev *) pls->dev; 00545 00546 fprintf( OF, "\n%%%%Trailer\n" ); 00547 00548 dev->llx /= ENLARGE; 00549 dev->lly /= ENLARGE; 00550 dev->urx /= ENLARGE; 00551 dev->ury /= ENLARGE; 00552 dev->llx += XOFFSET; 00553 dev->lly += YOFFSET; 00554 dev->urx += XOFFSET; 00555 dev->ury += YOFFSET; 00556 00557 // changed for correct Bounding boundaries Jan Thorbecke okt 1993 00558 // occurs from the integer truncation -- postscript uses fp arithmetic 00559 00560 dev->urx += 1; 00561 dev->ury += 1; 00562 00563 if ( pls->family ) 00564 fprintf( OF, "%%%%Pages: %d\n", (int) 1 ); 00565 else 00566 fprintf( OF, "%%%%Pages: %d\n", (int) pls->page ); 00567 00568 fprintf( OF, "@end\n" ); 00569 fprintf( OF, "%%%%EOF\n" ); 00570 00571 // Backtrack to write the BoundingBox at the beginning 00572 // Some applications don't like it atend 00573 00574 rewind( OF ); 00575 fprintf( OF, "%%!PS-Adobe-2.0 EPSF-2.0\n" ); 00576 fprintf( OF, "%%%%BoundingBox: %d %d %d %d\n", 00577 dev->llx, dev->lly, dev->urx, dev->ury ); 00578 plCloseFile( pls ); 00579 } 00580 00581 //-------------------------------------------------------------------------- 00582 // plD_state_ps() 00583 // 00584 // Handle change in PLStream state (color, pen width, fill attribute, etc). 00585 //-------------------------------------------------------------------------- 00586 00587 void 00588 plD_state_ps( PLStream *pls, PLINT op ) 00589 { 00590 PSDev *dev = (PSDev *) pls->dev; 00591 00592 switch ( op ) 00593 { 00594 case PLSTATE_WIDTH: { 00595 int width = (int) ( 00596 ( pls->width < MIN_WIDTH ) ? DEF_WIDTH : 00597 ( pls->width > MAX_WIDTH ) ? MAX_WIDTH : pls->width ); 00598 00599 fprintf( OF, " S\n%d W", width ); 00600 00601 dev->xold = PL_UNDEFINED; 00602 dev->yold = PL_UNDEFINED; 00603 break; 00604 } 00605 case PLSTATE_COLOR0: 00606 if ( !pls->color ) 00607 { 00608 fprintf( OF, " S\n%.4f G", ( pls->icol0 ? 0.0 : 1.0 ) ); 00609 break; 00610 } 00611 // else fallthrough 00612 case PLSTATE_COLOR1: 00613 if ( pls->color ) 00614 { 00615 PLFLT r = ( (PLFLT) pls->curcolor.r ) / 255.0; 00616 PLFLT g = ( (PLFLT) pls->curcolor.g ) / 255.0; 00617 PLFLT b = ( (PLFLT) pls->curcolor.b ) / 255.0; 00618 00619 fprintf( OF, " S\n%.4f %.4f %.4f C", r, g, b ); 00620 } 00621 else 00622 { 00623 PLFLT r = ( (PLFLT) pls->curcolor.r ) / 255.0; 00624 fprintf( OF, " S\n%.4f G", 1.0 - r ); 00625 } 00626 break; 00627 } 00628 00629 // Reinitialize current point location. 00630 00631 if ( dev->xold != PL_UNDEFINED && dev->yold != PL_UNDEFINED ) 00632 { 00633 fprintf( OF, " %d %d M \n", (int) dev->xold, (int) dev->yold ); 00634 } 00635 } 00636 00637 //-------------------------------------------------------------------------- 00638 // plD_esc_ps() 00639 // 00640 // Escape function. 00641 //-------------------------------------------------------------------------- 00642 00643 void 00644 plD_esc_ps( PLStream *pls, PLINT op, void *ptr ) 00645 { 00646 switch ( op ) 00647 { 00648 case PLESC_FILL: 00649 fill_polygon( pls ); 00650 break; 00651 case PLESC_HAS_TEXT: 00652 proc_str( pls, (EscText *) ptr ); 00653 break; 00654 } 00655 } 00656 00657 //-------------------------------------------------------------------------- 00658 // fill_polygon() 00659 // 00660 // Fill polygon described in points pls->dev_x[] and pls->dev_y[]. 00661 // Only solid color fill supported. 00662 //-------------------------------------------------------------------------- 00663 00664 static void 00665 fill_polygon( PLStream *pls ) 00666 { 00667 PSDev *dev = (PSDev *) pls->dev; 00668 PLINT n, ix = 0, iy = 0; 00669 PLINT x, y; 00670 00671 fprintf( OF, " Z\n" ); 00672 00673 for ( n = 0; n < pls->dev_npts; n++ ) 00674 { 00675 x = pls->dev_x[ix++]; 00676 y = pls->dev_y[iy++]; 00677 00678 // Rotate by 90 degrees 00679 00680 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x, &y ); 00681 00682 // First time through start with a x y moveto 00683 00684 if ( n == 0 ) 00685 { 00686 snprintf( outbuf, OUTBUF_LEN, "N %d %d M", x, y ); 00687 dev->llx = MIN( dev->llx, x ); 00688 dev->lly = MIN( dev->lly, y ); 00689 dev->urx = MAX( dev->urx, x ); 00690 dev->ury = MAX( dev->ury, y ); 00691 fprintf( OF, "%s", outbuf ); 00692 pls->bytecnt += (PLINT) strlen( outbuf ); 00693 continue; 00694 } 00695 00696 if ( pls->linepos + 21 > LINELENGTH ) 00697 { 00698 putc( '\n', OF ); 00699 pls->linepos = 0; 00700 } 00701 else 00702 putc( ' ', OF ); 00703 00704 pls->bytecnt++; 00705 00706 snprintf( outbuf, OUTBUF_LEN, "%d %d D", x, y ); 00707 dev->llx = MIN( dev->llx, x ); 00708 dev->lly = MIN( dev->lly, y ); 00709 dev->urx = MAX( dev->urx, x ); 00710 dev->ury = MAX( dev->ury, y ); 00711 00712 fprintf( OF, "%s", outbuf ); 00713 pls->bytecnt += (PLINT) strlen( outbuf ); 00714 pls->linepos += 21; 00715 } 00716 dev->xold = PL_UNDEFINED; 00717 dev->yold = PL_UNDEFINED; 00718 fprintf( OF, " F " ); 00719 } 00720 00721 //-------------------------------------------------------------------------- 00722 // ps_getdate() 00723 // 00724 // Get the date and time 00725 //-------------------------------------------------------------------------- 00726 00727 static char * 00728 ps_getdate( void ) 00729 { 00730 int len; 00731 time_t t; 00732 char *p; 00733 00734 t = time( (time_t *) 0 ); 00735 p = ctime( &t ); 00736 len = (int) strlen( p ); 00737 *( p + len - 1 ) = '\0'; // zap the newline character 00738 return p; 00739 } 00740 00741 00742 // 0.8 should mimic the offset of first superscript/subscript level 00743 // implemented in plstr (plsym.c) for Hershey fonts. However, when 00744 // comparing with -dev xwin and -dev xcairo results changing this 00745 // factor to 0.6 appears to offset the centers of the letters 00746 // appropriately while 0.8 gives much poorer agreement with the 00747 // other devices. 00748 # define RISE_FACTOR 0.6 00749 00750 //-------------------------------------------------------------------------- 00751 // proc_str() 00752 // 00753 // Prints postscript strings. 00754 // N.B. Now unicode only, no string access! 00755 // 00756 //-------------------------------------------------------------------------- 00757 00758 void 00759 proc_str( PLStream *pls, EscText *args ) 00760 { 00761 PLFLT *t = args->xform, tt[4]; // Transform matrices 00762 PLFLT theta, shear, stride; // Rotation angle and shear from the matrix 00763 PLFLT ft_ht, offset; // Font height and offset 00764 PLFLT cs, sn, l1, l2; 00765 PSDev *dev = (PSDev *) pls->dev; 00766 const char *font; 00767 char esc; 00768 // Be generous. Used to store lots of font changes which take 00769 // 3 characters per change. 00770 #define PROC_STR_STRING_LENGTH 1000 00771 unsigned char *strp, str[PROC_STR_STRING_LENGTH], *cur_strp, 00772 cur_str[PROC_STR_STRING_LENGTH]; 00773 float font_factor = 1.4f; 00774 PLINT clxmin, clxmax, clymin, clymax; // Clip limits 00775 PLINT clipx[4], clipy[4]; // Current clip limits 00776 00777 PLFLT scale = 1., up = 0.; // Font scaling and shifting parameters 00778 00779 int i = 0; // String index 00780 00781 // unicode only! so test for it. 00782 if ( args->unicode_array_len > 0 ) 00783 { 00784 int j, s, f; 00785 const char *fonts[PROC_STR_STRING_LENGTH]; 00786 const PLUNICODE *cur_text; 00787 PLUNICODE fci, fci_save; 00788 PLFLT old_sscale, sscale, old_soffset, soffset, ddup; 00789 PLINT level = 0; 00790 // translate from unicode into type 1 font index. 00791 // 00792 // Choose the font family, style, variant, and weight using 00793 // the FCI (font characterization integer). 00794 // 00795 00796 plgesc( &esc ); 00797 plgfci( &fci ); 00798 fci_save = fci; 00799 font = get_font( dev, fci ); 00800 cur_text = args->unicode_array; 00801 for ( f = s = j = 0; j < args->unicode_array_len; j++ ) 00802 { 00803 if ( cur_text[j] & PL_FCI_MARK ) 00804 { 00805 // process an FCI by saving it and escaping cur_str 00806 // with an escff to make it a 2-character escape 00807 // that is not used in legacy Hershey code 00808 // 00809 if ( ( f < PROC_STR_STRING_LENGTH ) && ( s + 3 < PROC_STR_STRING_LENGTH ) ) 00810 { 00811 fci_save = cur_text[j]; 00812 fonts[f++] = get_font( dev, fci_save ); 00813 cur_str[s++] = (unsigned char) esc; 00814 cur_str[s++] = 'f'; 00815 cur_str[s++] = 'f'; 00816 } 00817 } 00818 else if ( s + 4 < PROC_STR_STRING_LENGTH ) 00819 { 00820 #undef PL_TEST_TYPE1 00821 #ifdef PL_TEST_TYPE1 00822 // Use this test case only to conveniently view Type1 font 00823 // possibilities (as in test_type1.py example). 00824 // This functionality is useless other than for this test case. 00825 PLINT ifamily, istyle, iweight; 00826 plgfont( &ifamily, &istyle, &iweight ); 00827 if ( 0 <= cur_text[j] && cur_text[j] < 256 ) 00828 cur_str[s++] = cur_text[j]; 00829 else 00830 cur_str[s++] = 32; 00831 // Overwrite font just for this special case. 00832 if ( ifamily == PL_FCI_SYMBOL ) 00833 font = get_font( dev, 0 ); 00834 else 00835 font = get_font( dev, fci ); 00836 #else 00837 cur_str[s] = plunicode2type1( cur_text[j], dev->lookup, dev->nlookup ); 00838 if ( cur_text[j] != ' ' && cur_str[s] == ' ' ) 00839 { 00840 // failed lookup. 00841 if ( !dev->if_symbol_font ) 00842 { 00843 // failed standard font lookup. Use symbol 00844 // font instead which will return a blank if 00845 // that fails as well. 00846 fonts[f++] = get_font( dev, 0 ); 00847 cur_str[s++] = (unsigned char) esc; 00848 cur_str[s++] = 'f'; 00849 cur_str[s++] = 'f'; 00850 cur_str[s++] = plunicode2type1( cur_text[j], dev->lookup, dev->nlookup ); 00851 } 00852 else 00853 { 00854 // failed symbol font lookup. Use last standard 00855 // font instead which will return a blank if 00856 // that fails as well. 00857 fonts[f++] = get_font( dev, fci_save ); 00858 cur_str[s++] = (unsigned char) esc; 00859 cur_str[s++] = 'f'; 00860 cur_str[s++] = 'f'; 00861 cur_str[s++] = plunicode2type1( cur_text[j], dev->lookup, dev->nlookup ); 00862 } 00863 } 00864 else 00865 { 00866 // lookup succeeded. 00867 s++; 00868 } 00869 #endif 00870 pldebug( "proc_str", "unicode = 0x%x, type 1 code = %d\n", 00871 cur_text[j], cur_str[s - 1] ); 00872 } 00873 } 00874 cur_str[s] = '\0'; 00875 00876 // finish previous polyline 00877 00878 dev->xold = PL_UNDEFINED; 00879 dev->yold = PL_UNDEFINED; 00880 00881 // Determine the font height 00882 ft_ht = pls->chrht * 72.0 / 25.4; // ft_ht in points, ht is in mm 00883 00884 00885 // The transform matrix has only rotations and shears; extract them 00886 plRotationShear( t, &theta, &shear, &stride ); 00887 cs = cos( theta ); 00888 sn = sin( theta ); 00889 tt[0] = t[0] * cs + t[2] * sn; 00890 tt[1] = t[1] * cs + t[3] * sn; 00891 tt[2] = -t[0] * sn + t[2] * cs; 00892 tt[3] = -t[1] * sn + t[3] * cs; 00893 00894 // 00895 // Reference point conventions: 00896 // If base = 0, it is aligned with the center of the text box 00897 // If base = 1, it is aligned with the baseline of the text box 00898 // If base = 2, it is aligned with the top of the text box 00899 // 00900 // Currently plplot only uses base=0 00901 // Postscript uses base=1 00902 // 00903 // We must calculate the difference between the two and apply the offset. 00904 // 00905 00906 if ( args->base == 2 ) // not supported by plplot 00907 offset = ENLARGE * ft_ht / 2.; // half font height 00908 else if ( args->base == 1 ) 00909 offset = 0.; 00910 else 00911 offset = -ENLARGE * ft_ht / 2.; 00912 00913 // Determine the adjustment for page orientation 00914 theta -= PI / 2. * pls->diorot; 00915 args->y += (PLINT) ( offset * cos( theta ) ); 00916 args->x -= (PLINT) ( offset * sin( theta ) ); 00917 00918 // ps driver is rotated by default 00919 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, 00920 &( args->x ), &( args->y ) ); 00921 00922 // Correct for the fact ps driver uses landscape by default 00923 theta += PI / 2.; 00924 00925 // Output 00926 // Set clipping 00927 clipx[0] = pls->clpxmi; 00928 clipx[2] = pls->clpxma; 00929 clipy[0] = pls->clpymi; 00930 clipy[2] = pls->clpyma; 00931 clipx[1] = clipx[2]; 00932 clipy[1] = clipy[0]; 00933 clipx[3] = clipx[0]; 00934 clipy[3] = clipy[2]; 00935 difilt( clipx, clipy, 4, &clxmin, &clxmax, &clymin, &clymax ); 00936 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, 00937 &clipx[0], &clipy[0] ); 00938 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, 00939 &clipx[1], &clipy[1] ); 00940 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, 00941 &clipx[2], &clipy[2] ); 00942 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, 00943 &clipx[3], &clipy[3] ); 00944 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] ); 00945 00946 // move to string reference point 00947 fprintf( OF, " %d %d M\n", args->x, args->y ); 00948 00949 // Save the current position and set the string rotation 00950 fprintf( OF, "gsave %.3f R\n", TRMFLT( theta * 180. / PI ) ); 00951 00952 // Purge escape sequences from string, so that postscript can find it's 00953 // length. The string length is computed with the current font, and can 00954 // thus be wrong if there are font change escape sequences in the string 00955 // 00956 00957 esc_purge( str, cur_str ); 00958 00959 fprintf( OF, "/%s %.3f SF\n", font, TRMFLT( font_factor * ENLARGE * ft_ht ) ); 00960 00961 // Output string, while escaping the '(', ')' and '\' characters. 00962 // this string is output for measurement purposes only. 00963 // 00964 fprintf( OF, "%.3f (", TRMFLT( -args->just ) ); 00965 while ( str[i] != '\0' ) 00966 { 00967 if ( str[i] == '(' || str[i] == ')' || str[i] == '\\' ) 00968 fprintf( OF, "\\%c", str[i] ); 00969 else 00970 fprintf( OF, "%c", str[i] ); 00971 i++; 00972 } 00973 fprintf( OF, ") SW\n" ); 00974 00975 00976 // Parse string for PLplot escape sequences and print everything out 00977 00978 cur_strp = cur_str; 00979 f = 0; 00980 do 00981 { 00982 strp = str; 00983 00984 if ( *cur_strp == esc ) 00985 { 00986 cur_strp++; 00987 00988 if ( *cur_strp == esc ) // <esc><esc> 00989 { 00990 *strp++ = *cur_strp++; 00991 } 00992 else if ( *cur_strp == 'f' ) 00993 { 00994 cur_strp++; 00995 if ( *cur_strp++ != 'f' ) 00996 { 00997 // escff occurs because of logic above. But any suffix 00998 // other than "f" should never happen. 00999 plabort( "proc_str, internal PLplot logic error;" 01000 "wrong escf escape sequence" ); 01001 return; 01002 } 01003 font = fonts[f++]; 01004 pldebug( "proc_str", "string-specified fci = 0x%x, font name = %s\n", fci, font ); 01005 continue; 01006 } 01007 else 01008 switch ( *cur_strp++ ) 01009 { 01010 case 'd': //subscript 01011 case 'D': 01012 plP_script_scale( FALSE, &level, 01013 &old_sscale, &sscale, &old_soffset, &soffset ); 01014 scale = sscale; 01015 // The correction for the difference in magnitude 01016 // between the baseline and middle coordinate systems 01017 // for subscripts should be 01018 // -0.5*(base font size - superscript/subscript font size). 01019 ddup = -0.5 * ( 1.0 - sscale ); 01020 up = -font_factor * ENLARGE * ft_ht * ( RISE_FACTOR * soffset + ddup ); 01021 break; 01022 01023 case 'u': //superscript 01024 case 'U': 01025 plP_script_scale( TRUE, &level, 01026 &old_sscale, &sscale, &old_soffset, &soffset ); 01027 scale = sscale; 01028 // The correction for the difference in magnitude 01029 // between the baseline and middle coordinate systems 01030 // for superscripts should be 01031 // 0.5*(base font size - superscript/subscript font size). 01032 ddup = 0.5 * ( 1.0 - sscale ); 01033 up = font_factor * ENLARGE * ft_ht * ( RISE_FACTOR * soffset + ddup ); 01034 break; 01035 01036 // ignore the next sequences 01037 01038 case '+': 01039 case '-': 01040 case 'b': 01041 case 'B': 01042 plwarn( "'+', '-', and 'b/B' text escape sequences not processed." ); 01043 break; 01044 } 01045 } 01046 01047 // copy from current to next token, adding a postscript escape 01048 // char '\' if necessary 01049 // 01050 while ( *cur_strp && *cur_strp != esc ) 01051 { 01052 if ( *cur_strp == '(' || *cur_strp == ')' || *cur_strp == '\\' ) 01053 *strp++ = '\\'; 01054 *strp++ = *cur_strp++; 01055 } 01056 *strp = '\0'; 01057 01058 if ( fabs( up ) < 0.001 ) 01059 up = 0.; // Watch out for small differences 01060 01061 // Apply the scaling and the shear 01062 fprintf( OF, "/%s [%.3f %.3f %.3f %.3f 0 0] SF\n", 01063 font, 01064 TRMFLT( tt[0] * font_factor * ENLARGE * ft_ht * scale ), 01065 TRMFLT( tt[2] * font_factor * ENLARGE * ft_ht * scale ), 01066 TRMFLT( tt[1] * font_factor * ENLARGE * ft_ht * scale ), 01067 TRMFLT( tt[3] * font_factor * ENLARGE * ft_ht * scale ) ); 01068 01069 // if up/down escape sequences, save current point and adjust baseline; 01070 // take the shear into account 01071 if ( up != 0. ) 01072 fprintf( OF, "gsave %.3f %.3f rmoveto\n", TRMFLT( up * tt[1] ), TRMFLT( up * tt[3] ) ); 01073 01074 // print the string 01075 fprintf( OF, "(%s) show\n", str ); 01076 01077 // back to baseline 01078 if ( up != 0. ) 01079 fprintf( OF, "grestore (%s) stringwidth rmoveto\n", str ); 01080 } while ( *cur_strp ); 01081 01082 fprintf( OF, "grestore\n" ); 01083 fprintf( OF, "grestore\n" ); 01084 01085 // 01086 // keep driver happy -- needed for background and orientation. 01087 // arghhh! can't calculate it, as I only have the string reference 01088 // point, not its extent! 01089 // Still a hack - but at least it takes into account the string 01090 // length and justification. Character width is assumed to be 01091 // 0.6 * character height. Add on an extra 1.5 * character height 01092 // for safety. 01093 // 01094 cs = cos( theta ); 01095 sn = sin( theta ); 01096 l1 = -i * args->just; 01097 l2 = i * ( 1. - args->just ); 01098 // Factor of 0.6 is an empirical fudge to convert character 01099 // height to average character width 01100 l1 *= 0.6; 01101 l2 *= 0.6; 01102 01103 dev->llx = (int) ( MIN( dev->llx, args->x + ( MIN( l1 * cs, l2 * cs ) - 1.5 ) * font_factor * ft_ht * ENLARGE ) ); 01104 dev->lly = (int) ( MIN( dev->lly, args->y + ( MIN( l1 * sn, l2 * sn ) - 1.5 ) * font_factor * ft_ht * ENLARGE ) ); 01105 dev->urx = (int) ( MAX( dev->urx, args->x + ( MAX( l1 * cs, l2 * cs ) + 1.5 ) * font_factor * ft_ht * ENLARGE ) ); 01106 dev->ury = (int) ( MAX( dev->ury, args->y + ( MAX( l1 * sn, l2 * sn ) + 1.5 ) * font_factor * ft_ht * ENLARGE ) ); 01107 } 01108 } 01109 01110 static void 01111 esc_purge( unsigned char *dstr, unsigned char *sstr ) 01112 { 01113 char esc; 01114 01115 plgesc( &esc ); 01116 01117 while ( *sstr ) 01118 { 01119 if ( *sstr != esc ) 01120 { 01121 *dstr++ = *sstr++; 01122 continue; 01123 } 01124 01125 sstr++; 01126 if ( *sstr == esc ) 01127 { 01128 *dstr++ = *sstr++; 01129 continue; 01130 } 01131 01132 else 01133 { 01134 switch ( *sstr++ ) 01135 { 01136 case 'f': 01137 sstr++; 01138 break; // two chars sequence 01139 01140 default: 01141 break; // single char escape 01142 } 01143 } 01144 } 01145 *dstr = '\0'; 01146 } 01147 01148 //-------------------------------------------------------------------------- 01149 // unsigned char plunicode2type1 (const PLUNICODE index, 01150 // const Unicode_to_Type1_table lookup[], const int number_of_entries) 01151 // 01152 // Function takes an input unicode index, looks through the lookup 01153 // table (which must be sorted by PLUNICODE Unicode), then returns the 01154 // corresponding Type1 code in the lookup table. If the Unicode index is 01155 // not present the returned value is 32 (which is normally a blank 01156 // for Type 1 fonts). 01157 //-------------------------------------------------------------------------- 01158 01159 static unsigned char 01160 plunicode2type1( const PLUNICODE index, 01161 const Unicode_to_Type1_table lookup[], 01162 const int nlookup ) 01163 { 01164 int jlo = -1, jmid, jhi = nlookup; 01165 while ( jhi - jlo > 1 ) 01166 { 01167 // Note that although jlo or jhi can be just outside valid 01168 // range (see initialization above) because of while condition 01169 // jlo < jmid < jhi and jmid must be in valid range. 01170 // 01171 jmid = ( jlo + jhi ) / 2; 01172 if ( index > lookup[jmid].Unicode ) 01173 jlo = jmid; 01174 else if ( index < lookup[jmid].Unicode ) 01175 jhi = jmid; 01176 else 01177 // We have found it! 01178 // index == lookup[jmid].Unicode 01179 // 01180 return ( lookup[jmid].Type1 ); 01181 } 01182 // jlo is invalid or it is valid and index > lookup[jlo].Unicode. 01183 // jhi is invalid or it is valid and index < lookup[jhi].Unicode. 01184 // All these conditions together imply index cannot be found in lookup. 01185 // Mark with ' ' (which is normally the index for blank in type 1 fonts). 01186 // 01187 return ( ' ' ); 01188 } 01189 01190 //-------------------------------------------------------------------------- 01191 // get_font( PSDev* dev, PLUNICODE fci ) 01192 // 01193 // Sets the Type1 font. 01194 //-------------------------------------------------------------------------- 01195 static const char * 01196 get_font( PSDev* dev, PLUNICODE fci ) 01197 { 01198 const char *font; 01199 // fci = 0 is a special value indicating the Type 1 Symbol font 01200 // is desired. This value cannot be confused with a normal FCI value 01201 // because it doesn't have the PL_FCI_MARK. 01202 if ( fci == 0 ) 01203 { 01204 font = "Symbol"; 01205 dev->nlookup = number_of_entries_in_unicode_to_symbol_table; 01206 dev->lookup = unicode_to_symbol_lookup_table; 01207 dev->if_symbol_font = 1; 01208 } 01209 else 01210 { 01211 // convert the fci to Base14/Type1 font information 01212 font = plP_FCI2FontName( fci, Type1Lookup, N_Type1Lookup ); 01213 dev->nlookup = number_of_entries_in_unicode_to_standard_table; 01214 dev->lookup = unicode_to_standard_lookup_table; 01215 dev->if_symbol_font = 0; 01216 } 01217 pldebug( "set_font", "fci = 0x%x, font name = %s\n", fci, font ); 01218 return ( font ); 01219 } 01220 01221 #else 01222 int 01223 pldummy_ps() 01224 { 01225 return 0; 01226 } 01227 01228 #endif // PLD_ps