• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

ps.c

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

Generated on Wed Oct 12 2011 20:42:23 for PLplot by  doxygen 1.7.1