PLplot  5.10.0
ps.c
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines