--- /dev/null
+/* Hello, Emacs: this is -*-C-*- !
+ * $Id: post.trm,v 1.203.2.17 2009/03/02 17:40:06 mikulik Exp $
+ */
+
+/* GNUPLOT - post.trm */
+
+/*[
+ * Copyright 1990 - 1993, 1998, 1999, 2000, 2001, 2004
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the complete modified source code. Modifications are to
+ * be distributed as patches to the released version. Permission to
+ * distribute binaries produced by compiling modified sources is granted,
+ * provided you
+ * 1. distribute the corresponding source modifications from the
+ * released version in the form of a patch file along with the binaries,
+ * 2. add special version identification to distinguish your version
+ * in addition to the base release version number,
+ * 3. provide your name and address as the primary contact for the
+ * support of your modified version, and
+ * 4. retain our contact information in regard to use of the base
+ * software.
+ * Permission to distribute the released version of the source code along
+ * with corresponding source modifications in the form of a patch file is
+ * granted with same provisions 2 through 4 for binary distributions.
+ *
+ * This software is provided "as is" without express or implied warranty
+ * to the extent permitted by applicable law.
+]*/
+
+/*
+ * This terminal driver supports:
+ * postscript
+ *
+ * AUTHORS
+ * Russell Lang <rjl@monu1.cc.monash.edu.au>
+ *
+ * modified 10/5/95 by drd - put in support for other postscript drivers
+ * (enhpost, pslatex, ...) so they dont have to work quite so hard
+ *
+ * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
+ *
+ * The 'postscript' driver produces landscape output 10" wide and 7" high.
+ * To change font to Times-Roman and font size to 20pts use
+ * 'set term postscript "Times-Roman" 20'.
+ * To get a smaller (5" x 3.5") eps output use 'set term post eps'
+ * and make only one plot per file. Font size for eps will be half
+ * the specified size.
+ *
+ * Erik Luijten 30/5/97: added %%CreationDate, made %%DocumentFonts conform
+ * to DSC, added version no. and patchl. to %%Creator
+ * Petr Mikulik, Jan 1999: terminal entries for PM3D functionality
+ *
+ * Dick Crawford 24/5/00: added 'a{}{}' syntax to allow for overprinting
+ *
+ * Dan Sebald, 7 March 2003: terminal entry for image functionality
+ *
+ * Harald Harders (h.harders@tu-bs.de), 2004-12-02:
+ * Moved all terminal settings into a single structure.
+ *
+ * Harald Harders (h.harders@tu-bs.de), 2005-02-08:
+ * Merged functionality of postscript, pslatex, pstex, and epslatex terminals.
+ *
+ * Ethan Merritt Mar 2006: Break out prolog and character encodings into
+ * separate files loaded at runtime
+ */
+
+#include "driver.h"
+
+#ifdef TERM_PROTO
+#include "variable.h" /* For loadpath_handler used in PS_dump_prologue_file */
+#endif
+
+#ifdef TERM_REGISTER
+register_term(post)
+#endif
+
+#ifdef TERM_PROTO
+TERM_PUBLIC void PS_options __PROTO((void));
+TERM_PUBLIC void PS_common_init __PROTO((TBOOLEAN uses_fonts, unsigned int xoff, unsigned int yoff, unsigned int bb_xmin, unsigned int bb_ymin, unsigned int bb_xmax, unsigned int bb_ymax, const char **dict));
+TERM_PUBLIC void PS_init __PROTO((void));
+TERM_PUBLIC void PS_graphics __PROTO((void));
+TERM_PUBLIC void PS_text __PROTO((void));
+TERM_PUBLIC void PS_reset __PROTO((void));
+TERM_PUBLIC void PS_linetype __PROTO((int linetype));
+TERM_PUBLIC void PS_move __PROTO((unsigned int x, unsigned int y));
+TERM_PUBLIC void PS_vector __PROTO((unsigned int x, unsigned int y));
+TERM_PUBLIC void PS_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
+TERM_PUBLIC int PS_text_angle __PROTO((int ang));
+TERM_PUBLIC int PS_justify_text __PROTO((enum JUSTIFY mode));
+TERM_PUBLIC void PS_point __PROTO((unsigned int x, unsigned int y, int number));
+TERM_PUBLIC void PS_arrow __PROTO(( unsigned int sx, unsigned int sy,
+ unsigned int ex, unsigned int ey, int head));
+TERM_PUBLIC int PS_set_font __PROTO((const char * font));
+TERM_PUBLIC void PS_fillbox __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height));
+TERM_PUBLIC void PS_linewidth __PROTO((double linewidth)); /* JFi [linewidth] */
+TERM_PUBLIC void PS_pointsize __PROTO((double ptsize)); /* JFi [pointsize] */
+TERM_PUBLIC int PS_make_palette (t_sm_palette *);
+TERM_PUBLIC void PS_previous_palette (void);
+TERM_PUBLIC void PS_set_color (t_colorspec *);
+TERM_PUBLIC void PS_filled_polygon (int, gpiPoint *);
+#ifdef WITH_IMAGE
+TERM_PUBLIC void PS_image __PROTO((unsigned, unsigned, coordval *, gpiPoint *, t_imagecolor));
+#endif
+
+/* To support "set term post enhanced" */
+TERM_PUBLIC void ENHPS_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
+TERM_PUBLIC int ENHPS_set_font __PROTO((const char * font));
+TERM_PUBLIC void ENHPS_OPEN __PROTO((char * fontname, double fontsize,
+ double base, TBOOLEAN widthflag, TBOOLEAN showflag,
+ int overprint));
+TERM_PUBLIC void ENHPS_FLUSH __PROTO((void));
+TERM_PUBLIC void ENHPS_WRITEC __PROTO((int c));
+TERM_PUBLIC char *PS_RememberFont __PROTO((char *fname, int reencode));
+
+TERM_PUBLIC char *PS_escape_string __PROTO((char *origstr, char *escapelist));
+
+TERM_PUBLIC void PS_path __PROTO((int p));
+static TBOOLEAN PS_newpath = FALSE;
+
+#endif /* TERM_PROTO */
+
+#ifndef TERM_PROTO_ONLY
+
+#ifdef TERM_BODY
+
+#include "post.h"
+
+#define PS_FLUSH_PATH do { \
+ if (ps_path_count) { \
+ fputs("stroke\n", gppsfile); \
+ ps_path_count = 0; \
+ PS_relative_ok = FALSE; \
+ } \
+} while (0)
+
+/* Datastructure implementing inclusion of font files */
+struct ps_fontfile_def {
+ struct ps_fontfile_def *next;/* pointer to next fontfile in linked list */
+ char *fontfile_name;
+ char *fontfile_fullname;
+};
+
+/* Terminal type of postscript dialect */
+enum PS_TERMINALTYPE {
+ PSTERM_PSTEX, PSTERM_PSLATEX, PSTERM_EPSLATEX, PSTERM_POSTSCRIPT
+};
+
+enum PS_PSFORMAT {
+ PSTERM_EPS, PSTERM_PORTRAIT, PSTERM_LANDSCAPE
+};
+
+/* One struct that takes all terminal parameters
+ * by Harald Harders <h.harders@tu-bs.de> */
+typedef struct ps_params_t {
+ enum PS_TERMINALTYPE terminal;
+ int xoff;
+ int yoff;
+ enum PS_PSFORMAT psformat;
+ TBOOLEAN level1;
+ TBOOLEAN color;
+ TBOOLEAN blacktext;
+ TBOOLEAN solid;
+ float dash_length;
+ float linewidth_factor;
+ TBOOLEAN duplex_option; /* one of duplex or simplex specified? */
+ TBOOLEAN duplex_state;
+ TBOOLEAN rounded; /* rounded linecaps and linejoins */
+ struct ps_fontfile_def *first_fontfile;
+ char font[MAX_ID_LEN+1]; /* name of font */
+ float fontsize; /* size of font in pts */
+ TBOOLEAN useauxfile; /* only necessary for ps(la)tex */
+ TBOOLEAN rotate; /* only necessary for ps(la)tex */
+ int palfunc_samples; /* setable via "palf$uncparam" */
+ double palfunc_deviation; /* terminal option */
+ TBOOLEAN oldstyle;
+ TBOOLEAN epslatex_standalone;
+} ps_params_t;
+
+#define POST_PARAMS_DEFAULT { \
+ PSTERM_POSTSCRIPT, 50, 50, \
+ PSTERM_LANDSCAPE, FALSE, FALSE, FALSE, FALSE, 1.0, 1.0, FALSE, \
+ FALSE, FALSE, NULL, "Helvetica", 14, FALSE, FALSE, 2000, 0.003, \
+ FALSE, FALSE \
+}
+
+static ps_params_t post_params = POST_PARAMS_DEFAULT;
+static const ps_params_t post_params_default = POST_PARAMS_DEFAULT;
+
+#define EPSLATEX_PARAMS_DEFAULT { \
+ PSTERM_EPSLATEX, 50, 50, \
+ PSTERM_EPS, FALSE, FALSE, TRUE, FALSE, 1.0, 1.0, FALSE, \
+ FALSE, FALSE, NULL, "", 11, TRUE, FALSE, 2000, 0.003, \
+ FALSE, FALSE \
+}
+static ps_params_t epslatex_params = EPSLATEX_PARAMS_DEFAULT;
+static const ps_params_t epslatex_params_default = EPSLATEX_PARAMS_DEFAULT;
+
+#define PSLATEX_PARAMS_DEFAULT { \
+ PSTERM_PSLATEX, 0, 0, \
+ PSTERM_EPS, FALSE, FALSE, TRUE, FALSE, 1.0, 1.0, FALSE, \
+ FALSE, FALSE, NULL, "", 0, FALSE, TRUE, 2000, 0.003, \
+ FALSE, FALSE \
+}
+static ps_params_t pslatex_params = PSLATEX_PARAMS_DEFAULT;
+static const ps_params_t pslatex_params_default = PSLATEX_PARAMS_DEFAULT;
+
+#define PSTEX_PARAMS_DEFAULT { \
+ PSTERM_PSTEX, 0, 0, \
+ PSTERM_EPS, FALSE, FALSE, TRUE, FALSE, 1.0, 1.0, FALSE, \
+ FALSE, FALSE, NULL, "", 0, FALSE, TRUE, 2000, 0.003, \
+ FALSE, FALSE \
+}
+static ps_params_t pstex_params = PSTEX_PARAMS_DEFAULT;
+static const ps_params_t pstex_params_default = PSTEX_PARAMS_DEFAULT;
+
+static ps_params_t *ps_params = &post_params;
+
+static void make_interpolation_code __PROTO((void));
+static void make_color_model_code __PROTO((void));
+static char * save_space __PROTO((double gray));
+static void write_component_array __PROTO((const char *text, gradient_struct *grad, int cnt, int offset));
+static void write_gradient_definition __PROTO((gradient_struct *gradient, int cnt));
+static void write_color_space __PROTO((t_sm_palette *palette));
+static void make_palette_formulae __PROTO((void));
+static void PS_make_header __PROTO((t_sm_palette *palette));
+
+static float ps_fontsize;
+
+/* for enhanced mode, we keep a separate font name and size, which
+ * is restored to the default value on font of ""
+ */
+static char ps_enh_font[MAX_ID_LEN+1];
+static float ps_enh_fontsize;
+static int ENHPS_initialized;
+
+static int ps_page = 0; /* page count */
+static int ps_path_count = 0; /* count of lines in path */
+static int ps_ang = 0; /* text angle */
+static enum JUSTIFY ps_justify = LEFT; /* text is flush left */
+
+static void delete_ps_fontfile __PROTO((struct ps_fontfile_def *, struct ps_fontfile_def *));
+
+TERM_PUBLIC void PS_load_fontfile __PROTO((struct ps_fontfile_def *,TBOOLEAN));
+TERM_PUBLIC void PS_load_fontfiles __PROTO((TBOOLEAN));
+
+static TBOOLEAN ps_explicit_size = FALSE;
+static size_units ps_explicit_units = INCHES;
+static int eps_explicit_x = 0;
+static int eps_explicit_y = 0;
+
+#define DOTS_PER_INCH (300) /* resolution of printer we expect to use */
+
+/* name of auxiliary file */
+static char *pslatex_auxname = NULL;
+
+/* Routine to copy pre-existing prolog files into output stream */
+static void PS_dump_prologue_file __PROTO((char *));
+
+static const char GPFAR * GPFAR OldEPSL_linetypes[] = {
+/* Line Types */
+"% Redefine line types to match old epslatex driver\n",
+"/LTw { PL [] 1 setgray } def\n", /* background (assumed white) */
+"/LTb { BL [] 0 0 0 DL } def\n", /* border */
+"/LTa { AL [1 udl mul 2 udl mul] 0 setdash 0 0 0 setrgbcolor } def\n", /* axes */
+"/LT0 { PL [] 1 0 0 DL } def\n",
+"/LT1 { PL [8 dl1 5 dl1] 0 0 1 DL } def\n",
+"/LT2 { PL [4 dl1 4 dl1] 0 1 1 DL } def\n",
+"/LT3 { PL [8 dl1 5 dl1 0.5 dl1 5 dl1] 1 0 1 DL } def\n",
+NULL
+};
+
+static const char GPFAR * GPFAR ENHPS_header[] = {
+/* For MFshow and MFwidth the tos is an array with the string and font info: */
+/* [<fontname (a string)> <fontsize> <vertical offset> <width significant?> <printed?> <overprint> <text string>] */
+/* EAM Mar 2004 - Add in a special case overprint 3 = save, overprint 4 = restore */
+
+"/MFshow {\n",
+" { dup 5 get 3 ge\n", /* EAM test for overprint 3 or 4 */
+" { 5 get 3 eq {gsave} {grestore} ifelse }\n", /* EAM */
+" {dup dup 0 get findfont exch 1 get scalefont setfont\n",
+" [ currentpoint ] exch dup 2 get 0 exch R dup 5 get 2 ne {dup dup 6\n",
+" get exch 4 get {show} {stringwidth pop 0 R} ifelse }if dup 5 get 0 eq\n",
+" {dup 3 get {2 get neg 0 exch R pop} {pop aload pop M} ifelse} {dup 5\n",
+" get 1 eq {dup 2 get exch dup 3 get exch 6 get stringwidth pop -2 div\n",
+" dup 0 R} {dup 6 get stringwidth pop -2 div 0 R 6 get\n",
+" show 2 index {aload pop M neg 3 -1 roll neg R pop pop} {pop pop pop\n",
+" pop aload pop M} ifelse }ifelse }ifelse }\n",
+" ifelse }\n", /* EAM */
+" forall} bind def\n",
+
+/* get the width of the text */
+/* HH 2005-07-24 - Add in a special case overprint 3 = save, 4 = restore
+ * also for estimation of string width. This is done by interposing an
+ * additional value on the stack. between XYsave and XYrestore,
+ * this number is increased by the strings. By pop'ing this number, all
+ * strings between XYsave and XYrestore are ignored. */
+"/MFwidth {0 exch { dup 5 get 3 ge { 5 get 3 eq { 0 } { pop } ifelse }\n",
+" {dup 3 get{dup dup 0 get findfont exch 1 get scalefont setfont\n",
+" 6 get stringwidth pop add} {pop} ifelse} ifelse} forall} bind def\n",
+
+/* flush left show */
+"/MLshow { currentpoint stroke M\n",
+" 0 exch R\n Blacktext {gsave 0 setgray MFshow grestore} {MFshow} ifelse } bind def\n",
+
+/* flush right show */
+"/MRshow { currentpoint stroke M\n",
+" exch dup MFwidth neg 3 -1 roll R\n Blacktext {gsave 0 setgray MFshow grestore} {MFshow} ifelse } bind def\n",
+
+/* centred show */
+"/MCshow { currentpoint stroke M\n",
+" exch dup MFwidth -2 div 3 -1 roll R\n Blacktext {gsave 0 setgray MFshow grestore} {MFshow} ifelse } bind def\n",
+
+/* Save and restore for @-text (phantom box) */
+"/XYsave { [( ) 1 2 true false 3 ()] } bind def\n",
+"/XYrestore { [( ) 1 2 true false 4 ()] } bind def\n",
+
+NULL
+};
+
+/* external/internal prologue files machinery */
+#if defined(GNUPLOT_PS_DIR)
+# if defined(_Windows)
+# include "win/winmain.h"
+# elif defined(OS2)
+# define INCL_DOSPROCESS
+# define INCL_DOSMODULEMGR
+# include <os2.h>
+# endif /* _Windows || OS2 */
+#else /* GNUPLOT_PS_DIR */
+# include "PostScript/prologues.h"
+#endif /* GNUPLOT_PS_DIR */
+
+/* added to enhpost by Matt Heffron <heffron@falstaff.css.beckman.com> */
+/* moved to post.trm by drd */
+
+static struct PS_FontName {
+ char *name;
+ struct PS_FontName *next;
+} *PS_DocFonts = NULL;
+
+static char PS_default_font[MAX_ID_LEN+1] = {'H','e','l','v','e','t','i','c','a',',','1','4','\0'};
+
+/* given a font, look in store to see if it is there already
+ * if so, return NULL. If not, reencode it if allowed to, otherwise
+ * return an appropriate re-encode string
+ */
+
+TERM_PUBLIC char *
+PS_RememberFont(char *fname, int can_reencode)
+{
+ struct PS_FontName *fnp;
+ char *recode = NULL;
+ char *myfname = "Symbol";
+
+ if (strcmp(fname, "Symbol-Oblique") != 0)
+ myfname = fname;
+
+ for (fnp = PS_DocFonts; fnp ; fnp = fnp->next)
+ if (strcmp(fnp->name, myfname) == 0)
+ return NULL;
+
+ /* we did not find the name */
+
+ fnp = (struct PS_FontName *)gp_alloc(sizeof(struct PS_FontName),
+ "PostScript Font record");
+ fnp->name = gp_strdup(myfname);
+ fnp->next = PS_DocFonts;
+ PS_DocFonts = fnp;
+
+ switch(encoding) {
+ case S_ENC_ISO8859_1:
+ recode = "reencodeISO def\n";
+ break;
+ case S_ENC_ISO8859_2:
+ recode = "reencodeISO2 def\n";
+ break;
+ case S_ENC_ISO8859_15:
+ recode = "reencodeISO15 def\n";
+ break;
+ case S_ENC_CP437:
+ recode = "reencodeCP437 def\n";
+ break;
+ case S_ENC_CP850 :
+ recode = "reencodeCP850 def\n";
+ break;
+ case S_ENC_CP852 :
+ recode = "reencodeCP852 def\n";
+ break;
+ case S_ENC_KOI8_R :
+ recode = "reencodeKOI8R def\n";
+ break;
+ case S_ENC_CP1250 :
+ recode = "reencodeCP1250 def\n";
+ break;
+ case S_ENC_KOI8_U :
+ recode = "reencodeKOI8U def\n";
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+
+ if (can_reencode && recode) {
+ fprintf(gppsfile,"/%s %s", myfname, recode);
+ return NULL;
+ } else
+ return recode;
+}
+
+char *
+PS_escape_string(char *origstr, char *escapelist)
+{
+ char *newstr;
+ char *n;
+
+ if (!origstr || !*origstr)
+ return NULL;
+
+ newstr = gp_alloc(2*strlen(origstr)+1,"PS_escape_string");
+ for (n=newstr; *origstr; *n++ = *origstr++) {
+ if (strchr(escapelist,*origstr))
+ *n++ = '\\';
+ }
+ *n = '\0';
+
+ return newstr;
+}
+
+static int PS_pen_x, PS_pen_y;
+static int PS_taken;
+static int PS_linetype_last;
+static double PS_linewidth_last; /* HBB NEW 20031219 */
+static TBOOLEAN PS_relative_ok;
+
+/* HBB 990914: PS_SOLID is already used by the WIN32 API headers.
+ * Renamed to PS_SOLIDE, therefore... */
+enum PS_id {
+ PS_PORTRAIT, PS_LANDSCAPE,
+ PS_EPSF, PS_DEFAULT, PS_ENHANCED, PS_NOENHANCED,
+ PS_LATEX, EPSLATEX_STANDALONE, EPSLATEX_INPUT,
+ PS_MONOCHROME, PS_COLOR, PS_BLACKTEXT, PS_COLORTEXT,
+ PS_SOLIDE, PS_DASHED, PS_DASHLENGTH, PS_LINEWIDTH,
+ PS_SIMPLEX, PS_DUPLEX, PS_DEFAULTPLEX,
+ PS_ROUNDED, PS_NOROUNDED, PS_FONTFILE, PS_NOFONTFILES,
+ PS_PALFUNCPARAM,
+ PS_LEVEL1, PS_LEVELDEFAULT, PS_FONT,
+ PSLATEX_ROTATE, PSLATEX_NOROTATE, PSLATEX_AUXFILE, PSLATEX_NOAUXFILE,
+ PSLATEX_OLDSTYLE, PSLATEX_NEWSTYLE, EPSLATEX_HEADER, EPSLATEX_NOHEADER,
+ PS_SIZE,
+ PS_OTHER
+};
+
+static struct gen_table PS_opts[] =
+{
+ { "d$efault", PS_DEFAULT },
+ { "p$ortrait", PS_PORTRAIT },
+ { "l$andscape", PS_LANDSCAPE },
+ { "ep$sf", PS_EPSF },
+ { "enh$anced", PS_ENHANCED },
+ { "noenh$anced", PS_NOENHANCED },
+ { "m$onochrome", PS_MONOCHROME },
+ { "c$olor", PS_COLOR },
+ { "c$olour", PS_COLOR },
+ { "b$lacktext", PS_BLACKTEXT },
+ { "colort$ext", PS_COLORTEXT },
+ { "colourt$ext", PS_COLORTEXT },
+ { "so$lid", PS_SOLIDE },
+ { "da$shed", PS_DASHED },
+ { "dashl$ength", PS_DASHLENGTH },
+ { "dl", PS_DASHLENGTH },
+ { "linew$idth", PS_LINEWIDTH },
+ { "lw", PS_LINEWIDTH },
+ { "size", PS_SIZE },
+ { "si$mplex", PS_SIMPLEX },
+ { "du$plex", PS_DUPLEX },
+ { "defaultp$lex", PS_DEFAULTPLEX },
+ { "butt", PS_NOROUNDED },
+ { "rou$nded", PS_ROUNDED },
+ { "fontf$ile", PS_FONTFILE },
+ { "nofontf$iles", PS_NOFONTFILES },
+ { "palf$uncparam", PS_PALFUNCPARAM },
+ { "level1", PS_LEVEL1 },
+ { "leveldefault", PS_LEVELDEFAULT },
+ { "font", PS_FONT },
+ { "stand$alone", EPSLATEX_STANDALONE },
+ { "inp$ut", EPSLATEX_INPUT },
+ { "header", EPSLATEX_HEADER },
+ { "noheader", EPSLATEX_NOHEADER },
+ { "r$otate", PSLATEX_ROTATE },
+ { "n$orotate", PSLATEX_NOROTATE },
+ { "a$uxfile", PSLATEX_AUXFILE },
+ { "noa$uxfile", PSLATEX_NOAUXFILE },
+ { "old$style", PSLATEX_OLDSTYLE },
+ { "new$style", PSLATEX_NEWSTYLE },
+ { NULL, PS_OTHER }
+};
+
+
+TERM_PUBLIC void
+PS_options()
+{
+ struct value a;
+ char *s;
+ char *ps_fontfile_char = NULL;
+ char tmp_term_options[MAX_LINE_LEN+1] = "";
+
+ TBOOLEAN set_orientation = FALSE, set_enhanced = FALSE, set_plex = FALSE;
+ TBOOLEAN set_level = FALSE, set_color = FALSE, set_dashed = FALSE;
+ TBOOLEAN set_dashlen = FALSE, set_linewidth = FALSE, set_round = FALSE;
+ TBOOLEAN set_palfunc = FALSE, set_colortext = FALSE;
+ TBOOLEAN set_standalone = FALSE, set_epslheader = FALSE;
+ TBOOLEAN set_pslrotate = FALSE, set_pslauxfile = FALSE;
+ TBOOLEAN set_psloldstyle = FALSE, set_font = FALSE, set_fontsize = FALSE;
+
+ /* Annoying hack to handle the case of 'set termoption' after */
+ /* we have already initialized the terminal. */
+ if (c_token != 2)
+ ps_explicit_size = FALSE;
+
+ if (strcmp(term->name, "pstex") == 0)
+ ps_params = &pstex_params;
+ else if (strcmp(term->name, "pslatex") == 0)
+ ps_params = &pslatex_params;
+ else if (strcmp(term->name, "epslatex") == 0) {
+ ps_params = &epslatex_params;
+ } else
+ ps_params = &post_params;
+
+ if (ps_params->terminal == PSTERM_POSTSCRIPT) {
+ if (pslatex_auxname)
+ free(pslatex_auxname);
+ pslatex_auxname = NULL;
+ } else {
+ term->set_font = PS_set_font;
+ }
+
+ if (!END_OF_COMMAND) {
+ if (lookup_table(&PS_opts[0],c_token) == PS_DEFAULT) {
+ switch (ps_params->terminal) {
+ case PSTERM_POSTSCRIPT:
+ while (ps_params->first_fontfile != NULL)
+ delete_ps_fontfile((struct ps_fontfile_def *) NULL,
+ ps_params->first_fontfile);
+ *ps_params = post_params_default;
+ break;
+ case PSTERM_EPSLATEX:
+ *ps_params = epslatex_params_default;
+ break;
+ case PSTERM_PSLATEX:
+ *ps_params = pslatex_params_default;
+ break;
+ case PSTERM_PSTEX:
+ *ps_params = pstex_params_default;
+ break;
+ }
+ term->flags &= ~TERM_ENHANCED_TEXT;
+ c_token++;
+ if (!END_OF_COMMAND)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ }
+ }
+
+ while (!END_OF_COMMAND) {
+ switch(lookup_table(&PS_opts[0],c_token)) {
+ case PS_PORTRAIT:
+ if (set_orientation || ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_orientation = TRUE;
+ ps_params->psformat = PSTERM_PORTRAIT;
+ c_token++;
+ break;
+ case PS_LANDSCAPE:
+ if (set_orientation || ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_orientation = TRUE;
+ ps_params->psformat = PSTERM_LANDSCAPE;
+ c_token++;
+ break;
+ case PS_EPSF:
+ if (set_orientation || ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_orientation = TRUE;
+ ps_params->psformat = PSTERM_EPS;
+ c_token++;
+ break;
+ case PS_LEVEL1:
+ if (set_level)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_level = TRUE;
+ ps_params->level1 = TRUE;
+ c_token++;
+ break;
+ case PS_LEVELDEFAULT:
+ if (set_level)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_level = TRUE;
+ ps_params->level1 = FALSE;
+ c_token++;
+ break;
+ case PS_DEFAULT:
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ c_token++;
+ break;
+ case PS_ENHANCED:
+ if (set_enhanced || ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_enhanced = TRUE;
+ term->put_text = ENHPS_put_text;
+ term->set_font = ENHPS_set_font;
+ term->flags |= TERM_ENHANCED_TEXT;
+ ++c_token;
+ break;
+ case PS_NOENHANCED:
+ if (set_enhanced || ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_enhanced = TRUE;
+ term->put_text = PS_put_text;
+ term->set_font = PS_set_font;
+ term->flags &= ~TERM_ENHANCED_TEXT;
+ ++c_token;
+ break;
+#ifdef PSLATEX_DRIVER
+ case EPSLATEX_STANDALONE:
+ if (set_standalone || ps_params->terminal != PSTERM_EPSLATEX)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_standalone = TRUE;
+ ps_params->epslatex_standalone = TRUE;
+ ++c_token;
+ break;
+ case EPSLATEX_INPUT:
+ if (set_standalone || ps_params->terminal != PSTERM_EPSLATEX)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_standalone = TRUE;
+ ps_params->epslatex_standalone = FALSE;
+ ++c_token;
+ break;
+
+ case EPSLATEX_HEADER:
+ if (set_epslheader || ps_params->terminal != PSTERM_EPSLATEX)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_epslheader = TRUE;
+ ++c_token;
+ free(epslatex_header);
+ /* Protect against int_error() bail from try_to_get_string() */
+ epslatex_header = NULL;
+ epslatex_header = try_to_get_string();
+ if (!epslatex_header)
+ int_error(c_token,"String containing header information expected");
+ break;
+
+ case EPSLATEX_NOHEADER:
+ if (set_epslheader || ps_params->terminal != PSTERM_EPSLATEX)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_epslheader = TRUE;
+ free(epslatex_header);
+ epslatex_header = NULL;
+ ++c_token;
+ break;
+
+ case PSLATEX_ROTATE:
+ if (set_pslrotate || ((ps_params->terminal != PSTERM_PSLATEX) &&
+ (ps_params->terminal != PSTERM_PSTEX)))
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_pslrotate = TRUE;
+ ps_params->rotate = TRUE;
+ ++c_token;
+ break;
+ case PSLATEX_NOROTATE:
+ if (set_pslrotate || ((ps_params->terminal != PSTERM_PSLATEX) &&
+ (ps_params->terminal != PSTERM_PSTEX)))
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_pslrotate = TRUE;
+ ps_params->rotate = FALSE;
+ ++c_token;
+ break;
+ case PSLATEX_AUXFILE:
+ if (set_pslauxfile ||
+ ((ps_params->terminal == PSTERM_POSTSCRIPT) ||
+ (ps_params->terminal == PSTERM_EPSLATEX)))
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_pslauxfile = TRUE;
+ ps_params->useauxfile = TRUE;
+ c_token++;
+ break;
+ case PSLATEX_NOAUXFILE:
+ if (set_pslauxfile ||
+ ((ps_params->terminal == PSTERM_POSTSCRIPT) ||
+ (ps_params->terminal == PSTERM_EPSLATEX)))
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_pslauxfile = TRUE;
+ ps_params->useauxfile = FALSE;
+ c_token++;
+ break;
+ case PSLATEX_OLDSTYLE:
+ if (set_psloldstyle || ps_params->terminal == PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_psloldstyle = TRUE;
+ ps_params->oldstyle = TRUE;
+ if (ps_params->terminal == PSTERM_EPSLATEX)
+ ps_params->rounded = TRUE;
+ c_token++;
+ break;
+ case PSLATEX_NEWSTYLE:
+ if (set_psloldstyle || ps_params->terminal == PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_psloldstyle = TRUE;
+ ps_params->oldstyle = FALSE;
+ c_token++;
+ break;
+#endif
+ case PS_MONOCHROME:
+ if (set_color)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_color = TRUE;
+ ps_params->color = FALSE;
+ c_token++;
+ break;
+ case PS_COLOR:
+ if (set_color)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_color = TRUE;
+ ps_params->color = TRUE;
+ c_token++;
+ break;
+ case PS_BLACKTEXT:
+ if (set_colortext || ((ps_params->terminal != PSTERM_POSTSCRIPT) &&
+ (ps_params->terminal != PSTERM_EPSLATEX)))
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_colortext = TRUE;
+ ps_params->blacktext = TRUE;
+ c_token++;
+ break;
+ case PS_COLORTEXT:
+ if (set_colortext || ((ps_params->terminal != PSTERM_POSTSCRIPT) &&
+ (ps_params->terminal != PSTERM_EPSLATEX)))
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_colortext = TRUE;
+ ps_params->blacktext = FALSE;
+ c_token++;
+ break;
+ case PS_SOLIDE:
+ if (set_dashed)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_dashed = TRUE;
+ ps_params->solid = TRUE;
+ c_token++;
+ break;
+ case PS_DASHED:
+ if (set_dashed)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_dashed = TRUE;
+ ps_params->solid = FALSE;
+ c_token++;
+ break;
+ case PS_DASHLENGTH:
+ if (set_dashlen)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_dashlen = TRUE;
+ c_token++;
+ ps_params->dash_length = real(const_express(&a));
+ if (ps_params->dash_length <= 0.0)
+ ps_params->dash_length = 1.0;
+ break;
+ case PS_LINEWIDTH:
+ if (set_linewidth)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_linewidth = TRUE;
+ c_token++;
+ ps_params->linewidth_factor = real(const_express(&a));
+ if (ps_params->linewidth_factor <= 0.0)
+ ps_params->linewidth_factor = 1.0;
+ break;
+ case PS_SIMPLEX:
+ if (set_plex || ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_plex = TRUE;
+ ps_params->duplex_state = FALSE;
+ ps_params->duplex_option = TRUE;
+ c_token++;
+ break;
+ case PS_DUPLEX:
+ if (set_plex || ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_plex = TRUE;
+ ps_params->duplex_state = TRUE;
+ ps_params->duplex_option = TRUE;
+ c_token++;
+ break;
+ case PS_DEFAULTPLEX:
+ if (set_plex || ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_plex = TRUE;
+ ps_params->duplex_option = FALSE;
+ c_token++;
+ break;
+ case PS_ROUNDED:
+ if (set_round)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_round = TRUE;
+ ps_params->rounded = TRUE;
+ c_token++;
+ break;
+ case PS_NOROUNDED:
+ if (set_round)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_round = TRUE;
+ ps_params->rounded = FALSE;
+ c_token++;
+ break;
+ case PS_FONTFILE: {
+ TBOOLEAN deleteentry = FALSE;
+ c_token++;
+ if (ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+
+ if (!isstring(c_token)) {
+ if (equals(c_token, "add"))
+ c_token++;
+ else if (almost_equals(c_token, "del$ete")) {
+ deleteentry = TRUE;
+ c_token++;
+ } else
+ int_error(c_token, "Font filename expected");
+ }
+ if (isstring(c_token)) {
+ TBOOLEAN filename_doubled = FALSE;
+ struct ps_fontfile_def *curr_ps_fontfile =
+ ps_params->first_fontfile;
+ struct ps_fontfile_def *prev_ps_fontfile = NULL;
+ struct ps_fontfile_def *new_ps_fontfile =
+ gp_alloc(sizeof(struct ps_fontfile_def),
+ "new_ps_fontfile");
+
+ new_ps_fontfile->fontfile_name =
+ gp_alloc (token_len(c_token),
+ "new_ps_fontfile->fontfile_name");
+ quote_str(new_ps_fontfile->fontfile_name,
+ c_token, token_len(c_token));
+ gp_expand_tilde(&(new_ps_fontfile->fontfile_name));
+ if (!deleteentry) {
+#if defined(PIPES)
+ if (*(new_ps_fontfile->fontfile_name) != '<') {
+#endif
+ new_ps_fontfile->fontfile_fullname =
+ fontpath_fullname(new_ps_fontfile->fontfile_name);
+ if (!new_ps_fontfile->fontfile_fullname)
+ int_error(c_token, "Font file '%s' not found",
+ new_ps_fontfile->fontfile_name);
+#if defined(PIPES)
+ } else
+ new_ps_fontfile->fontfile_fullname = NULL;
+#endif
+
+ }
+ new_ps_fontfile->next = NULL;
+
+ if (!deleteentry) {
+ LFS *lf=lf_head;
+ if (lf) {
+ while (lf->prev)
+ lf=lf->prev;
+ }
+ if ((lf && lf->interactive) || interactive)
+ /* if (interactive) { */
+ PS_load_fontfile(new_ps_fontfile,FALSE);
+ }
+
+ if (ps_params->first_fontfile) {
+ while (curr_ps_fontfile) {
+ if (strcmp(curr_ps_fontfile->fontfile_name,
+ new_ps_fontfile->fontfile_name) == 0) {
+ filename_doubled = TRUE;
+ if (deleteentry) {
+ delete_ps_fontfile(prev_ps_fontfile,
+ curr_ps_fontfile);
+ curr_ps_fontfile = NULL;
+ break;
+ }
+ }
+ prev_ps_fontfile = curr_ps_fontfile;
+ curr_ps_fontfile = curr_ps_fontfile->next;
+ }
+ if (!filename_doubled) {
+ if (!deleteentry)
+ prev_ps_fontfile->next = new_ps_fontfile;
+ else
+ int_warn(c_token,"Can't delete Font filename '%s'",
+ new_ps_fontfile->fontfile_name);
+ }
+ } else {
+ if (!deleteentry)
+ ps_params->first_fontfile = new_ps_fontfile;
+ else
+ int_warn(c_token, "Can't delete Font filename '%s'",
+ new_ps_fontfile->fontfile_name);
+ }
+ c_token++;
+ } else
+ int_error(c_token, "Font filename expected");
+ break;
+ }
+ case PS_NOFONTFILES:
+ if (ps_params->terminal != PSTERM_POSTSCRIPT)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ while (ps_params->first_fontfile != NULL)
+ delete_ps_fontfile((struct ps_fontfile_def *) NULL,
+ ps_params->first_fontfile);
+ ++c_token;
+ break;
+ case PS_PALFUNCPARAM:
+ if (set_palfunc)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",term->name);
+ set_palfunc = TRUE;
+ ++c_token;
+ ps_params->palfunc_samples = (int)real(const_express(&a));
+ if (ps_params->palfunc_samples < 2)
+ ps_params->palfunc_samples = 2;
+ if (!END_OF_COMMAND && equals(c_token, ",")) {
+ ++c_token;
+ ps_params->palfunc_deviation = fabs(real(const_express(&a)));
+ if (ps_params->palfunc_deviation >= 1)
+ int_error(c_token-1,"allowed deviation must be < 1");
+ }
+ break;
+
+ case PS_SIZE:
+ {
+ float xmax_t, ymax_t;
+
+ c_token++;
+ ps_explicit_size = TRUE;
+ ps_explicit_units = parse_term_size(&xmax_t, &ymax_t, INCHES);
+
+ /* PostScript *always* works in pts, not locally defined dpi */
+ term->xmax = xmax_t * PS_SC * 72./gp_resolution;
+ term->ymax = ymax_t * PS_SC * 72./gp_resolution;
+ eps_explicit_x = 2 * term->xmax;
+ eps_explicit_y = 2 * term->ymax;
+ break;
+ }
+
+ case PS_FONT:
+ c_token++;
+ /* Fall through to attempt to read font name */
+ case PS_OTHER:
+ default:
+ if ((s = try_to_get_string())) {
+ if (set_font)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",
+ term->name);
+ set_font = TRUE;
+ if ((ps_params->terminal == PSTERM_POSTSCRIPT) ||
+ (ps_params->terminal == PSTERM_EPSLATEX)) {
+ char *comma = strrchr(s,',');
+ if (comma && (1 == sscanf(comma+1,"%f",&ps_params->fontsize))) {
+ set_fontsize = TRUE;
+ *comma = '\0';
+ }
+ if (*s)
+ strncpy(ps_params->font, s, sizeof(ps_params->font));
+ free(s);
+ } else
+ int_error(c_token-1,
+ "terminal %s does not allow specification %s",
+ term->name, "of font name");
+ } else {
+ if (set_fontsize)
+ int_error(c_token,
+ "extraneous argument in set terminal %s",
+ term->name);
+ set_fontsize = TRUE;
+ /* We have font size specified */
+ ps_params->fontsize = real(const_express(&a));
+ }
+ break;
+ }
+ }
+
+ switch (ps_params->terminal) {
+ case PSTERM_POSTSCRIPT:
+ ps_fontsize = ps_params->fontsize;
+ break;
+ case PSTERM_EPSLATEX:
+ ps_fontsize = 2 * ps_params->fontsize;
+ break;
+ case PSTERM_PSLATEX:
+ case PSTERM_PSTEX:
+ if (ps_params->fontsize > 0)
+ ps_fontsize = 2 * ps_params->fontsize;
+ else
+ ps_fontsize = 20; /* default: 10pt */
+ break;
+ }
+ term->v_char = (unsigned int)(ps_fontsize*PS_SC);
+ if (ps_params->oldstyle)
+ term->h_char = (unsigned int)(ps_fontsize*PS_SC*5/10);
+ else
+ term->h_char = (unsigned int)(ps_fontsize*PS_SC*6/10);
+ sprintf(PS_default_font,"%s,%g",ps_params->font,ps_fontsize);
+
+ if (ps_params->terminal == PSTERM_POSTSCRIPT) {
+ if (ps_params->first_fontfile) {
+ struct ps_fontfile_def *curr_ps_fontfile =
+ ps_params->first_fontfile;
+ unsigned int totlength = 0;
+ char *running;
+
+ while (curr_ps_fontfile) {
+ totlength += strlen(curr_ps_fontfile->fontfile_name) +
+ strlen(" fontfile \"\"");
+ curr_ps_fontfile = curr_ps_fontfile->next;
+ }
+ curr_ps_fontfile = ps_params->first_fontfile;
+ ps_fontfile_char = gp_alloc (totlength+1,"ps_fontfile_char");
+ running = ps_fontfile_char;
+ while (curr_ps_fontfile) {
+ sprintf(running," fontfile \"%s\"",
+ curr_ps_fontfile->fontfile_name);
+ running += strlen(running);
+ curr_ps_fontfile = curr_ps_fontfile->next;
+ }
+ }
+ }
+
+ /* HBB 19990823: fixed the options string. It violated the 'save
+ * loadable output' rule */
+ if (ps_params->terminal == PSTERM_POSTSCRIPT)
+ sprintf(term_options,"%s %s %s \\\n",
+ ps_params->psformat==PSTERM_EPS ? "eps" :
+ (ps_params->psformat==PSTERM_PORTRAIT ?
+ "portrait" : "landscape"),
+ term->put_text == ENHPS_put_text ? "enhanced" : "noenhanced",
+ ps_params->duplex_option ? (ps_params->duplex_state ?
+ "duplex" : "simplex")
+ : "defaultplex");
+ else if (ps_params->terminal != PSTERM_EPSLATEX)
+ sprintf(term_options, "%s%s",
+ ps_params->rotate ? "rotate" : "norotate",
+ ps_params->useauxfile ? " auxfile" : "");
+ else
+ term_options[0] = '\0';
+
+ sprintf(tmp_term_options," %s %s %s \\\n\
+ %s dashlength %.1f linewidth %.1f %s \\\n",
+ ps_params->level1 ? "level1" : "leveldefault",
+ ps_params->color ? "color" : "monochrome",
+ ps_params->blacktext ? "blacktext" : "colortext",
+ ps_params->solid ? "solid" : "dashed",
+ ps_params->dash_length,
+ ps_params->linewidth_factor,
+ ps_params->rounded ? "rounded" : "butt");
+ strcat(term_options,tmp_term_options);
+
+ sprintf(tmp_term_options," palfuncparam %d,%g \\\n ",
+ ps_params->palfunc_samples, ps_params->palfunc_deviation);
+ strcat(term_options,tmp_term_options);
+
+#ifdef PSLATEX_DRIVER
+ if ((ps_params->terminal == PSTERM_PSTEX) ||
+ (ps_params->terminal == PSTERM_PSLATEX)) {
+ sprintf(tmp_term_options, "%s %s ",
+ ps_params->rotate ? "rotate" : "norotate",
+ ps_params->useauxfile ? "auxfile" : "noauxfile");
+ strcat(term_options,tmp_term_options);
+ }
+
+ if (ps_params->terminal == PSTERM_EPSLATEX) {
+ sprintf(tmp_term_options, "%s ",
+ ps_params->epslatex_standalone ? "standalone" : "input");
+ if (epslatex_header)
+ sprintf(tmp_term_options, "header \"%s\" ", epslatex_header);
+ else
+ sprintf(tmp_term_options, "noheader ");
+ strcat(term_options,tmp_term_options);
+ }
+#endif
+
+ if (ps_explicit_size) {
+ if (ps_explicit_units == CM)
+ sprintf(tmp_term_options,"size %.2fcm, %.2fcm ",
+ 2.54*(float)term->xmax/(72.*PS_SC), 2.54*(float)term->ymax/(72.*PS_SC));
+ else
+ sprintf(tmp_term_options,"size %.2fin, %.2fin ",
+ (float)term->xmax/(72.*PS_SC), (float)term->ymax/(72.*PS_SC));
+ strcat(term_options,tmp_term_options);
+ }
+
+ if (ps_params->terminal == PSTERM_POSTSCRIPT)
+ sprintf(tmp_term_options,"\"%s\" %g%s ",
+ ps_params->font,ps_params->fontsize,
+ ps_fontfile_char ? ps_fontfile_char : "");
+ else if (ps_params->terminal == PSTERM_EPSLATEX)
+ sprintf(tmp_term_options,"\"%s\" %g ",
+ ps_params->font,ps_params->fontsize);
+ else if (ps_params->fontsize)
+ sprintf(tmp_term_options,"%g ",ps_params->fontsize);
+ else
+ tmp_term_options[0]='\0';
+ if (ps_fontfile_char)
+ free(ps_fontfile_char);
+
+ strcat(term_options,tmp_term_options);
+
+}
+
+/* store settings passed to common_init() for use in PS_graphics()
+ * ps_params->psformat, etc are reserved for storing the term options
+ */
+static TBOOLEAN ps_common_uses_fonts;
+static unsigned int ps_common_xoff, ps_common_yoff;
+
+
+TERM_PUBLIC void
+PS_load_fontfile(struct ps_fontfile_def *current_ps_fontfile, TBOOLEAN doload)
+{
+ if (current_ps_fontfile) {
+ unsigned int linesread = 0;
+ FILE *ffont = NULL;
+ char line[256];
+ char ext[4];
+ char cmd[256];
+ char *fontname = NULL;
+#if defined(PIPES)
+ char *envcmd = NULL;
+ TBOOLEAN ispipe = FALSE;
+#endif
+
+ ext[0] = '\0';
+ cmd[0] = '\0';
+
+ if (doload)
+ fprintf(gppsfile,"%%%%BeginProcSet: %s\n",
+ current_ps_fontfile->fontfile_name);
+
+ /* get filename extension if no pipe (if pipe *ext=='\0') */
+#if defined(PIPES)
+ if (*(current_ps_fontfile->fontfile_name) != '<') {
+ /* Filename is given */
+#endif
+ if (strlen(current_ps_fontfile->fontfile_name) > 3)
+ strcpy(ext, current_ps_fontfile->fontfile_name +
+ strlen(current_ps_fontfile->fontfile_name) - 3);
+ else
+ strcpy(ext, current_ps_fontfile->fontfile_name);
+
+ /* make extension lowercase for comparison */
+ lower_case(ext);
+
+ if (!current_ps_fontfile->fontfile_fullname)
+ int_error(NO_CARET, "Font file '%s' not found",
+ current_ps_fontfile->fontfile_name);
+#if defined(PIPES)
+ }
+#endif
+ if (strlen(ext) == 0) {
+#if defined(PIPES)
+ /* Pipe is given */
+ ispipe = TRUE;
+ strcpy(cmd,current_ps_fontfile->fontfile_name + 1);
+ ffont = popen(cmd, "r");
+ if (!ffont)
+ int_error(NO_CARET, "Could not execute pipe '%s'",
+ current_ps_fontfile->fontfile_name + 1);
+#endif
+ }
+ else if (strcmp(ext,"ttf") == 0) {
+ /* TrueType */
+#if defined(PIPES)
+ ispipe = TRUE;
+ envcmd = getenv("GNUPLOT_TTFTOPFA");
+ if (envcmd != NULL)
+ sprintf(cmd,envcmd,current_ps_fontfile->fontfile_fullname);
+ else
+ sprintf(cmd,"ttf2pt1 -a -e -W 0 %s -",
+ current_ps_fontfile->fontfile_fullname);
+ if (strlen(cmd) == 0)
+ int_error(NO_CARET,
+ "No command for automatic font conversion ttf->pfa defined");
+ else {
+ ffont = popen(cmd,"r");
+ if (!ffont)
+ int_error(NO_CARET,"Could not execute command '%s'", cmd);
+ }
+#else
+ os_error(NO_CARET,
+ "Automatic font conversion ttf->pfa not supported");
+#endif
+ } else if (strcmp(ext,"pfb") == 0) {
+ /* PFB */
+#if defined(PIPES)
+ ispipe = TRUE;
+ envcmd = getenv("GNUPLOT_PFBTOPFA");
+ if (envcmd != NULL)
+ sprintf(cmd,envcmd,current_ps_fontfile->fontfile_fullname);
+ else
+ sprintf(cmd,"pfbtops %s",
+ current_ps_fontfile->fontfile_fullname);
+ if (strlen(cmd) == 0)
+ int_error(NO_CARET,
+ "No command for automatic font conversion pfb->pfa defined");
+ else {
+ ffont = popen(cmd,"r");
+ if (!ffont)
+ int_error(NO_CARET,"Could not execute command '%s'", cmd);
+ }
+#else
+ os_error(NO_CARET,
+ "Automatic font conversion pfb->pfa not supported");
+#endif
+ } else {
+ /* PFA */
+ if (strcmp(ext,"pfa") != 0)
+ int_warn(NO_CARET,
+ "Font file '%s' has unknown extension. Assume it is a pfa file",
+ current_ps_fontfile->fontfile_name);
+ ffont = fopen(current_ps_fontfile->fontfile_fullname, "r");
+ if (!ffont)
+ int_error(NO_CARET, "Font file '%s' not found",
+ current_ps_fontfile->fontfile_name);
+ }
+ /* read the file */
+ while (fgets(line,255,ffont)) {
+ /* test file format */
+ if ((linesread == 0) &&
+ (strstr(line,"%!PS-AdobeFont") != line) &&
+ (strstr(line,"%!FontType1") != line)) {
+#if defined(PIPES)
+ if (ispipe)
+ int_warn(NO_CARET,
+ "Command '%s' seems not to generate PFA data",
+ cmd);
+ else
+#endif
+ int_warn(NO_CARET,
+ "Font file '%s' seems not to be a PFA file",
+ current_ps_fontfile->fontfile_name);
+ }
+ /* get fontname */
+ if (strstr(line,"/FontName") == line) {
+ char *fnende = NULL;
+ fontname = gp_alloc(strlen(line)-9,"load_fontfiles");
+ strcpy(fontname,strstr(line+1,"/")+1);
+ fnende = strstr(fontname," ");
+ *fnende = '\0';
+ /* Print font name */
+ if (!doload) {
+ if (current_ps_fontfile->fontfile_fullname)
+ fprintf(stderr,
+ "Font file '%s' contains the font '%s'. Location:\n %s\n",
+ current_ps_fontfile->fontfile_name,
+ fontname,
+ current_ps_fontfile->fontfile_fullname);
+ else
+ fprintf(stderr,
+ "Pipe '%s' contains the font '%s'.\n",
+ current_ps_fontfile->fontfile_name,
+ fontname);
+#if defined(PIPES)
+ /* Stop reading font file in order to save time */
+ /* This does not work for pipes because they give the */
+ /* error message 'broken pipe' */
+ if (!ispipe)
+#endif
+ break;
+ }
+ }
+
+ if (doload)
+ fputs(line, gppsfile);
+
+ ++linesread;
+ }
+#if defined(PIPES)
+ if (ispipe) {
+ int exitcode;
+ if ((exitcode = pclose(ffont)) != 0)
+ int_error(NO_CARET,
+ "Command '%s' generated error, exitcode is %d",
+ cmd, exitcode);
+ }
+ else
+#endif
+ fclose(ffont);
+
+ if (linesread == 0) {
+#if defined(PIPES)
+ if (ispipe)
+ int_error(NO_CARET,
+ "Command '%s' generates empty output",
+ cmd);
+ else
+#endif
+ int_error(NO_CARET, "Font file '%s' is empty",
+ current_ps_fontfile->fontfile_name);
+ }
+ if (doload)
+ fputs("%%EndProcSet\n", gppsfile);
+
+ /* Computer Modern Symbol font with corrected baseline if the
+ * font CMEX10 is embedded */
+ if (doload && fontname && (strcmp(fontname,"CMEX10") == 0)) {
+ fputs("%%BeginProcSet: CMEX10-Baseline\n", gppsfile);
+ fputs("/CMEX10-Baseline /CMEX10 findfont [1 0 0 1 0 1] makefont\n",
+ gppsfile);
+ fputs("dup length dict begin {1 index /FID eq {pop pop} {def} ifelse} forall\n", gppsfile);
+ fputs("currentdict end definefont pop\n", gppsfile);
+ fputs("%%EndProcSet\n",gppsfile);
+ }
+
+ if (fontname) {
+ free(fontname);
+ fontname = NULL;
+ }
+ }
+}
+
+
+TERM_PUBLIC void
+PS_load_fontfiles(TBOOLEAN doload)
+{
+ struct ps_fontfile_def *current_ps_fontfile=ps_params->first_fontfile;
+
+ while (current_ps_fontfile) {
+ PS_load_fontfile(current_ps_fontfile,doload);
+ current_ps_fontfile = current_ps_fontfile->next;
+ }
+}
+
+
+TERM_PUBLIC void
+PS_common_init(
+ TBOOLEAN uses_fonts, /* FALSE for (e)ps(la)tex */
+ unsigned int xoff, unsigned int yoff, /* how much to translate by */
+ unsigned int bb_xmin, unsigned int bb_ymin,
+ unsigned int bb_xmax, unsigned int bb_ymax, /* bounding box */
+ const char **dict) /* extra entries for the dictionary */
+{
+ static const char GPFAR psi1[] = "\
+%%%%Creator: gnuplot %s patchlevel %s\n\
+%%%%CreationDate: %s\n\
+%%%%DocumentFonts: %s\n";
+
+ static const char GPFAR psi2[] = "\
+%%%%EndComments\n\
+%%%%BeginProlog\n\
+/gnudict 256 dict def\ngnudict begin\n\
+%%\n\
+%% The following 6 true/false flags may be edited by hand if required\n\
+%% The unit line width may also be changed\n\
+%%\n\
+/Color %s def\n\
+/Blacktext %s def\n\
+/Solid %s def\n\
+/Dashlength %g def\n\
+/Landscape %s def\n\
+/Level1 %s def\n\
+/Rounded %s def\n\
+/TransparentPatterns false def\n\
+/gnulinewidth %.3f def\n\
+/userlinewidth gnulinewidth def\n\
+%%\n\
+/vshift %d def\n\
+/dl1 {\n\
+ %.1f Dashlength mul mul\n\
+ Rounded { currentlinewidth 0.75 mul sub dup 0 le { pop 0.01 } if } if\n\
+} def\n\
+/dl2 {\n\
+ %.1f Dashlength mul mul\n\
+ Rounded { currentlinewidth 0.75 mul add } if\n\
+} def\n\
+/hpt_ %.1f def\n\
+/vpt_ %.1f def\n\
+/hpt hpt_ def\n\
+/vpt vpt_ def\n";
+
+ static const char GPFAR psi3[] = "\
+Level1 {} {\n\
+/SDict 10 dict def\n\
+systemdict /pdfmark known not {\n\
+ userdict /pdfmark systemdict /cleartomark get put\n\
+} if\n\
+SDict begin [\n\
+ /Title (%s)\n\
+ /Subject (gnuplot plot)\n\
+ /Creator (gnuplot %s patchlevel %s)\n\
+ /Author (%s)\n\
+%% /Producer (gnuplot)\n\
+%% /Keywords ()\n\
+ /CreationDate (%s)\n\
+ /DOCINFO pdfmark\n\
+end\n\
+} ifelse\n";
+
+
+ struct termentry *t = term;
+ int i;
+ time_t now;
+ char *timedate;
+
+ ps_common_uses_fonts = uses_fonts;
+ ps_common_xoff = xoff;
+ ps_common_yoff = yoff;
+
+ ps_page = 0;
+
+ time(&now);
+ timedate=asctime(localtime(&now));
+ timedate[strlen(timedate)-1]='\0';
+
+#ifdef PSLATEX_DRIVER
+ /* Set files for (e)ps(la)tex terminals */
+ switch (ps_params->terminal) {
+ case PSTERM_EPSLATEX:
+ EPSLATEX_common_init();
+ break;
+ case PSTERM_PSLATEX:
+ case PSTERM_PSTEX:
+ PSTEX_common_init();
+ break;
+ default:; /* do nothing, just avoid a compiler warning */
+ }
+#endif
+
+ if (ps_params->psformat == PSTERM_EPS)
+ fputs("%!PS-Adobe-2.0 EPSF-2.0\n", gppsfile);
+ else
+ fputs("%!PS-Adobe-2.0\n", gppsfile);
+
+ if (outstr)
+ fprintf(gppsfile, "%%%%Title: %s\n", outstr); /* JFi */
+ fprintf(gppsfile, psi1, gnuplot_version, gnuplot_patchlevel,
+ timedate, uses_fonts ? "(atend)" : "");
+
+ fprintf(gppsfile,"%%%%BoundingBox: %d %d %d %d\n",
+ xoff + bb_xmin, yoff + bb_ymin, xoff + bb_xmax, yoff + bb_ymax);
+
+ if ((ps_params->terminal == PSTERM_POSTSCRIPT) &&
+ (ps_params->psformat != PSTERM_EPS))
+ fprintf(gppsfile,"%%%%Orientation: %s\n",
+ ps_params->psformat == PSTERM_LANDSCAPE ?
+ "Landscape" : "Portrait");
+
+ if (ps_params->psformat != PSTERM_EPS)
+ fputs("%%Pages: (atend)\n", gppsfile);
+ fprintf(gppsfile, psi2,
+ ps_params->color ? "true" : "false",
+ ps_params->blacktext ? "true" : "false",
+ ps_params->solid ? "true" : "false",
+ ps_params->dash_length, /* dash length */
+ ps_params->psformat == PSTERM_LANDSCAPE ? "true" : "false",
+ ps_params->level1 ? "true" : "false",
+ ps_params->rounded ? "true" : "false",
+ PS_LW*ps_params->linewidth_factor, /* line width */
+ (int)(t->v_char)/(-3), /* shift for vertical centring */
+ PS_SC*1.0, /* dash length */
+ PS_SC*1.0, /* dash length */
+ PS_HTIC/2.0, /* half point width */
+ PS_VTIC/2.0); /* half point height */
+
+ /* HH: print pdf information interpreted by ghostscript/acrobat */
+ {
+ char *username=getusername();
+ char *username2=PS_escape_string(username,"()\\");
+ char *outstr2=PS_escape_string(outstr,"()\\");
+ fprintf(gppsfile, psi3,
+ outstr2?outstr2:"",
+ gnuplot_version, gnuplot_patchlevel,
+ username2?username2:"",
+ timedate);
+ if (username)
+ free(username);
+ if (username2)
+ free(username2);
+ if (outstr2)
+ free(outstr2);
+ }
+
+ /* insert font encoding vector */
+ if (uses_fonts) {
+ switch (encoding) {
+ case S_ENC_ISO8859_1: PS_dump_prologue_file("8859-1.ps"); break;
+ case S_ENC_ISO8859_2: PS_dump_prologue_file("8859-2.ps"); break;
+ case S_ENC_ISO8859_15: PS_dump_prologue_file("8859-15.ps"); break;
+ case S_ENC_CP437: PS_dump_prologue_file("cp437.ps"); break;
+ case S_ENC_CP850: PS_dump_prologue_file("cp850.ps"); break;
+ case S_ENC_CP852: PS_dump_prologue_file("cp852.ps"); break;
+ case S_ENC_CP1250: PS_dump_prologue_file("cp1250.ps"); break;
+ case S_ENC_KOI8_R: PS_dump_prologue_file("koi8r.ps"); break;
+ case S_ENC_KOI8_U: PS_dump_prologue_file("koi8u.ps"); break;
+ case S_ENC_DEFAULT:
+ default: break;
+ }
+ }
+
+ /* Dump the body of the prologue */
+ PS_dump_prologue_file("prologue.ps");
+
+ /* Redefine old epslatex linetypes if requested */
+ if ((ps_params->terminal == PSTERM_EPSLATEX) && ps_params->oldstyle) {
+ for (i = 0; OldEPSL_linetypes[i] != NULL; i++)
+ fprintf(gppsfile,"%s",OldEPSL_linetypes[i]);
+ }
+
+ if (ps_params->duplex_option)
+ fprintf(gppsfile, "statusdict begin %s setduplexmode end\n",
+ ps_params->duplex_state ? "true" : "false");
+
+ if (dict)
+ while (*dict)
+ fputs(*(dict++), gppsfile);
+
+ if (uses_fonts) {
+ PS_load_fontfiles(TRUE);
+ PS_RememberFont(ps_params->font, 1);
+ }
+
+ fputs("end\n%%EndProlog\n", gppsfile);
+}
+
+/* the init fn for the postscript driver */
+TERM_PUBLIC void
+PS_init()
+{
+ unsigned int xmin_t = 0, ymin_t = 0, xmax_t = 0, ymax_t = 0;
+
+ switch (ps_params->psformat) {
+ case PSTERM_EPS:
+ if (ps_explicit_size) {
+ term->xmax = eps_explicit_x;
+ term->ymax = eps_explicit_y;
+ } else {
+ term->xmax = PS_XMAX;
+ if (ps_params->oldstyle)
+ term->ymax = PS_YMAX_OLDSTYLE;
+ else
+ term->ymax = PS_YMAX;
+ }
+ xmin_t = term->xmax * xoffset / (2*PS_SC);
+ xmax_t = term->xmax * (xsize + xoffset) / (2*PS_SC);
+ ymin_t = term->ymax * yoffset / (2*PS_SC);
+ ymax_t = term->ymax * (ysize + yoffset) / (2*PS_SC);
+ break;
+ case PSTERM_PORTRAIT:
+ if (!ps_explicit_size) {
+ term->xmax = PS_YMAX;
+ term->ymax = PS_XMAX;
+ }
+ xmin_t = term->xmax * xoffset / PS_SC;
+ xmax_t = term->xmax * (xsize + xoffset) / PS_SC;
+ ymin_t = term->ymax * yoffset / PS_SC;
+ ymax_t = term->ymax * (ysize + yoffset) / PS_SC;
+ break;
+ case PSTERM_LANDSCAPE:
+ if (!ps_explicit_size) {
+ term->xmax = PS_XMAX;
+ term->ymax = PS_YMAX;
+ }
+ ymin_t = term->xmax * xoffset / PS_SC;
+ ymax_t = term->xmax * (xsize+xoffset) / PS_SC;
+ xmin_t = term->ymax * (1-ysize-yoffset) / PS_SC;
+ xmax_t = term->ymax * (1-yoffset) / PS_SC;
+ break;
+ default:
+ int_error(NO_CARET, "invalid postscript format used");
+ }
+
+ /* for enhanced postscript, copy ps_params->font to ps_enh_font
+ * does no harm for non-enhanced
+ */
+ strcpy(ps_enh_font, ps_params->font);
+ ps_enh_fontsize = ps_fontsize;
+
+ switch (ps_params->terminal) {
+ case PSTERM_POSTSCRIPT:
+ gppsfile = gpoutfile;
+ break;
+ default:
+#ifdef PSLATEX_DRIVER
+ PSTEX_reopen_output();
+ break;
+ case PSTERM_EPSLATEX:
+ EPSLATEX_reopen_output();
+#endif
+ break;
+ }
+
+ PS_common_init(ps_params->terminal == PSTERM_POSTSCRIPT,
+ ps_params->xoff, ps_params->yoff,
+ xmin_t, ymin_t, xmax_t, ymax_t,
+ (term->put_text == ENHPS_put_text) ? ENHPS_header : NULL);
+
+ /* Keep track of whether we have written the enhanced text dictionary yet */
+ ENHPS_initialized = (term->put_text == ENHPS_put_text) ? 2 : 1;
+}
+
+
+TERM_PUBLIC void
+PS_graphics()
+{
+ static char GPFAR psg1[] = "0 setgray\nnewpath\n";
+ struct termentry *t = term;
+ ps_page++;
+ if (ps_params->psformat != PSTERM_EPS)
+ fprintf(gppsfile,"%%%%Page: %d %d\n",ps_page,ps_page);
+
+ /* If we are about to use enhanced text mode for the first time in a plot that */
+ /* was initialized previously without it, we need to write out the macros now */
+ if (term->put_text == ENHPS_put_text && ENHPS_initialized == 1) {
+ const char **dict = ENHPS_header;
+ while (*dict)
+ fputs(*(dict++), gppsfile);
+ fprintf(stderr,"Writing out PostScript macros for enhanced text mode\n");
+ ENHPS_initialized = 2;
+ }
+
+ fprintf(gppsfile,"\
+gnudict begin\ngsave\n\
+%d %d translate\n\
+%.3f %.3f scale\n",
+ ps_common_xoff, ps_common_yoff,
+ (ps_params->psformat == PSTERM_EPS ? 0.5 : 1.0)/PS_SC,
+ (ps_params->psformat == PSTERM_EPS ? 0.5 : 1.0)/PS_SC);
+ if (ps_params->psformat == PSTERM_LANDSCAPE)
+ fprintf(gppsfile,"90 rotate\n0 %d translate\n", -(int)(term->ymax));
+ fprintf(gppsfile, psg1);
+ if (ps_common_uses_fonts)
+ fprintf(gppsfile, "(%s) findfont %d scalefont setfont\n",
+ ps_params->font, (t->v_char));
+ ps_path_count = 0;
+ PS_relative_ok = FALSE;
+ PS_pen_x = PS_pen_y = -4000;
+ PS_taken = 0;
+ PS_linewidth_last = PS_linetype_last = LT_UNDEFINED;
+}
+
+
+TERM_PUBLIC void
+PS_text()
+{
+ ps_path_count = 0;
+ fputs("stroke\ngrestore\nend\nshowpage\n", gppsfile);
+ /* fprintf(stderr,"taken %d times\n",PS_taken); */
+ /* informational: tells how many times it was "cheaper"
+ * to do a relative moveto or lineto rather than an
+ * absolute one */
+}
+
+
+TERM_PUBLIC void
+PS_reset()
+{
+ fputs("%%Trailer\n", gppsfile);
+
+ /* I think the following commands should be executed
+ `if (ps_common_uses_fonts)`. So I changed the next line.
+ Please see "PS_RememberFont", too. */ /* JFi */
+
+ /* if (!ps_common_uses_fonts) { */ /* JFi */
+ if (ps_common_uses_fonts) {
+ fputs("%%DocumentFonts: ", gppsfile);
+ while (PS_DocFonts) {
+ struct PS_FontName *fnp;
+ fnp = PS_DocFonts->next;
+ fprintf(gppsfile, "%s%s", PS_DocFonts->name, fnp ? " " : "\n");
+ free(PS_DocFonts->name);
+ free(PS_DocFonts);
+ PS_DocFonts = fnp;
+ }
+ }
+ if (ps_params->psformat != PSTERM_EPS)
+ fprintf(gppsfile,"%%%%Pages: %d\n",ps_page);
+}
+
+TERM_PUBLIC void
+PS_linetype(int linetype)
+{
+ if ((ps_params->terminal == PSTERM_EPSLATEX) && ps_params->oldstyle)
+ linetype = (linetype % 4) + 3;
+ else
+ linetype = (linetype % 9) + 3;
+ if (linetype < 0) /* LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED */
+ linetype = 0;
+
+ if (PS_linetype_last == linetype) return;
+
+ PS_relative_ok = FALSE;
+ PS_FLUSH_PATH;
+
+ PS_linetype_last = linetype;
+ fprintf(gppsfile, "LT%c\n", "wba012345678"[linetype]);
+ ps_path_count = 0;
+}
+
+
+TERM_PUBLIC void
+PS_linewidth (double linewidth)
+{
+ /* HBB NEW 20031219: don't do anything if nothing changed */
+ if (ps_path_count != 0 && PS_linewidth_last == linewidth)
+ return;
+ PS_linewidth_last = linewidth;
+ PS_linetype_last = -1; /* disable cache for next linetype change */
+
+ PS_FLUSH_PATH;
+ fprintf(gppsfile, "%.3f UL\n", linewidth);
+
+ /*
+ Documentation of the 'change linewidth' strategy of the postscript terminal:
+
+ 1. define a new postscript variable with a default value:
+ /userlinewidth gnulinewidth def
+
+ 2. define a new postscript command to change the contents of that variable:
+ /UL { gnulinewidth mul /userlinewidth exch def } def
+ usage: multiplication_factor UL
+
+ 3. modify the already known postscript command /PL for the plot lines:
+ /PL { stroke userlinewidth setlinewidth } def
+
+ 4. issue the new command before every change of the plot linestyle:
+ example:
+ 4.0 UL
+ LT0
+ result:
+ Linetype 0 is drawn four times as thick as defined by the contents
+ of the postscript variable 'gnulinewidth'.
+ */
+}
+
+
+TERM_PUBLIC void
+PS_pointsize (double ptsize)
+{
+ fprintf(gppsfile, "%.3f UP\n", ptsize);
+
+/*
+ * Documentation of the 'change pointsize' strategy of the postscript
+ * terminal:
+ *
+ * 1. define two new postscript variables to hold the overall pointsize:
+ * /hpt_ and /vpt_
+ *
+ * 2. define a new postscript command to use the contents of these variables:
+ * /UP { cf. definition above } def
+ * usage: multiplication_factor UP
+ *
+ * [3.] [doesn't exist, skip to next number]
+ *
+ * 4. issue the new command whereever you change the symbols (and linetype):
+ * example:
+ * 2.5 UP
+ * 4.0 UL % optionally change linewidth, too
+ * LT0
+ * result:
+ * Next symbols will be drawn 2.5 times as big as defined by the
+ * GNUPLOT `set pointsize` command (= overall pointsize).
+ */
+}
+
+
+TERM_PUBLIC void
+PS_move(unsigned int x, unsigned int y)
+{
+ /* Make this semi-dynamic and independent of architecture */
+ char abso[5+2*INT_STR_LEN], rel[5+2*INT_STR_LEN];
+ int dx = x - PS_pen_x;
+ int dy = y - PS_pen_y;
+
+ /* can't cancel all null moves--need a move after stroke'ing */
+ if (dx==0 && dy==0 && PS_relative_ok)
+ return;
+
+ sprintf(abso, "%d %d M\n", x, y);
+ sprintf(rel, "%d %d R\n", dx, dy);
+
+ if (PS_newpath) {
+ fprintf(gppsfile, "%d %d N\n", x, y);
+ PS_newpath = FALSE;
+ } else
+ if (strlen(rel) < strlen(abso) && PS_relative_ok) {
+ fputs(rel, gppsfile);
+ PS_taken++;
+ } else
+ fputs(abso, gppsfile);
+ PS_relative_ok = TRUE;
+ ps_path_count += 1;
+
+ PS_pen_x = x;
+ PS_pen_y = y;
+}
+
+TERM_PUBLIC void
+PS_vector(unsigned int x, unsigned int y)
+{
+ char abso[5+2*INT_STR_LEN], rel[5+2*INT_STR_LEN];
+ int dx = x - PS_pen_x;
+ int dy = y - PS_pen_y;
+
+ if (dx==0 && dy==0)
+ return;
+
+ sprintf(abso, "%d %d L\n", x, y);
+ sprintf(rel, "%d %d V\n", dx, dy);
+
+ /* The following PS_move() is executed only when the limit of ps_path_count
+ * has been reached below: then PS_FLUSH_PATH has been called which has not
+ * moved to currentpoint after the stroke. */
+ if (!PS_relative_ok)
+ PS_move(PS_pen_x, PS_pen_y);
+
+ if (strlen(rel) < strlen(abso)) {
+ fputs(rel, gppsfile);
+ PS_taken++; /* only used for debug info */
+ ps_path_count += 1;
+ } else {
+ fputs(abso, gppsfile);
+ ps_path_count = 1; /* If we set it to zero, it may never get flushed */
+ }
+ /* Ghostscript has a "pile-up of rounding errors" bug: a sequence of many
+ * rmove's or rlineto's does not yield the same line as move's or lineto's.
+ * Therefore, we periodically force an update of the absolute position.
+ * There was a case when 400 rlineto's were too much, so let's go a little
+ * bit higher than the default function sampling rate in gnuplot.
+ * This runs into a second ghostscript bug, that mixing relative and absolute
+ * lineto with no intervening 'stroke' is ridiculously slow to render.
+ * So we stroke the partial line, update the position in absolute terms,
+ * then continue. This whole section can go away if ghostscript/gv is fixed.
+ */
+#define MAX_REL_PATHLEN 105
+ if (ps_path_count >= MAX_REL_PATHLEN) {
+ fprintf(gppsfile, "stroke %d %d M\n", x, y);
+ ps_path_count = 1;
+ }
+
+ PS_relative_ok = TRUE;
+ PS_pen_x = x;
+ PS_pen_y = y;
+}
+
+
+TERM_PUBLIC void
+PS_put_text(unsigned int x, unsigned int y, const char *str)
+{
+ char ch;
+
+ if (!str && !strlen(str))
+ return;
+ PS_move(x,y);
+ if (ps_ang != 0)
+ fprintf(gppsfile,"currentpoint gsave translate %d rotate 0 0 M\n",
+ ps_ang);
+ putc('(',gppsfile);
+ ch = *str++;
+ while(ch!='\0') {
+ if ((ch=='(') || (ch==')') || (ch=='\\'))
+ putc('\\', gppsfile);
+ putc(ch, gppsfile);
+ ch = *str++;
+ }
+
+ switch(ps_justify) {
+ case LEFT :
+ fputs(") Lshow\n", gppsfile);
+ break;
+ case CENTRE :
+ fputs(") Cshow\n", gppsfile);
+ break;
+ case RIGHT :
+ fputs(") Rshow\n", gppsfile);
+ break;
+ }
+ if (ps_ang != 0)
+ fputs("grestore\n", gppsfile);
+ ps_path_count = 0;
+ PS_relative_ok = FALSE;
+}
+
+
+TERM_PUBLIC int
+PS_text_angle(int ang)
+{
+ ps_ang = ang;
+ return TRUE;
+}
+
+
+TERM_PUBLIC int
+PS_justify_text(enum JUSTIFY mode)
+{
+ ps_justify = mode;
+ return TRUE;
+}
+
+
+TERM_PUBLIC int
+PS_set_font(const char *font)
+{
+ char *name;
+ unsigned int i;
+ float size;
+ size_t sep;
+
+ if (!font || !(*font))
+ font = PS_default_font;
+ sep = strcspn(font,",");
+ name = gp_strdup(font);
+ name[sep] = NUL;
+ for (i=0; i<sep; i++)
+ if (name[i] == ' ') name[i] = '-';
+ size = ps_fontsize;
+ if (font[sep] == ',')
+ sscanf (&(font[sep+1]),"%f",&size);
+
+ /* If TeX is doing the font handling, we don't need to */
+ /* write anything into the postscript stream */
+ if (ps_params->terminal == PSTERM_POSTSCRIPT) {
+ PS_RememberFont(name,1);
+ fprintf(gppsfile, "/%s findfont %g scalefont setfont\n",
+ name, size*PS_SC);
+ }
+ free(name);
+
+ term->v_char = (unsigned int)(size*PS_SC);
+ term->h_char = (unsigned int)(size*PS_SC*6/10);
+ return TRUE;
+}
+
+
+/* postscript point routines */
+
+
+TERM_PUBLIC void
+PS_point(unsigned int x, unsigned int y, int number)
+{
+ static const char GPFAR * GPFAR pointFNS[] = {
+ "Pnt", "Pls", "Crs", "Star",
+ "Box", "BoxF", "Circle", "CircleF",
+ "TriU", "TriUF", "TriD", "TriDF",
+ "Dia", "DiaF", "Pent", "PentF",
+ "C0", "C1", "C2", "C3",
+ "C4", "C5", "C6", "C7",
+ "C8", "C9", "C10", "C11",
+ "C12", "C13", "C14", "C15",
+ "S0", "S1", "S2", "S3",
+ "S4", "S5", "S6", "S7",
+ "S8", "S9", "S10", "S11",
+ "S12", "S13", "S14", "S15",
+ "D0", "D1", "D2", "D3",
+ "D4", "D5", "D6", "D7",
+ "D8", "D9", "D10", "D11",
+ "D12", "D13", "D14", "D15",
+ "BoxE", "CircE", "TriUE", "TriDE",
+ "DiaE", "PentE", "BoxW", "CircW",
+ "TriUW","TriDW", "DiaW", "PentW"
+ };
+ static const char GPFAR * GPFAR pointFNS_OldEPSL[] = {
+ "Pnt", "Dia", "Circle", "Pls",
+ "Crs", "Box", "DiaF", "CircleF",
+ "BoxF"
+ };
+ if ((ps_params->terminal == PSTERM_EPSLATEX) && ps_params->oldstyle) {
+ if (number < 0)
+ number = -1; /* negative types are all 'dot' */
+ else
+ number %= sizeof(pointFNS_OldEPSL)/sizeof(pointFNS_OldEPSL[0]) -1;
+ fprintf(gppsfile, "%d %d %s\n", x, y, pointFNS_OldEPSL[number+1]);
+ } else {
+ if (number < 0)
+ number = -1; /* negative types are all 'dot' */
+ else
+ number %= sizeof(pointFNS)/sizeof(pointFNS[0]) -1;
+ fprintf(gppsfile, "%d %d %s\n", x, y, pointFNS[number+1]);
+ }
+
+ PS_relative_ok = FALSE;
+ ps_path_count = 0;
+ PS_linewidth_last = PS_linetype_last = -1; /* force next linetype change */
+}
+
+TERM_PUBLIC void
+PS_fillbox(
+ int style,
+ unsigned int x1, unsigned int y1,
+ unsigned int width, unsigned int height)
+{
+ double filldens;
+ int pattern;
+
+ PS_FLUSH_PATH;
+
+ switch(style & 0xf) {
+
+ case FS_SOLID:
+ /* style == 1 --> fill with intensity according to filldensity */
+ filldens = (style >> 4) / 100.0;
+ if(filldens < 0.0)
+ filldens = 0.0;
+ if(filldens > 1.0)
+ filldens = 1.0;
+ fprintf(gppsfile, "%.3f %d %d %d %d BoxColFill\n",
+ filldens, x1,y1, width,height);
+ break;
+
+ case FS_PATTERN:
+ /* style == 2 --> fill with pattern according to fillpattern */
+ /* the upper 3 nibbles of 'style' contain pattern number */
+ pattern = (style >> 4) % 8;
+ switch (pattern) {
+
+ default:
+ case 0:
+ fprintf(gppsfile, "%d %d %d %d BoxFill\n",
+ x1, y1, width, height);
+ break;
+ case 1:
+ fprintf(gppsfile, "%d %d %d %d %d %d 1 PatternFill\n",
+ x1, y1, width, height, 80, -45);
+ break;
+ case 2:
+ fprintf(gppsfile, "%d %d %d %d %d %d 2 PatternFill\n",
+ x1, y1, width, height, 40, 45);
+ break;
+ case 3:
+ fprintf(gppsfile, "1 %d %d %d %d BoxColFill\n",
+ x1, y1, width, height);
+ break;
+ case 4:
+ fprintf(gppsfile, "%d %d %d %d %d %d 0 PatternFill\n",
+ x1, y1, width, height, 80, 45);
+ break;
+ case 5:
+ fprintf(gppsfile, "%d %d %d %d %d %d 0 PatternFill\n",
+ x1, y1, width, height, 80, -45);
+ break;
+ case 6:
+ fprintf(gppsfile, "%d %d %d %d %d %d 0 PatternFill\n",
+ x1, y1, width, height, 40, 30);
+ break;
+ case 7:
+ fprintf(gppsfile, "%d %d %d %d %d %d 0 PatternFill\n",
+ x1, y1, width, height, 40, -30);
+ break;
+ }
+ break; /* end of pattern filling part */
+
+ default: /* style == 0 or unknown --> fill with background color */
+ fprintf(gppsfile, "%d %d %d %d BoxFill\n", x1, y1, width, height);
+ }
+
+ PS_relative_ok = FALSE;
+ PS_linewidth_last = PS_linetype_last = -1;
+}
+
+
+/* ENHPOST */
+
+static TBOOLEAN ENHps_opened_string; /* try to cut out empty ()'s */
+
+/*
+ * close a postscript string if it has been opened
+ */
+TERM_PUBLIC void
+ENHPS_FLUSH()
+{
+ if (ENHps_opened_string) {
+ fputs(")]\n", gppsfile);
+ ENHps_opened_string = FALSE;
+ }
+}
+
+/*
+ * open a postscript string
+ */
+TERM_PUBLIC void
+ENHPS_OPEN(
+ char *fontname,
+ double fontsize, double base,
+ TBOOLEAN widthflag, TBOOLEAN showflag,
+ int overprint)
+{
+ /* overprint 3 means save current position; 4 means restore saved position */
+ /* EAM FIXME - I couldn't figure out how to use less than the 7 parameters */
+ /* that the normal case macro wants. Somebody more familiar with PostScript*/
+ /* than I am please clean it up! */
+ if (overprint == 3) {
+ fputs("XYsave\n", gppsfile);
+ return;
+ } else if (overprint == 4) {
+ fputs("XYrestore\n", gppsfile);
+ return;
+ }
+
+ if (!ENHps_opened_string) {
+ fprintf(gppsfile, "[(%s) %.1f %.1f %s %s %d (",
+ fontname, fontsize, base,
+ widthflag ? "true" : "false",
+ showflag ? "true" : "false",
+ overprint);
+ ENHps_opened_string = TRUE;
+ }
+}
+
+/*
+ * write one or more characters from inside enhanced text processing
+ */
+TERM_PUBLIC void
+ENHPS_WRITEC(int c)
+{
+ fputc(c, gppsfile);
+}
+
+/* a set-font routine for enhanced post : simply copies
+ * the font into a global, or restores the globals
+ * to the ps_params->font default
+ */
+
+TERM_PUBLIC int
+ENHPS_set_font(const char *font)
+{
+ if (ignore_enhanced_text)
+ return PS_set_font(font);
+
+ if (*font) {
+ size_t sep = strcspn(font,",");
+ if (sep > 0) {
+ strncpy(ps_enh_font,font,sep);
+ ps_enh_font[sep] = NUL;
+ PS_RememberFont(ps_enh_font, 1);
+ }
+ ps_enh_fontsize = ps_fontsize;
+ sscanf (font+sep+1,"%f",&ps_enh_fontsize);
+ } else {
+ /* return to defaults */
+ strcpy(ps_enh_font, ps_params->font);
+ ps_enh_fontsize = ps_fontsize;
+ }
+ term->v_char = (unsigned int)(ps_enh_fontsize*PS_SC);
+ term->h_char = (unsigned int)(ps_enh_fontsize*PS_SC*6/10);
+
+ return TRUE;
+}
+
+TERM_PUBLIC void
+ENHPS_put_text(unsigned int x, unsigned int y, const char *str)
+{
+ if (ignore_enhanced_text) {
+ PS_put_text(x,y,str);
+ return;
+ }
+
+ /* flush any pending graphics (all the XShow routines do this...) */
+
+ if (!strlen(str))
+ return;
+
+ PS_FLUSH_PATH;
+
+ /* if there are no magic characters, we should just be able
+ * punt the string to PS_put_text(), which will give shorter
+ * ps output [eg tics and stuff rarely need extra processing],
+ * but we need to make sure that the current font is the
+ * default one before we can do that. {ie I tried it and it
+ * used the wrong font !}
+ * if (!strpbrk(str, "{}^_@&~"))
+ * {
+ * - do something to ensure default font is selected
+ * PS_put_text(x,y,str);
+ * return;
+ * }
+ */
+
+ PS_move(x,y);
+
+ if (ps_ang != 0)
+ fprintf(gppsfile,"currentpoint gsave translate %d rotate 0 0 moveto\n",
+ ps_ang);
+
+ fputs("[ ", gppsfile);
+
+ /* set up the global variables needed by enhanced_recursion() */
+ enhanced_max_height = -1000;
+ enhanced_min_height = 1000;
+ enhanced_fontscale = PS_SC;
+ strncpy(enhanced_escape_format,"\\%o",sizeof(enhanced_escape_format));
+
+ ENHps_opened_string = FALSE;
+
+ /* Set the recursion going. We say to keep going until a
+ * closing brace, but we don't really expect to find one.
+ * If the return value is not the nul-terminator of the
+ * string, that can only mean that we did find an unmatched
+ * closing brace in the string. We increment past it (else
+ * we get stuck in an infinite loop) and try again.
+ *
+ * ps_enh_font and ps_enh_fontsize are either set to the
+ * the defaults set on option line, or have been set to
+ * "font,size". That is to say, ps_params->font is used only
+ * at startup and by ENHPS_set_font
+ */
+ while (*(str = enhanced_recursion((char *)str, TRUE, ps_enh_font,
+ (double)(ps_enh_fontsize*PS_SC), 0.0, TRUE, TRUE, 0))) {
+ ENHPS_FLUSH();
+
+ /* I think we can only get here if *str == '}' */
+ enh_err_check(str);
+
+ if (!*++str)
+ break; /* end of string */
+
+ /* else carry on and process the rest of the string */
+ }
+
+ enhanced_max_height += enhanced_min_height;
+
+ fprintf(gppsfile, "] %.1f ", -enhanced_max_height/3);
+
+ switch(ps_justify) {
+ case LEFT :
+ fputs("MLshow\n", gppsfile);
+ break;
+ case CENTRE :
+ fputs("MCshow\n", gppsfile);
+ break;
+ case RIGHT :
+ fputs("MRshow\n", gppsfile);
+ break;
+ }
+
+ if (ps_ang != 0)
+ fputs("grestore\n", gppsfile);
+ ps_path_count = 0;
+ PS_relative_ok = FALSE;
+}
+
+static void
+make_palette_formulae()
+{
+#define R sm_palette.formulaR
+#define G sm_palette.formulaG
+#define B sm_palette.formulaB
+/* print the definition of R,G,B formulae */
+ fputs("/InterpolatedColor false def\n", gppsfile);
+if (sm_palette.ps_allcF == 0) { /* print only those 3 used formulae */
+ fprintf(gppsfile, "/cF%i {%s} bind def\t%% %s\n",
+ abs(R), ps_math_color_formulae[ 2*abs(R) ],
+ ps_math_color_formulae[ 2*abs(R)+1 ]);
+ if (abs(G) != abs(R))
+ fprintf(gppsfile, "/cF%i {%s} bind def\t%% %s\n",
+ abs(G), ps_math_color_formulae[ 2*abs(G) ],
+ ps_math_color_formulae[ 2*abs(G)+1 ]);
+ if ((abs(B) != abs(R)) && (abs(B) != abs(G)))
+ fprintf(gppsfile, "/cF%i {%s} bind def\t%% %s\n",
+ abs(B), ps_math_color_formulae[ 2*abs(B) ],
+ ps_math_color_formulae[ 2*abs(B)+1 ]);
+ }
+ else { /* all color formulae are written into the output PostScript file */
+ int i = 0;
+ while (*(ps_math_color_formulae[2*i])) {
+ fprintf(gppsfile, "/cF%i {%s} bind def\t%% %s\n",
+ i, ps_math_color_formulae[ 2*i ],
+ ps_math_color_formulae[ 2*i+1 ]);
+ i++;
+ }
+ }
+#undef R
+#undef G
+#undef B
+}
+
+
+
+static void
+make_interpolation_code()
+{
+ static const char *header[] = {
+ "/grayindex {/gidx 0 def\n",
+ " {GrayA gidx get grayv ge {exit} if /gidx gidx 1 add def} loop} def\n",
+ "/dgdx {grayv GrayA gidx get sub GrayA gidx 1 sub get\n",
+ " GrayA gidx get sub div} def \n",
+ "/redvalue {RedA gidx get RedA gidx 1 sub get\n",
+ " RedA gidx get sub dgdxval mul add} def\n",
+ "/greenvalue {GreenA gidx get GreenA gidx 1 sub get\n",
+ " GreenA gidx get sub dgdxval mul add} def\n",
+ "/bluevalue {BlueA gidx get BlueA gidx 1 sub get\n",
+ " BlueA gidx get sub dgdxval mul add} def\n",
+ "/interpolate {\n",
+ " grayindex grayv GrayA gidx get sub abs 1e-5 le\n",
+ " {RedA gidx get GreenA gidx get BlueA gidx get}\n",
+ " {/dgdxval dgdx def redvalue greenvalue bluevalue} ifelse} def\n",
+ NULL,
+ };
+ int i;
+
+ for(i=0; header[i]!=NULL; ++i) {
+ fputs(header[i], gppsfile);
+ }
+}
+
+
+static void
+make_color_model_code()
+{
+ /* Postscript version of the color space transformations in getcolor.c */
+ static const char *header[] = {
+ "/HSV2RGB {",
+ " exch dup 0.0 eq {pop exch pop dup dup} % achromatic gray\n",
+ " { /HSVs exch def /HSVv exch def 6.0 mul dup floor dup 3 1 roll sub\n ",
+ " /HSVf exch def /HSVi exch cvi def /HSVp HSVv 1.0 HSVs sub mul def\n",
+ " /HSVq HSVv 1.0 HSVs HSVf mul sub mul def \n",
+ " /HSVt HSVv 1.0 HSVs 1.0 HSVf sub mul sub mul def\n",
+ " /HSVi HSVi 6 mod def 0 HSVi eq {HSVv HSVt HSVp}\n",
+ " {1 HSVi eq {HSVq HSVv HSVp}{2 HSVi eq {HSVp HSVv HSVt}\n",
+ " {3 HSVi eq {HSVp HSVq HSVv}{4 HSVi eq {HSVt HSVp HSVv}\n",
+ " {HSVv HSVp HSVq} ifelse} ifelse} ifelse} ifelse} ifelse\n",
+ " } ifelse} def\n",
+ "/Constrain {\n",
+ " dup 0 lt {0 exch pop}{dup 1 gt {1 exch pop} if} ifelse} def\n",
+ "/YIQ2RGB {\n",
+ " 3 copy -1.702 mul exch -1.105 mul add add Constrain 4 1 roll\n",
+ " 3 copy -0.647 mul exch -0.272 mul add add Constrain 5 1 roll\n",
+ " 0.621 mul exch -0.956 mul add add Constrain 3 1 roll } def\n",
+ "/CMY2RGB {",
+ " 1 exch sub exch 1 exch sub 3 2 roll 1 exch sub 3 1 roll exch } def\n",
+ "/XYZ2RGB {",
+ " 3 copy -0.9017 mul exch -0.1187 mul add exch 0.0585 mul exch add\n",
+ " Constrain 4 1 roll 3 copy -0.0279 mul exch 1.999 mul add exch\n",
+ " -0.9844 mul add Constrain 5 1 roll -0.2891 mul exch -0.5338 mul add\n",
+ " exch 1.91 mul exch add Constrain 3 1 roll} def\n",
+ "/SelectSpace {ColorSpace (HSV) eq {HSV2RGB}{ColorSpace (XYZ) eq {\n",
+ " XYZ2RGB}{ColorSpace (CMY) eq {CMY2RGB}{ColorSpace (YIQ) eq {YIQ2RGB}\n",
+ " if} ifelse} ifelse} ifelse} def\n",
+ NULL,
+ };
+ int i;
+
+ for(i=0; header[i]!=NULL; ++i) {
+ fputs(header[i], gppsfile);
+ }
+}
+
+
+static char
+*save_space(double gray)
+{
+ /* printing the gray with 4 digits and without the leading 0
+ * ... saving space */
+ static char s[40];
+
+ gray = 0.0001*(int)(gray*10000+0.5); /* round it to 4 digits */
+ sprintf(s, "%.4g", gray);
+ if (s[0] == '0' && s[1] == '.')
+ return &(s[1]); /* strip leading 0 */
+ else
+ return s;
+}
+
+
+static void
+write_color_space(t_sm_palette *palette)
+{
+ /* write something like
+ * /ColorSpace (HSV) def
+ * depending on the selected cmodel in palette */
+ fputs("/ColorSpace ", gppsfile);
+ switch(palette->cmodel) {
+ case C_MODEL_RGB:
+ fputs("(RGB)", gppsfile);
+ break;
+ case C_MODEL_HSV:
+ fputs("(HSV)", gppsfile);
+ break;
+ case C_MODEL_CMY:
+ fputs("(CMY)", gppsfile);
+ break;
+ case C_MODEL_YIQ:
+ fputs("(YIQ)", gppsfile);
+ break;
+ case C_MODEL_XYZ:
+ fputs("(XYZ)", gppsfile);
+ break;
+ default:
+ fprintf(stderr,"%s:%d ooops: Unkown color model '%c'. Will be RGB\n",
+ __FILE__, __LINE__, (char)(palette->cmodel));
+ fputs("(RGB)", gppsfile);
+ break;
+ }
+ fputs(" def\n", gppsfile);
+}
+
+
+static void
+write_component_array(const char *text, gradient_struct *grad,
+ int cnt, int offset)
+{
+ /* write someting like
+ * /RedA [ 0 .1 .2 .3 .35 .3 .2 .1 0 0 0 ] def
+ * nicely formated to gppsfile
+ */
+ int i=0, len=0;
+ char *val;
+
+ fprintf(gppsfile, "/%s [", text);
+ len = strlen(text) + 4;
+ for(i=0; i<cnt; ++i) {
+ char *ref = (char*)(&(grad[i]));
+
+ ref += offset;
+ val = save_space(*((double*) (ref)));
+ len += strlen(val) + 1;
+ if(len > 77) {
+ fputs("\n ",gppsfile);
+ len = strlen(val) + 3;
+ }
+ fprintf(gppsfile, "%s ", val);
+ }
+ fputs("] def\n", gppsfile);
+}
+
+
+static void
+write_gradient_definition(gradient_struct *gradient, int cnt)
+{
+ /* some strange pointer acrobatic here, but it seems to work... */
+ char *ref = (char*) (gradient);
+ int p = (char*) (&(gradient[0].pos)) - ref;
+ int r = (char*) (&(gradient[0].col.r)) - ref;
+ int g = (char*) (&(gradient[0].col.g)) - ref;
+ int b = (char*) (&(gradient[0].col.b)) - ref;
+
+ write_component_array("GrayA", gradient, cnt, p);
+ write_component_array("RedA", gradient, cnt, r);
+ write_component_array("GreenA", gradient, cnt, g);
+ write_component_array("BlueA", gradient, cnt, b);
+}
+
+
+static void
+PS_make_header(t_sm_palette *palette)
+{
+ /* write header for smooth colors */
+ fputs("gsave % colour palette begin\n", gppsfile);
+ fprintf(gppsfile, "/maxcolors %i def\n", sm_palette.use_maxcolors);
+ make_color_model_code();
+
+ switch(sm_palette.colorMode) {
+ case SMPAL_COLOR_MODE_GRAY:
+ fputs("/InterpolatedColor false def\n", gppsfile);
+ break; /* nothing to do for gray */
+ case SMPAL_COLOR_MODE_RGB:
+ make_palette_formulae();
+ break;
+ case SMPAL_COLOR_MODE_FUNCTIONS: {
+ int cnt=0;
+ gradient_struct *gradient;
+
+ fputs("/InterpolatedColor true def\n", gppsfile);
+ make_interpolation_code();
+ gradient = approximate_palette(palette, ps_params->palfunc_samples,
+ ps_params->palfunc_deviation, &cnt);
+ write_gradient_definition(gradient, cnt);
+ free(gradient);
+ break;
+ }
+ case SMPAL_COLOR_MODE_GRADIENT:
+ fputs("/InterpolatedColor true def\n", gppsfile);
+ make_interpolation_code();
+ write_gradient_definition(palette->gradient, palette->gradient_num);
+ break;
+ default:
+ fprintf(stderr, "%s:%d ooops: Unknown color mode '%c'\n",
+ __FILE__, __LINE__, (char)(sm_palette.colorMode));
+ }
+ fputs("/pm3dround {maxcolors 0 gt {dup 1 ge\n", gppsfile);
+ fputs("\t{pop 1} {maxcolors mul floor maxcolors 1 sub div} ifelse} if} def\n",
+ gppsfile);
+ fprintf(gppsfile, "/pm3dGamma 1.0 %g div def\n", sm_palette.gamma);
+ write_color_space(palette);
+
+/* Now print something like
+ /g {dup cF7 exch dup cF5 exch cF15 setrgbcolor} bind def
+*/
+#define R sm_palette.formulaR
+#define G sm_palette.formulaG
+#define B sm_palette.formulaB
+
+/* 18.1.2009 Since the beginning of pm3d, the Color definition switched
+ between gray and colour map. This led to ambiguities for custom colour
+ palettes if they contain grays only. Thus let postscript choose always
+ always colour palette for interpolated colours ('set palette defined',
+ 'set palette file') and colour/gray according to Color otherwise
+ ('set palette gray', 'set palette rgb').
+*/
+#if 0
+ fprintf(gppsfile, "Color %s and { %% COLOUR vs. GRAY map\n",
+ (sm_palette.colorMode!=SMPAL_COLOR_MODE_GRAY) ? "true":"false");
+#else
+ if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY)
+ fputs("false { % COLOUR vs. GRAY map\n", gppsfile);
+ else
+ fputs("Color InterpolatedColor or { % COLOUR vs. GRAY map\n", gppsfile);
+#endif
+
+ fputs(" InterpolatedColor { %% Interpolation vs. RGB-Formula\n",
+ gppsfile);
+ fputs(" /g {stroke pm3dround /grayv exch def interpolate\n", gppsfile);
+ fputs(" SelectSpace setrgbcolor} bind def\n", gppsfile);
+ fputs(" }{\n", gppsfile);
+ fputs(" /g {stroke pm3dround dup ", gppsfile);
+ if (R < 0)
+ fputs("1 exch sub ", gppsfile); /* negate */
+ fprintf(gppsfile,"cF%i Constrain exch dup ", abs(R));
+ if (G < 0)
+ fputs("1 exch sub ", gppsfile); /* negate */
+ fprintf(gppsfile,"cF%i Constrain exch ", abs(G));
+ if (R<0 || G<0 || B<0)
+ fputs("\n\t", gppsfile);
+ if (B < 0)
+ fputs("1 exch sub ", gppsfile); /* negate */
+ fprintf(gppsfile,"cF%i Constrain ", abs(B));
+ fputs("\n SelectSpace setrgbcolor} bind def\n", gppsfile);
+ fputs(" } ifelse\n", gppsfile);
+ fputs("}{\n", gppsfile);
+ fputs(" /g {stroke pm3dround pm3dGamma exp setgray} bind def\n", gppsfile);
+ fputs("} ifelse\n", gppsfile);
+#undef R
+#undef G
+#undef B
+}
+
+
+TERM_PUBLIC int PS_make_palette (t_sm_palette *palette)
+{
+ if (palette == NULL) {
+ return 0; /* postscript can do continuous colors */
+ }
+
+ PS_make_header(palette);
+ return 0;
+}
+
+
+TERM_PUBLIC void PS_set_color (t_colorspec *colorspec)
+{
+ double gray;
+
+ PS_linetype_last = -1; /* Force next call to linetype to be honored */
+
+ if (colorspec->type == TC_LT) {
+ int linetype = colorspec->lt;
+ PS_FLUSH_PATH;
+ if ((ps_params->terminal == PSTERM_EPSLATEX) && ps_params->oldstyle)
+ linetype = (linetype % 4) + 3;
+ else
+ linetype = (linetype % 9) + 3;
+ if (linetype < 0) /* LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED */
+ linetype = 0;
+ fprintf(gppsfile, "LC%1c setrgbcolor\n","wba012345678"[linetype]);
+ } else if (colorspec->type == TC_RGB) {
+ double r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
+ double g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
+ double b = (double)(colorspec->lt & 255) / 255.;
+ PS_FLUSH_PATH;
+ fprintf(gppsfile, "%3.2f %3.2f %3.2f C ",r,g,b);
+ }
+
+ if (colorspec->type != TC_FRAC)
+ return;
+
+/* map [0;1] to gray/colors */
+ gray = colorspec->value;
+ if (gray <= 0)
+ fputs("0 g ", gppsfile);
+ else {
+ if (gray >= 1)
+ fputs("1 g ", gppsfile);
+ else
+ fprintf(gppsfile, "%s g ", save_space(gray));
+ }
+ PS_relative_ok = FALSE; /* "M" required because "g" forces stroke (??) */
+}
+
+
+TERM_PUBLIC void PS_filled_polygon (int points, gpiPoint *corners)
+{
+ int i;
+ float filldens = 1.0;
+ int pattern = 0;
+ int style = corners->style;
+
+ /* Stroke the previous graphic element if required. */
+ if (PS_relative_ok)
+ PS_FLUSH_PATH;
+
+ if (points == 4 && style == FS_OPAQUE) {
+ /* Special case for pm3d surface quadrangles
+ * <x0> <y0> ... <x4> <y4> h
+ */
+ fprintf(gppsfile, "%i %i N", corners[0].x, corners[0].y);
+ fprintf(gppsfile, " %i %i %i %i %i %i h\n",
+ corners[3].x-corners[2].x, corners[3].y-corners[2].y,
+ corners[2].x-corners[1].x, corners[2].y-corners[1].y,
+ corners[1].x-corners[0].x, corners[1].y-corners[0].y);
+ } else {
+ /* General case for solid or pattern-filled polygons
+ * gsave <x0> <y0> N <x1> <y1> ... <xn> <yn> density PolyFill
+ */
+ fprintf(gppsfile, "gsave ");
+ fprintf(gppsfile, "%i %i N", corners[0].x, corners[0].y);
+ for (i = 1; i < points; i++) {
+ /* The rationale for mixing V and L is given in PS_vector */
+ if (i % MAX_REL_PATHLEN)
+ fprintf(gppsfile, " %i %i V", corners[i].x-corners[i-1].x,
+ corners[i].y-corners[i-1].y);
+ else
+ fprintf(gppsfile, " %i %i L", corners[i].x, corners[i].y);
+ }
+
+ switch(style & 0xf) {
+
+ case FS_SOLID:
+ filldens = (style >> 4) / 100.0;
+ if(filldens < 0.0)
+ filldens = 0.0;
+ if(filldens >= 1.0)
+ fprintf(gppsfile, " 1 PolyFill\n");
+ else
+ fprintf(gppsfile, " %.2f PolyFill\n", filldens);
+ break;
+
+ case FS_PATTERN:
+ pattern = (style >> 4) % 8;
+ if (pattern == 0) {
+ filldens = 0.5;
+ fprintf(gppsfile, " %.1f PolyFill\n", filldens);
+ } else {
+ fprintf(gppsfile," Pattern%d fill grestore\n", pattern);
+ }
+ break;
+
+ default:
+ fputs(" 1 PolyFill\n", gppsfile);
+ break;
+
+ }
+ }
+
+ PS_relative_ok = FALSE;
+}
+
+#undef MAX_REL_PATHLEN
+
+TERM_PUBLIC void PS_previous_palette()
+{
+ /* Needed to stroke the previous graphic element. */
+ PS_FLUSH_PATH;
+ fputs("grestore % colour palette end\n", gppsfile);
+}
+
+
+/*
+ * The reason for having a PostScript-specific wrapper for do_arrow
+ * is that post.trm draws dotted lines for monochrome output, and
+ * dotted arrowheads are ugly. So in that case we call do_arrow twice,
+ * the second time to retrace the head with the line style forced to solid.
+ */
+TERM_PUBLIC void PS_arrow (
+ unsigned int sx, unsigned int sy,
+ unsigned int ex, unsigned int ey,
+ int head)
+{
+ do_arrow( sx, sy, ex, ey, head );
+ if (!ps_params->solid && head != 0) {
+ PS_FLUSH_PATH;
+ fputs("gsave [] 0 setdash\n", gppsfile);
+ do_arrow( sx, sy, ex, ey, -head );
+ PS_FLUSH_PATH;
+ fputs("grestore\n", gppsfile);
+ }
+}
+
+static void
+delete_ps_fontfile(struct ps_fontfile_def *prev, struct ps_fontfile_def *this)
+{
+ if (this != NULL) { /* there really is something to delete */
+ FPRINTF((stderr, "Remove font/kerning file `%s'\n",
+ this->fontfile_name));
+ if (prev != NULL) /* there is a previous ps_fontfile */
+ prev->next = this->next;
+ else /* this = ps_params->first_fontfile */
+ /* so change ps_params->first_fontfile */
+ ps_params->first_fontfile = this->next;
+ free(this->fontfile_name);
+ free(this->fontfile_fullname);
+ free(this);
+ this = NULL;
+ }
+}
+
+
+#ifdef WITH_IMAGE
+
+static void
+PS_encode85(unsigned long tuple4, unsigned char *tuple5)
+{
+ /* The compiler should know to carry out the powers of
+ * 85 computation at compilation time.
+ */
+ tuple5[0] = tuple4/(85*85*85*85);
+ tuple4 -= ((unsigned long)tuple5[0])*(85*85*85*85);
+ tuple5[1] = tuple4/(85*85*85);
+ tuple4 -= ((unsigned long)tuple5[1])*(85*85*85);
+ tuple5[2] = tuple4/(85*85);
+ tuple4 -= ((unsigned long)tuple5[2])*(85*85);
+ tuple5[3] = tuple4/(85);
+ tuple4 -= ((unsigned long)tuple5[3])*(85);
+ tuple5[4] = tuple4;
+}
+
+enum PS_ENCODING {
+ PS_ASCII_HEX,
+ PS_ASCII85
+} PS_ENCODING;
+
+/* Returns pointer to encoded image, allocated on heap that the
+ * caller must free. Can error to command line so make sure all
+ * heap memory is recorded in static pointers when calling this
+ * routine.
+ */
+static char *
+PS_encode_image(unsigned M, unsigned N, coordval *image, t_imagecolor color_mode,
+ int bits_per_component, int max_colors, double cscale,
+ enum PS_ENCODING encoding, int *return_num_bytes)
+{
+ unsigned coord_remaining;
+ coordval *coord_ptr;
+ unsigned short i_line;
+ unsigned i_element;
+ unsigned end_of_line;
+ unsigned short bits_remaining, bits_start;
+
+ unsigned long tuple4;
+ unsigned char tuple5[5];
+ int max_encoded_bytes;
+ char *encoded_image, *encoded_image_ptr;
+ unsigned long total_bits;
+
+#define ASCII_PER_LINE 78
+
+ /* 18.1.2009 RGB images ("plot ... with rgbimage") are drawn always in color,
+ * i.e. for both "set term post color" and "set term post mono".
+ */
+ total_bits = bits_per_component*M*N*((color_mode == IC_RGB /* && ps_params->color */) ? 3 : 1);
+
+ /* At the end of each image line, data is aligned to the nearest 8 bits,
+ * which means potentially adding 7 bits per line.
+ */
+ end_of_line = M;
+ total_bits += N*7;
+
+ /* Compute max number of ascii characters encoding will require.
+ */
+ if (encoding == PS_ASCII_HEX) {
+ /* Straight hex encoding */
+ max_encoded_bytes = (total_bits/4 + 1);
+ max_encoded_bytes += max_encoded_bytes / ASCII_PER_LINE; /* newline characters */
+ } else {
+ /* ASCII85 encoding */
+ max_encoded_bytes = (total_bits/32 + 1)*5 + 2; /* 5 tuples and additional ~> */
+ max_encoded_bytes += max_encoded_bytes / ASCII_PER_LINE; /* newline characters */
+ }
+
+ /* Reserve enough memory. */
+ if (!(encoded_image = gp_alloc(max_encoded_bytes, "encoded image")))
+ int_error(NO_CARET, "GNUPLOT (post.trm): Error allocating memory.\n");
+ encoded_image_ptr = encoded_image;
+
+ coord_ptr = image;
+ i_line = ASCII_PER_LINE;
+ i_element = 0;
+ coord_remaining = M*N;
+ if (color_mode == IC_RGB /* && ps_params->color */) {
+ end_of_line *= 3;
+ coord_remaining *= 3;
+ }
+ bits_remaining = 32;
+ bits_start = 0;
+ tuple4 = 0;
+
+ while (coord_remaining) {
+ unsigned short us_tmp;
+ if (0 /* color_mode == IC_RGB && !ps_params->color */) {
+ coordval c_tmp;
+ c_tmp = *coord_ptr++;
+ c_tmp += *coord_ptr++;
+ c_tmp += *coord_ptr++;
+ us_tmp = (unsigned short) (c_tmp*(max_colors-1)/3.0 + 0.5);
+ } else
+ us_tmp = (unsigned short) ((*coord_ptr++) * max_colors);
+
+ if (us_tmp > (max_colors-1)) us_tmp = max_colors-1;
+
+ /* Rescale to accommodate a mismatch between max_colors and # of bits */
+ us_tmp *= cscale;
+
+ if (bits_remaining < bits_per_component) {
+ tuple4 <<= bits_remaining;
+ bits_start = bits_per_component - bits_remaining;
+ bits_remaining = 0;
+ tuple4 |= (us_tmp >> bits_start);
+ } else {
+ tuple4 <<= bits_per_component;
+ tuple4 |= us_tmp;
+ bits_remaining -= bits_per_component;
+ }
+
+ /* If this is last pixel in line, pad to nearest 8 bits. */
+ i_element++;
+ if (i_element == end_of_line) {
+ register unsigned short bit_align = (bits_remaining & 0x7);
+ tuple4 <<= bit_align;
+ bits_remaining -= bit_align;
+ i_element = 0;
+ }
+
+ /* Check if another 4-tuple is complete. */
+ if (!bits_remaining) {
+ if (ps_params->level1) {
+ /* A straight hex encoding for every 4 bits. */
+ unsigned char tuple8[8];
+ int i;
+ for (i=7; i >= 0; i--) {
+ tuple8[i] = tuple4 & 0xf;
+ tuple4 >>= 4;
+ }
+ for (i=0; i < 8; i++) {
+ sprintf(encoded_image_ptr++, "%1x", tuple8[i]);
+ i_line--;
+ if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
+ }
+ } else {
+ /* Convert to ASCII85 representation. */
+ if (tuple4) {
+ int i;
+ PS_encode85(tuple4, tuple5);
+ tuple4 = 0;
+ for (i=0; i < 5; i++) {
+ sprintf(encoded_image_ptr++, "%c", tuple5[i]+'!');
+ i_line--;
+ if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
+ }
+ } else {
+ *encoded_image_ptr++ = 'z';
+ i_line--;
+ if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
+ }
+ }
+
+ /* Now pick up any bits that may have not made it into the 4-tuple. */
+ if (bits_start) {tuple4 = us_tmp - ((us_tmp>>bits_start)<<bits_start);}
+ bits_remaining = 32 - bits_start;
+ bits_start = 0;
+
+ }
+
+ coord_remaining--;
+
+ }
+
+ if (bits_remaining < 32) {
+ int i;
+ int n = 4 - bits_remaining/8;
+ if (ps_params->level1) {
+ /* A straight hex encoding for every 4 bits. */
+ unsigned char tuple8[8];
+ for (i=2*n-1; i >= 0; i--) {
+ tuple8[i] = tuple4 & 0xf;
+ tuple4 >>= 4;
+ }
+ for (i=0; i < 2*n; i++) {
+ sprintf(encoded_image_ptr++, "%1x", tuple8[i]);
+ i_line--;
+ if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
+ }
+ } else {
+ /* Convert to ASCII85 representation.
+ *
+ * The case where not all bytes in a tuple are used is slightly different.
+ * There is no use of 'z' as a special character and the remaining bytes
+ * need to be filled. Then use only a portion of the final 5-tuple.
+ */
+ tuple4 <<= bits_remaining;
+ PS_encode85(tuple4, tuple5);
+ /* Write first n+1 bytes. */
+ for (i=0; i <= n; i++) {
+ sprintf(encoded_image_ptr++, "%c", tuple5[i]+'!');
+ i_line--;
+ if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
+ }
+ }
+ }
+
+ if (!ps_params->level1) {
+ sprintf(encoded_image_ptr, "~>");
+ encoded_image_ptr += 2;
+ }
+
+ *return_num_bytes = (encoded_image_ptr - encoded_image);
+ assert(*return_num_bytes <= max_encoded_bytes);
+ return encoded_image;
+}
+
+
+static void
+print_five_operand_image(unsigned M, unsigned N, gpiPoint *corner, t_imagecolor color_mode, unsigned short bits_per_component)
+{
+ char *space = ps_params->level1 ? "" : " ";
+
+ fprintf(gppsfile, "%sgsave\n", space);
+ if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY)
+ fprintf(gppsfile, "%s{pm3dGamma exp} settransfer\n", space);
+ fprintf(gppsfile, "%s%d %d translate\n", space, corner[0].x, corner[0].y);
+ fprintf(gppsfile, "%s%d %d scale\n", space, (corner[1].x - corner[0].x), (corner[1].y - corner[0].y));
+ fprintf(gppsfile, "%s%d %d %d\n", space, M, N, bits_per_component);
+ fprintf(gppsfile, "%s[ %d 0 0 %d 0 0 ]\n", space, M, N);
+ if (ps_params->level1) {
+ fprintf(gppsfile, "/imagebuf %d string def\n",
+ (M*N*bits_per_component*((color_mode == IC_RGB /* && ps_params->color */) ? 3 : 1) + 7)/8);
+ fputs("{currentfile imagebuf readhexstring pop}\n", gppsfile);
+ } else
+ fprintf(gppsfile, " currentfile /ASCII85Decode filter\n");
+ if (color_mode == IC_RGB /* && ps_params->color */) {
+ fprintf(gppsfile, "%sfalse 3\n"
+ "%scolorimage\n", space, space);
+ } else
+ fprintf(gppsfile, "%simage\n", space);
+}
+
+
+TERM_PUBLIC void
+PS_image (unsigned M, unsigned N, coordval *image, gpiPoint *corner, t_imagecolor color_mode)
+{
+ char *encoded_image;
+ int num_encoded_bytes;
+ unsigned short bits_per_component = 0;
+ int max_colors, i_tmp;
+ TBOOLEAN five_operand_image;
+ double cscale;
+
+#define DEFAULT_BITS_PER_COMPONENT 8
+#define DEFAULT_COMPONENT_MAX (1<<DEFAULT_BITS_PER_COMPONENT)
+
+ if (sm_palette.use_maxcolors > 0)
+ max_colors = sm_palette.use_maxcolors;
+ else
+ max_colors = DEFAULT_COMPONENT_MAX;
+
+ i_tmp = 1;
+ while (i_tmp < max_colors) {
+ bits_per_component++;
+ i_tmp <<= 1;
+ }
+
+ if (bits_per_component < 1 || bits_per_component > 12) {
+ fprintf(stderr, "GNUPLOT (post.trm): Component bits (%d) out of range.\n", bits_per_component);
+ return;
+ }
+
+ if (bits_per_component > 8)
+ bits_per_component = 12;
+ else if (bits_per_component > 4)
+ bits_per_component = 8;
+ else if (bits_per_component > 2)
+ bits_per_component = 4;
+
+ /* Color and gray scale images do not need a palette and can use
+ * the 5 operand form of the image routine.
+ */
+#if 0
+ /* 18.1.2009 It was decided to use the custom palette (i.e. colours) also
+ for the monochrome postscript output.
+ */
+ if ((color_mode == IC_RGB) || (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY) || !ps_params->color)
+#else
+ if ((color_mode == IC_RGB) || (sm_palette.colorMode == SMPAL_COLOR_MODE_RGB && !ps_params->color) || (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY))
+#endif
+ five_operand_image = TRUE;
+ else
+ five_operand_image = FALSE;
+
+ /* The five operand image doesn't have a palette and the values are
+ * such that 0 maps to 0.0 and 2^bits_per_component - 1 maps to 1.0
+ * in the PostScript driver. Without any other knowledge, we scale
+ * things so that our max colors corresponds to 1.0.
+ */
+ if (five_operand_image)
+ cscale = (float)((1 << bits_per_component)-1) / (float)(max_colors-1);
+ else
+ cscale = 1.0;
+
+ encoded_image = PS_encode_image(M, N, image, color_mode,
+ bits_per_component, max_colors, cscale,
+ (ps_params->level1 ? PS_ASCII_HEX : PS_ASCII85), &num_encoded_bytes);
+
+ fputs("%%%%BeginImage\n", gppsfile);
+
+ /* Clip image to requested bounding box */
+ fprintf(gppsfile,"gsave %d %d N %d %d L %d %d L %d %d L Z clip\n",
+ corner[2].x, corner[2].y, corner[2].x, corner[3].y, corner[3].x, corner[3].y, corner[3].x, corner[2].y);
+
+ /* Color and gray scale images do not need a palette and can use
+ * the 5 operand form of the image routine. For other types of
+ * palettes, the 1 operand form of the image routine must be used
+ * and an indexed palette needs to be constructed.
+ */
+ if (five_operand_image) {
+
+ if (ps_params->level1) {
+ print_five_operand_image(M, N, corner, color_mode, bits_per_component);
+ } else {
+ fputs("InterpretLevel1 {\n"
+ " %% Construct a box instead of image\n"
+ " LTb\n", gppsfile);
+ fprintf(gppsfile, " %d %d M\n", corner[0].x, corner[0].y);
+ fprintf(gppsfile, " %d 0 V\n", (corner[1].x - corner[0].x));
+ fprintf(gppsfile, " 0 %d V\n", (corner[1].y - corner[0].y));
+ fprintf(gppsfile, " %d 0 V\n", -(corner[1].x - corner[0].x));
+ fprintf(gppsfile, " %d %d L\n", corner[0].x, corner[0].y);
+ fputs(" 40 -110 R\n"
+ " (PS level 2 image) Lshow\n"
+ " % Read data but ignore it\n", gppsfile);
+ fprintf(gppsfile, " /imagebuf %d string def\n", num_encoded_bytes);
+ fputs(" currentfile imagebuf readstring\n"
+ "} {\n", gppsfile);
+ print_five_operand_image(M, N, corner, color_mode, bits_per_component);
+ fputs("} ifelse\n", gppsfile);
+ }
+
+ }
+ else {
+
+ int allocated;
+ unsigned short i_tuple;
+ double fact = 1.0 / (double)(max_colors-1);
+ if (!ps_params->level1) {
+ fputs("InterpretLevel1 {\n"
+ " %% Construct a box instead of image\n"
+ " LTb\n", gppsfile);
+ fprintf(gppsfile, " %d %d M\n", corner[0].x, corner[0].y);
+ fprintf(gppsfile, " %d 0 V\n", (corner[1].x - corner[0].x));
+ fprintf(gppsfile, " 0 %d V\n", (corner[1].y - corner[0].y));
+ fprintf(gppsfile, " %d 0 V\n", -(corner[1].x - corner[0].x));
+ fprintf(gppsfile, " %d %d L\n", corner[0].x, corner[0].y);
+ fprintf(gppsfile, " 40 -110 R\n"
+ " (PS level 2 image) Lshow\n"
+ " %% Read data but ignore it\n"
+ " /imagebuf %d string def\n"
+ " currentfile imagebuf readstring\n", num_encoded_bytes);
+ fputs("} {\n", gppsfile);
+ }
+ fputs("gsave\n", gppsfile);
+ fprintf(gppsfile, "%d %d translate\n", corner[0].x, corner[0].y);
+ fprintf(gppsfile, "%d %d scale\n", (corner[1].x - corner[0].x), (corner[1].y - corner[0].y));
+ fputs("%%%%BeginPalette\n", gppsfile);
+ fprintf(gppsfile, "[ /Indexed\n /DeviceRGB %d\n <", (max_colors-1));
+
+#define TUPLES_PER_LINE 8
+
+ for (allocated = 0, i_tuple = 0; allocated < max_colors; allocated++, i_tuple--) {
+ double gray = (double) allocated * fact;
+ rgb255_color color;
+ rgb255maxcolors_from_gray( gray, &color );
+ if (!i_tuple) { fprintf(gppsfile,"\n "); i_tuple = TUPLES_PER_LINE; }
+ fprintf(gppsfile," %2.2x%2.2x%2.2x", (int)color.r, (int)color.g, (int)color.b);
+ }
+
+ fputs("\n >\n] setcolorspace\n", gppsfile);
+ fputs("%%%%EndPalette\n", gppsfile);
+ fprintf(gppsfile, "<<\n /ImageType 1\n /Width %d\n /Height %d\n", M, N);
+ fprintf(gppsfile, " /BitsPerComponent %d\n /ImageMatrix [ %d 0 0 %d 0 0 ]\n", bits_per_component, M, N);
+ fprintf(gppsfile, " /Decode [ 0 %d ]\n", ((1<<bits_per_component)-1));
+ if (ps_params->level1) {
+ fprintf(gppsfile, " /imagebuf %d string def\n", (M*N*bits_per_component + 7)/8);
+ fputs(" /DataSource {currentfile imagebuf readhexstring pop}\n", gppsfile);
+ } else {
+ fputs(" /DataSource currentfile /ASCII85Decode filter\n", gppsfile);
+ }
+ fputs(" /MultipleDataSources false\n", gppsfile);
+ fputs(" /Interpolate false\n"
+ ">>\n"
+ "image\n", gppsfile);
+ if (!ps_params->level1)
+ fputs("} ifelse\n", gppsfile);
+
+ }
+
+ /* Send encoded image to file. */
+ {
+ char *encoded_image_ptr;
+ for (i_tmp=0, encoded_image_ptr = encoded_image; i_tmp < num_encoded_bytes; i_tmp++)
+ fputc(*encoded_image_ptr++, gppsfile);
+ }
+
+ if (ps_params->level1)
+ fputs("\ngrestore\n", gppsfile);
+ else
+ fputs("\nInterpretLevel1 not {\n"
+ " grestore\n"
+ "} if\n", gppsfile);
+ fputs("grestore\n", gppsfile);
+ fputs("%%%%EndImage\n", gppsfile);
+
+ free(encoded_image);
+
+ return;
+}
+
+#endif /* WITH_IMAGE */
+
+/* First look for the GNUPLOT_PS_DIR environment variable
+ * If unsuccessful, look for hardcoded absolute path on UNIX,
+ * or hardcoded relative path on Windows and OS2,
+ * or files included at compile time. */
+static void
+PS_dump_prologue_file(char *name)
+{
+ char *fullname;
+ char *ps_prologue_dir;
+ FILE *prologue_fd;
+ char buf[256];
+
+ if ((ps_prologue_dir = getenv("GNUPLOT_PS_DIR")) == NULL) {
+#ifdef GNUPLOT_PS_DIR
+# if defined(_Windows)
+ /* retrieve prologues path relatively to gnuplot executable,
+ * whose path is in szModuleName (winmain.c) */
+ ps_prologue_dir = gp_alloc(strlen((char*) szModuleName)
+ + strlen(GNUPLOT_PS_DIR) + 2, "Prolog path");
+ strcpy(ps_prologue_dir, (char*) szModuleName);
+ strcat(ps_prologue_dir, "\\");
+ /* GNUPLOT_PS_DIR is _relative_ path */
+ strcat(ps_prologue_dir, GNUPLOT_PS_DIR);
+# elif defined(OS2)
+ const ULONG bufsiz = 1024;
+ CHAR exepath[bufsiz];
+ PPIB ppib;
+ ULONG rc;
+
+ rc = DosGetInfoBlocks(NULL, &ppib);
+ if (!rc)
+ rc = DosQueryModuleName(ppib->pib_hmte, bufsiz, (PCHAR) &exepath);
+ if (!rc) {
+ char *p = strrchr(exepath, '\\');
+ *(++p) = '\0';
+ ps_prologue_dir = gp_alloc(strlen(exepath) + strlen(GNUPLOT_PS_DIR) + 2,
+ "Prolog path");
+ strcpy(ps_prologue_dir, exepath);
+ strcat(ps_prologue_dir, "\\");
+ /* GNUPLOT_PS_DIR is _relative_ path */
+ strcat(ps_prologue_dir, GNUPLOT_PS_DIR);
+ }
+ else {
+ ps_prologue_dir = gp_alloc(1, "Prolog path");
+ /* unsucessful to retrieve executable path */
+ strcpy(ps_prologue_dir,"");
+ }
+# else /* !_Windows && !OS2 */
+ /* use hardcoded _absolute_ path */
+ ps_prologue_dir = GNUPLOT_PS_DIR;
+# endif
+#else /* using headers included at compile time */
+ const char **dump = NULL;
+ int i;
+
+ /* load from included header */
+ if (!strcmp(name,"8859-15.ps"))
+ dump = prologue_8859_15_ps;
+ else if (!strcmp(name,"8859-1.ps"))
+ dump = prologue_8859_1_ps;
+ else if (!strcmp(name,"8859-2.ps"))
+ dump = prologue_8859_2_ps;
+ else if (!strcmp(name,"cp1250.ps"))
+ dump = prologue_cp1250_ps;
+ else if (!strcmp(name,"cp437.ps"))
+ dump = prologue_cp437_ps;
+ else if (!strcmp(name,"cp850.ps"))
+ dump = prologue_cp850_ps;
+ else if (!strcmp(name,"cp852.ps"))
+ dump = prologue_cp852_ps;
+ else if (!strcmp(name,"koi8r.ps"))
+ dump = prologue_koi8r_ps;
+ else if (!strcmp(name,"koi8u.ps"))
+ dump = prologue_koi8u_ps;
+ else if (!strcmp(name,"prologue.ps"))
+ dump = prologue_prologue_ps;
+ else
+ int_error(NO_CARET,"Requested Postscript prologue is not included");
+
+ if (dump) {
+ for (i = 0; dump[i] != NULL; ++i)
+ fprintf(gppsfile, "%s", dump[i]);
+ }
+ return;
+#endif /* GNUPLOT_PS_DIR */
+ }
+
+ fullname = gp_alloc(strlen(ps_prologue_dir) + strlen(name) + 4,"Prolog name");
+ strcpy(fullname,ps_prologue_dir);
+#if defined(_Windows) || defined(OS2)
+ if (fullname[strlen(fullname)-1] != '\\')
+ strcat(fullname,"\\");
+#elif !defined(VMS)
+ if (fullname[strlen(fullname)-1] != '/')
+ strcat(fullname,"/");
+#endif
+ strcat(fullname,name);
+ prologue_fd = fopen(fullname,"r");
+#if defined(_Windows) || defined(OS2)
+ if (getenv("GNUPLOT_PS_DIR") == NULL)
+ free(ps_prologue_dir);
+#endif
+ if (!prologue_fd)
+ prologue_fd = loadpath_fopen(name,"r");
+ if (!prologue_fd) {
+ fprintf(stderr,"Can't find PostScript prologue file %s\n", fullname);
+ loadpath_handler(ACTION_SHOW,NULL);
+ free(fullname);
+ fprintf(stderr,"Please copy %s to one of the above directories\n",name);
+ fprintf(stderr,"or set the loadpath appropriately\n");
+ fprintf(stderr,"or set the environmental variable GNUPLOT_PS_DIR\n");
+ int_error(NO_CARET,"Plot failed!");
+ }
+ free(fullname);
+ while (fgets(buf, sizeof(buf), prologue_fd))
+ fputs(buf, gppsfile);
+ fclose(prologue_fd);
+}
+
+TERM_PUBLIC void
+PS_path(int p)
+{
+ switch (p) {
+ case 0: /* Start new path */
+ PS_FLUSH_PATH;
+ PS_newpath = TRUE;
+ break;
+
+ case 1: /* Close path */
+ fprintf(gppsfile, "Z ");
+ PS_FLUSH_PATH;
+ break;
+ }
+
+}
+
+#endif /* TERM_BODY */
+
+#ifdef TERM_TABLE
+
+TERM_TABLE_START(post_driver)
+ "postscript",
+ "PostScript graphics, including EPSF embedded files (*.eps)",
+ PS_XMAX, PS_YMAX, PS_VCHAR, PS_HCHAR,
+ PS_VTIC, PS_HTIC, PS_options, PS_init, PS_reset,
+ PS_text, null_scale, PS_graphics, PS_move, PS_vector,
+ PS_linetype, PS_put_text, PS_text_angle,
+ PS_justify_text, PS_point, PS_arrow, PS_set_font, PS_pointsize,
+ TERM_BINARY|TERM_IS_POSTSCRIPT|TERM_CAN_CLIP /*flags*/,
+ 0 /*suspend*/, 0 /*resume*/, PS_fillbox, PS_linewidth
+#ifdef USE_MOUSE
+ , 0, 0, 0, 0, 0 /* no mouse support for postscript */
+#endif
+ , PS_make_palette,
+ PS_previous_palette, /* write grestore */
+ PS_set_color,
+ PS_filled_polygon
+#ifdef WITH_IMAGE
+ , PS_image
+#endif
+ , ENHPS_OPEN, ENHPS_FLUSH, ENHPS_WRITEC
+ , 0 /* layer control */
+ , PS_path
+TERM_TABLE_END(post_driver)
+
+#undef LAST_TERM
+#define LAST_TERM post_driver
+
+#endif /* TERM_TABLE */
+
+#endif /* TERM_PROTO_ONLY */
+
+#ifdef TERM_HELP
+/* This is a pseudo help section that is labeled with 00psglobal to be
+ * sure that it is sorted in before `post', `epslatex', and `pslatex'.
+ * This section just defines commonly used text snippets for all three
+ * help sections defined in this file. Defining PS_COMMON_OPTS1,
+ * PS_COMMON_OPTS2, and PS_COMMON_DOC1 outside START_HELP()...END_HELP()
+ * does not work.
+ * The last line before the END_HELP(00psglobal) contains one single line
+ * of "text" that is necessary to avoid errors.
+ */
+START_HELP(00psglobal)
+#define PS_COMMON_OPTS1 \
+" {level1 | leveldefault}",\
+" {color | colour | monochrome}",\
+" {solid | dashed}",\
+" {dashlength | dl <DL>}",\
+" {linewidth | lw <LW>}",\
+" {rounded | butt}",\
+" {palfuncparam <samples>{,<maxdeviation>}}",\
+" {size <XX>{unit},<YY>{unit}}",
+#define PS_COMMON_OPTS2 \
+" {blacktext | colortext | colourtext}",\
+" {{font} \"fontname{,fontsize}\" {<fontsize>}}",
+#define PS_COMMON_PROLOG_INFO \
+" If you see the error message",\
+" \"Can't find PostScript prologue file ... \"",\
+" Please see and follow the instructions in `postscript prologue`.",\
+"",
+#define PS_COMMON_DOC1 \
+" The option `color` enables color, while `monochrome` prefers black and white",\
+" drawing elements. Further, `monochrome` uses gray `palette` but it does not",\
+" change color of objects specified with an explicit `colorspec`."\
+"",\
+" `solid` draws all plots with solid lines, overriding any dashed patterns.",\
+" `dashlength` or `dl` scales the length of the dashed-line segments by <DL>,",\
+" which is a floating-point number greater than zero.",\
+" `linewidth` or `lw` scales all linewidths by <LW>.",\
+"",\
+" By default the generated PostScript code uses language features that were",\
+" introduced in PostScript Level 2, notably filters and pattern-fill of",\
+" irregular objects such as filledcurves. PostScript Level 2 features are",\
+" conditionally protected so that PostScript Level 1 interpreters do not issue",\
+" errors but, rather, display a message or a PostScript Level 1 approximation.",\
+" The `level1` option substitutes PostScript Level 1 approximations of these",\
+" features and uses no PostScript Level 2 code. This may be required by some",\
+" old printers and old versions of Adobe Illustrator. The flag `level1` can be", \
+" toggled later by editing a single line in the PostScript output file to force",\
+" PostScript Level 1 interpretation. In the case of files containing level 2",\
+" code, the above features will not appear or will be replaced by a note when",\
+" this flag is set or when the interpreting program does not indicate that it",\
+" understands level 2 PostScript or higher.",\
+"",\
+" `rounded` sets line caps and line joins to be rounded; `butt` is the",\
+" default, butt caps and mitered joins;",\
+"",\
+" `palfuncparam` controls how `set palette functions` are encoded as gradients",\
+" in the output. Analytic color component functions (set via",\
+" `set palette functions`) are encoded as linear interpolated gradients in the",\
+" postscript output: The color component functions are sampled at <samples>",\
+" points and all points are removed from this gradient which can be removed",\
+" without changing the resulting colors by more than <maxdeviation>. For",\
+" almost every useful palette you may savely leave the defaults of",\
+" <samples>=2000 and <maxdeviation>=0.003 untouched.",\
+"",\
+" The default size for postscript output is 10 inches x 7 inches. The default",\
+" for eps output is 5 x 3.5 inches. The `size` option changes this to",\
+" whatever the user requests. By default the X and Y sizes are taken to be in",\
+" inches, but other units are possibly (currently only cm). The BoundingBox",\
+" of the plot is correctly adjusted to contain the resized image.",\
+" Screen coordinates always run from 0.0 to 1.0 along the full length of the",\
+" plot edges as specified by the `size` option.",\
+" NB: `this is a change from the previously recommended method of using the",\
+" set size command prior to setting the terminal type`. The old method left",\
+" the BoundingBox unchanged and screen coordinates did not correspond to the",\
+" actual limits of the plot.",\
+"",
+""
+END_HELP(00psglobal)
+
+START_HELP(epslatex)
+"1 epslatex",
+"?commands set terminal epslatex",
+"?set terminal epslatex",
+"?set term epslatex",
+"?terminal epslatex",
+"?term epslatex",
+"?epslatex",
+" The `epslatex` driver generates output for further processing by LaTeX.",
+"",
+" Syntax:",
+" set terminal epslatex {default}",
+" set terminal epslatex {standalone | input}",
+" {oldstyle | newstyle}",
+PS_COMMON_OPTS1
+" {header <header> | noheader}",
+PS_COMMON_OPTS2
+"",
+" The epslatex terminal prints a plot as `terminal postscript eps`",
+" but transfers the texts to LaTeX instead of including in the PostScript",
+" code. Thus, many options are the same as in the `postscript terminal`.",
+"",
+" From version 4.0 to 4.2, some changes have been invoked into the default ",
+" appearance of the epslatex terminal to reach better consistency with the",
+" postscript terminal: The plot size has been changed from 5 x 3 inches to",
+" 5 x 3.5 inches; the character width is now estimated to be 60% of the font",
+" size while the old epslatex terminal used 50%; now, the larger number of",
+" postscript linetypes and symbols are used. To reach an appearance that is",
+" nearly identical to the old one specify the option `oldstyle`. (In fact",
+" some small differences remain: the symbol sizes are slightly different, the",
+" tics are half as large as in the old terminal which can be changed using",
+" `set tics scale`, and the arrows have all features as in the postscript",
+" terminal.)",
+"",
+PS_COMMON_PROLOG_INFO
+PS_COMMON_DOC1
+" `blacktext` forces all text to be written in black even in color mode;",
+"",
+" The epslatex driver offers a special way of controlling text positioning:",
+" (a) If any text string begins with '{', you also need to include a '}' at the",
+" end of the text, and the whole text will be centered both horizontally",
+" and vertically by LaTeX. (b) If the text string begins with '[', you need",
+" to continue it with: a position specification (up to two out of t,b,l,r,c),",
+" ']{', the text itself, and finally, '}'. The text itself may be anything",
+" LaTeX can typeset as an LR-box. \\rule{}{}'s may help for best positioning.",
+" See also the documentation for the `pslatex` terminal driver.",
+" To create multiline labels, use \\shortstack, for example",
+" set ylabel '[r]{\\shortstack{first line \\\\ second line}}' ",
+"",
+" The `back` option of `set label` commands is handled slightly different",
+" than in other terminals. Labels using 'back' are printed behind all other",
+" elements of the plot while labels using 'front' are printed above ",
+" everything else.",
+"",
+" The driver produces two different files, one for the eps part of the figure",
+" and one for the LaTeX part. The name of the LaTeX file is taken from the",
+" `set output` command. The name of the eps file is derived by replacing",
+" the file extension (normally `.tex`) with `.eps` instead. There is no",
+" LaTeX output if no output file is given! Remember to close the",
+" `output file` before next plot unless in `multiplot` mode.",
+"",
+" In your LaTeX documents use '\\input{filename}' to include the figure.",
+" The `.eps` file is included by the command \\includegraphics{...}, so you",
+" must also include \\usepackage{graphicx} in the LaTeX preamble. If you",
+" want to use coloured text (option `textcolour`) you also have to include",
+" \\usepackage{color} in the LaTeX preamble.",
+"",
+" Pdf files can be made from the eps file using 'epstopdf'. If the graphics",
+" package is properly configured, the LaTeX files can also be processed by",
+" pdflatex without changes, using the pdf files instead of the eps files."
+"",
+" The behaviour concerning font selection depends on the header mode.",
+" In all cases, the given font size is used for the calculation of proper",
+" spacing. When not using the `standalone` mode the actual LaTeX font and",
+" font size at the point of inclusion is taken, so use LaTeX commands for",
+" changing fonts. If you use e.g. 12pt as font size for your LaTeX",
+" document, use '\"\" 12' as options. The font name is ignored. If using",
+" `standalone` the given font and font size are used, see below for a",
+" detailed description.",
+"",
+" If text is printed coloured is controlled by the TeX booleans \\ifGPcolor",
+" and \\ifGPblacktext. Only if \\ifGPcolor is true and \\ifGPblacktext is",
+" false, text is printed coloured. You may either change them in the",
+" generated TeX file or provide them globally in your TeX file, for example",
+" by using",
+" \\newif\\ifGPblacktext",
+" \\GPblacktexttrue",
+" in the preamble of your document. The local assignment is only done if no",
+" global value is given.",
+"",
+" When using the epslatex terminal give the name of the TeX file in the",
+" `set output` command including the file extension (normally \".tex\").",
+" The eps filename is generated by replacing the extension by \".eps\".",
+"",
+" If using the `standalone` mode a complete LaTeX header is added to the",
+" LaTeX file; and \"-inc\" is added to the filename of the eps file.",
+" The `standalone` mode generates a TeX file that produces",
+" output with the correct size when using dvips, pdfTeX, or VTeX.",
+" The default, `input`, generates a file that has to be included into a",
+" LaTeX document using the \\input command.",
+"",
+" If a font other than \"\" or \"default\" is given it is interpreted as",
+" LaTeX font name. It contains up to three parts, separated by a comma:",
+" 'fontname,fontseries,fontshape'. If the default fontshape or fontseries",
+" are requested, they can be omitted. Thus, the real syntax for the fontname",
+" is '[fontname][,fontseries][,fontshape]'. The naming convention for all",
+" parts is given by the LaTeX font scheme. The fontname is 3 to 4 characters",
+" long and is built as follows: One character for the font vendor, two",
+" characters for the name of the font, and optionally one additional",
+" character for special fonts, e.g., 'j' for fonts with old-style numerals",
+" or 'x' for expert fonts. The names of many fonts is described in",
+"^ <a href=\"http://www.tug.org/fontname/fontname.pdf\">",
+" http://www.tug.org/fontname/fontname.pdf",
+"^ </a>",
+" For example, 'cmr' stands for Computer Modern Roman, 'ptm' for Times-Roman,",
+" and 'phv' for Helvetica. The font series denotes the thickness of the",
+" glyphs, in most cases 'm' for normal (\"medium\") and 'bx' or 'b' for bold",
+" fonts. The font shape is 'n' for upright, 'it' for italics, 'sl' for",
+" slanted, or 'sc' for small caps, in general. Some fonts may provide",
+" different font series or shapes.",
+"",
+" Examples:",
+"",
+" Use Times-Roman boldface (with the same shape as in the surrounding text):",
+" set terminal epslatex 'ptm,bx'",
+" Use Helvetica, boldface, italics:",
+" set terminal epslatex 'phv,bx,it'",
+" Continue to use the surrounding font in slanted shape:",
+" set terminal epslatex ',,sl'",
+" Use small capitals:",
+" set terminal epslatex ',,sc'",
+"",
+" By this method, only text fonts are changed. If you also want to change",
+" the math fonts you have to use the \"gnuplot.cfg\" file or the `header`",
+" option, described below.",
+"",
+" In standalone mode, the font size is taken from the given font size in the",
+" `set terminal` command. To be able to use a specified font size, a file",
+" \"size<size>.clo\" has to reside in the LaTeX search path. By default,",
+" 10pt, 11pt, and 12pt are supported. If the package \"extsizes\" is",
+" installed, 8pt, 9pt, 14pt, 17pt, and 20pt are added.",
+"",
+" The `header` option takes a string as argument. This string is written",
+" into the generated LaTeX file. If using the `standalone` mode, it is ",
+" written into the preamble, directly before the \\begin{document} command.",
+" In the `input` mode, it is placed directly after the \\begingroup command",
+" to ensure that all settings are local to the plot.",
+"",
+" Examples:",
+"",
+" Use T1 fontencoding, change the text and math font to Times-Roman as well",
+" as the sans-serif font to Helvetica:",
+" set terminal epslatex standalone header \\",
+" \"\\\\usepackage[T1]{fontenc}\\n\\\\usepackage{mathptmx}\\n\\\\usepackage{helvet}\"",
+" Use a boldface font in the plot, not influencing the text outside the plot:",
+" set terminal epslatex input header \"\\\\bfseries\"",
+"",
+" If the file \"gnuplot.cfg\" is found by LaTeX it is input in the preamble",
+" the LaTeX document, when using `standalone` mode. It can be used for",
+" further settings, e.g., changing the document font to Times-Roman,",
+" Helvetica, and Courier, including math fonts (handled by \"mathptmx.sty\"):",
+" \\usepackage{mathptmx}",
+" \\usepackage[scaled=0.92]{helvet}",
+" \\usepackage{courier}",
+" The file \"gnuplot.cfg\" is loaded before the header information given",
+" by the `header` command. Thus, you can use `header` to overwrite some of",
+" settings performed using \"gnuplot.cfg\"",
+""
+END_HELP(epslatex)
+
+START_HELP(pslatex)
+"1 pslatex and pstex",
+"?commands set terminal pslatex",
+"?set terminal pslatex",
+"?set term pslatex",
+"?terminal pslatex",
+"?term pslatex",
+"?pslatex",
+"?commands set terminal pstex",
+"?set terminal pstex",
+"?set term pstex",
+"?terminal pstex",
+"?term pstex",
+"?pstex",
+" The `pslatex` driver generates output for further processing by LaTeX,",
+" while the `pstex` driver generates output for further processing by",
+" TeX. `pslatex` uses \\specials understandable by dvips and xdvi. Figures",
+" generated by `pstex` can be included in any plain-based format (including",
+" LaTeX).",
+"",
+" Syntax:",
+" set terminal [pslatex | pstex] {default}",
+" set terminal [pslatex | pstex]",
+" {rotate | norotate}",
+" {oldstyle | newstyle}",
+" {auxfile | noauxfile}",
+PS_COMMON_OPTS1
+" {<font_size>}",
+"",
+PS_COMMON_PROLOG_INFO
+PS_COMMON_DOC1
+" if `rotate` is specified, the y-axis label is rotated.",
+" <font_size> is the size (in pts) of the desired font.",
+"",
+" If `auxfile` is specified, it directs the driver to put the PostScript",
+" commands into an auxiliary file instead of directly into the LaTeX file.",
+" This is useful if your pictures are large enough that dvips cannot handle",
+" them. The name of the auxiliary PostScript file is derived from the name of",
+" the TeX file given on the `set output` command; it is determined by replacing",
+" the trailing `.tex` (actually just the final extent in the file name) with",
+" `.ps` in the output file name, or, if the TeX file has no extension, `.ps`",
+" is appended. The `.ps` is included into the `.tex` file by a",
+" \\special{psfile=...} command. Remember to close the `output file` before",
+" next plot unless in `multiplot` mode.",
+"",
+" Gnuplot versions prior version 4.2 have generated plots of the size",
+" 5 x 3 inches using the ps(la)tex terminal while the current version generates",
+" 5 x 3.5 inches to be consistent with the postscript eps terminal. In",
+" addition, the character width is now estimated to be 60% of the font size",
+" while the old epslatex terminal used 50%. To reach the old format specify",
+" the option `oldstyle`.",
+"",
+" The pslatex driver offers a special way of controlling text positioning: ",
+" (a) If any text string begins with '{', you also need to include a '}' at the",
+" end of the text, and the whole text will be centered both horizontally",
+" and vertically by LaTeX. (b) If the text string begins with '[', you need",
+" to continue it with: a position specification (up to two out of t,b,l,r),",
+" ']{', the text itself, and finally, '}'. The text itself may be anything",
+" LaTeX can typeset as an LR-box. \\rule{}{}'s may help for best positioning.",
+"",
+" The options not described here are identical to the `Postscript terminal`.",
+" Look there if you want to know what they do.",
+"",
+" Examples:",
+" set term pslatex monochrome dashed rotate # set to defaults",
+" To write the PostScript commands into the file \"foo.ps\":",
+" set term pslatex auxfile",
+" set output \"foo.tex\"; plot ...; set output",
+" About label positioning:",
+" Use gnuplot defaults (mostly sensible, but sometimes not really best):",
+" set title '\\LaTeX\\ -- $ \\gamma $'",
+" Force centering both horizontally and vertically:",
+" set label '{\\LaTeX\\ -- $ \\gamma $}' at 0,0",
+" Specify own positioning (top here):",
+" set xlabel '[t]{\\LaTeX\\ -- $ \\gamma $}'",
+" The other label -- account for long ticlabels:",
+" set ylabel '[r]{\\LaTeX\\ -- $ \\gamma $\\rule{7mm}{0pt}}'",
+"",
+" Linewidths and pointsizes may be changed with `set style line`."
+""
+END_HELP(pslatex)
+
+START_HELP(post)
+"1 postscript",
+"?commands set terminal postscript",
+"?set terminal postscript",
+"?set term postscript",
+"?terminal postscript",
+"?term postscript",
+"?postscript",
+" Several options may be set in the `postscript` driver.",
+"",
+" Syntax:",
+" set terminal postscript {default}",
+" set terminal postscript {landscape | portrait | eps}",
+" {enhanced | noenhanced}",
+" {defaultplex | simplex | duplex}",
+" {fontfile [add | delete] \"<filename>\"",
+" | nofontfiles}",
+PS_COMMON_OPTS1
+PS_COMMON_OPTS2
+PS_COMMON_PROLOG_INFO
+"",
+" `landscape` and `portrait` choose the plot orientation.",
+" `eps` mode generates EPS (Encapsulated PostScript) output, which is just",
+" regular PostScript with some additional lines that allow the file to be",
+" imported into a variety of other applications. (The added lines are",
+" PostScript comment lines, so the file may still be printed by itself.) To",
+" get EPS output, use the `eps` mode and make only one plot per file. In `eps`",
+" mode the whole plot, including the fonts, is reduced to half of the default",
+" size.",
+"",
+" `enhanced` enables enhanced text mode features (subscripts,",
+" superscripts and mixed fonts). See `enhanced` for more information.",
+" `blacktext` forces all text to be written in black even in color mode;",
+"",
+" Duplexing in PostScript is the ability of the printer to print on both",
+" sides of the same sheet of paper. With `defaultplex`, the default setting",
+" of the printer is used; with `simplex` only one side is printed; `duplex`",
+" prints on both sides (ignored if your printer can't do it).",
+"",
+" `\"<fontname>\"` is the name of a valid PostScript font; and `<fontsize>` is",
+" the size of the font in PostScript points.",
+" In addition to the standard postscript fonts, an oblique version of the",
+" Symbol font, useful for mathematics, is defined. It is called",
+" \"Symbol-Oblique\".",
+"",
+" `default` sets all options to their defaults: `landscape`, `monochrome`,",
+" `dashed`, `dl 1.0`, `lw 1.0`, `defaultplex`, `noenhanced`, \"Helvetica\" and",
+" 14pt. Default size of a PostScript plot is 10 inches wide and 7 inches high.",
+PS_COMMON_DOC1
+" Fonts listed by `fontfile` or `fontfile add` encapsulate the font",
+" definitions of the listed font from a postscript Type 1 or TrueType font",
+" file directly into the gnuplot output postscript file. Thus, the enclosed",
+" font can be used in labels, titles, etc. See the section",
+" `postscript fontfile` for more details. With `fontfile delete`, a fontfile",
+" is deleted from the list of embedded files. `nofontfiles` cleans the list",
+" of embedded fonts.",
+"",
+" Examples:",
+" set terminal postscript default # old postscript",
+" set terminal postscript enhanced # old enhpost",
+" set terminal postscript landscape 22 # old psbig",
+" set terminal postscript eps 14 # old epsf1",
+" set terminal postscript eps 22 # old epsf2",
+" set size 0.7,1.4; set term post portrait color \"Times-Roman\" 14",
+" set term post \"VAGRoundedBT_Regular\" 14 fontfile \"bvrr8a.pfa\"",
+"",
+" Linewidths and pointsizes may be changed with `set style line`.",
+"",
+" The `postscript` driver supports about 70 distinct pointtypes, selectable",
+" through the `pointtype` option on `plot` and `set style line`.",
+"",
+" Several possibly useful files about `gnuplot`'s PostScript are included",
+" in the /docs/psdoc subdirectory of the `gnuplot` distribution and at the",
+" distribution sites. These are \"ps_symbols.gpi\" (a `gnuplot` command file",
+" that, when executed, creates the file \"ps_symbols.ps\" which shows all the",
+" symbols available through the `postscript` terminal), \"ps_guide.ps\" (a",
+" PostScript file that contains a summary of the enhanced syntax and a page",
+" showing what the octal codes produce with text and symbol fonts),",
+" \"ps_file.doc\" (a text file that contains a discussion of the organization",
+" of a PostScript file written by `gnuplot`), and \"ps_fontfile_doc.tex\"",
+" (a LaTeX file which contains a short documentation concerning the",
+" encapsulation of LaTeX fonts with a glyph table of the math fonts).",
+"",
+" A PostScript file is editable, so once `gnuplot` has created one, you are",
+" free to modify it to your heart's desire. See the `editing postscript`",
+" section for some hints.",
+"2 enhanced postscript",
+"?commands set terminal postscript enhanced",
+"?set terminal postscript enhanced",
+"?set term postscript enhanced",
+"?terminal postscript enhanced",
+"?term postscript enhanced",
+"?enhanced_postscript",
+"?enhanced postscript",
+"?Enhanced postscript",
+"?enhanced text",
+"?Enhanced text",
+"?enhanced",
+" Several terminal types support an enhanced text mode in which ",
+" additional formatting information is embedded in the text string.",
+"",
+"@start table - first is interactive cleartext form",
+" Control Examples Explanation",
+" ^ a^x superscript",
+" _ a_x subscript",
+" @ @x or a@^b_c phantom box (occupies no width)",
+" & &{space} inserts space of specified length",
+" ~ ~a{.8-} overprints '-' on 'a', raised by .8",
+" times the current fontsize",
+"#\\begin{tabular}{|ccl|} \\hline",
+"#\\multicolumn{3}{|c|}{Enhanced Text Control Codes} \\\\ \\hline",
+"#Control & Examples & Explanation \\\\ \\hline",
+"#\\verb~^~ & \\verb~a^x~ & superscript\\\\",
+"#\\verb~_~ & \\verb~a_x~ & subscript\\\\",
+"#\\verb~@~ & \\verb~@x or a@^b_c~ & phantom box (occupies no width)\\\\",
+"#\\verb~&~ & \\verb~&{space}~ & inserts space of specified length\\\\",
+"#\\verb|~| & \\verb|~a{.8-}| & overprints '-' on 'a', raised by .8\\\\",
+"#\\verb~ ~ & \\verb~ ~ & times the current fontsize\\\\",
+"%c c l .",
+"%.TE", /* ugly - doc2ms uses @ for column separator, but here we */
+"%.TS", /* need @ in table, so end and restart the table ! */
+"%center box tab ($) ;",
+"%c c l .",
+"%Control$Examples$Explanation",
+"%_",
+"%^$a^x$superscript",
+"%\\&_$a\\&_x$subscript",
+"% @ $ @x or a\\&@^b\\&_c$phantom box (occupies no width)",
+"% & $ &{space}$inserts space of specified length",
+"% ~ $ ~a{.8-}$overprints '-' on 'a', raised by .8",
+"% $ $times the current fontsize",
+"@end table",
+"",
+" Braces can be used to place multiple-character text where a single character",
+" is expected (e.g., 2^{10}). To change the font and/or size, use the full",
+" form: {/[fontname][=fontsize | *fontscale] text}. Thus {/Symbol=20 G} is a",
+" 20-point GAMMA and {/*0.75 K} is a K at three-quarters of whatever fontsize",
+" is currently in effect. (The '/' character MUST be the first character after",
+" the '{'.)",
+"",
+" If the encoding vector has been changed by `set encoding`, the default",
+" encoding vector can be used instead by following the slash with a dash. This",
+" is unnecessary if you use the Symbol font, however---since /Symbol uses its",
+" own encoding vector, `gnuplot` will not apply any other encoding vector to",
+" it.",
+"",
+" The phantom box is useful for a@^b_c to align superscripts and subscripts",
+" but does not work well for overwriting an accent on a letter. (To do the",
+" latter, it is much better to use 'set encoding iso_8859_1' to change to the",
+" ISO Latin-1 encoding vector, which contains a large variety of letters with",
+" accents or other diacritical marks.) Since the box is non-spacing, it is",
+" sensible to put the shorter of the subscript or superscript in the box (that",
+" is, after the @).",
+"",
+" Space equal in length to a string can be inserted using the '&' character.",
+" Thus",
+" 'abc&{def}ghi'",
+" would produce",
+" 'abc ghi'.",
+"",
+" The '~' character causes the next character or bracketed text to be",
+" overprinted by the following character or bracketed text. The second text",
+" will be horizontally centered on the first. Thus '~a/' will result in an 'a'",
+" with a slash through it. You can also shift the second text vertically by",
+" preceding the second text with a number, which will define the fraction of the",
+" current fontsize by which the text will be raised or lowered. In this case",
+" the number and text must be enclosed in brackets because more than one",
+" character is necessary. If the overprinted text begins with a number, put a",
+" space between the vertical offset and the text ('~{abc}{.5 000}'); otherwise",
+" no space is needed ('~{abc}{.5---}'). You can change the font for one or",
+" both strings ('~a{.5 /*.2 o}'---an 'a' with a one-fifth-size 'o' on top---and",
+" the space between the number and the slash is necessary), but you can't",
+" change it after the beginning of the string. Neither can you use any other",
+" special syntax within either string. You can, of course, use control",
+" characters by escaping them (see below), such as '~a{\\^}'",
+"",
+" You can access special symbols numerically by specifying \\character-code (in",
+" octal), e.g., {/Symbol \\245} is the symbol for infinity.",
+"",
+" You can escape control characters using \\, e.g., \\\\, \\{, and so on.",
+"",
+" But be aware that strings in double-quotes are parsed differently than those",
+" enclosed in single-quotes. The major difference is that backslashes may need",
+" to be doubled when in double-quoted strings.",
+"",
+" Examples (these are hard to describe in words---try them!):",
+" set xlabel 'Time (10^6 {/Symbol m}s)'",
+" set title '{/Symbol=18 \\362@_{/=9.6 0}^{/=12 x}} \\",
+" {/Helvetica e^{-{/Symbol m}^2/2} d}{/Symbol m}'",
+"",
+" The file \"ps_guide.ps\" in the /docs/psdoc subdirectory of the `gnuplot` source",
+" distribution contains more examples of the enhanced syntax.",
+"2 editing postscript",
+"?commands set terminal postscript editing",
+"?set terminal postscript editing",
+"?set term postscript editing",
+"?terminal postscript editing",
+"?term postscript editing",
+"?editing_postscript",
+"?editing postscript",
+" The PostScript language is a very complex language---far too complex to",
+" describe in any detail in this document. Nevertheless there are some things",
+" in a PostScript file written by `gnuplot` that can be changed without risk of",
+" introducing fatal errors into the file.",
+"",
+" For example, the PostScript statement \"/Color true def\" (written into the",
+" file in response to the command `set terminal postscript color`), may be",
+" altered in an obvious way to generate a black-and-white version of a plot.",
+" Similarly line colors, text colors, line weights and symbol sizes can also be",
+" altered in straight-forward ways. Text (titles and labels) can be edited to",
+" correct misspellings or to change fonts. Anything can be repositioned, and",
+" of course anything can be added or deleted, but modifications such as these",
+" may require deeper knowledge of the PostScript language.",
+"",
+" The organization of a PostScript file written by `gnuplot` is discussed in",
+" the text file \"ps_file.doc\" in the docs/ps subdirectory of the gnuplot",
+" source distribution.",
+"2 postscript fontfile",
+"?commands set terminal postscript fontfile",
+"?set terminal postscript fontfile",
+"?set term postscript fontfile",
+"?terminal postscript fontfile",
+"?term postscript fontfile",
+"?postscript fontfile",
+"?fontfile",
+" The `fontfile` or `fontfile add` option takes one file name as argument",
+" and encapsulates this file into the postscript output in order to make",
+" this font available for text elements (labels, tic marks, titles, etc.).",
+" The `fontfile delete` option also takes one file name as argument. It",
+" deletes this file name from the list of encapsulated files.",
+"",
+" The postscript terminal understands some",
+" font file formats: Type 1 fonts in ASCII file format (extension \".pfa\"),",
+" Type 1 fonts in binary file format (extension \".pfb\"), and TrueType",
+" fonts (extension \".ttf\"). Pfa files are understood directly, pfb and ttf",
+" files are converted on the fly if appropriate conversion tools are",
+" installed (see below). You have to specify the full filename including the",
+" extension. Each `fontfile` option takes exact one font file name. This",
+" option can be used multiple times in order to include more than one font",
+" file.",
+"",
+" The font file is searched in the working directory and in all directories",
+" listed in the fontpath which is determined by `set fontpath`.",
+" In addition, the fontpath can be set using the environment variable",
+" GNUPLOT_FONTPATH. If this is not set a system dependent default search",
+" list is used. See `set fontpath` for more details.",
+"",
+" For using the encapsulated font file you have to specify the font name",
+" (which normally is not the same as the file name). When embedding a",
+" font file by using the `fontfile` option in interactive mode, the ",
+" font name is printed on the screen. E.g.",
+" Font file 'p052004l.pfb' contains the font 'URWPalladioL-Bold'. Location:",
+" /usr/lib/X11/fonts/URW/p052004l.pfb",
+"",
+" When using pfa or pfb fonts, you can also find it out by looking into the",
+" font file. There is a line similar to \"/FontName /URWPalladioL-Bold def\".",
+" The middle string without the slash is the fontname, here",
+" \"URWPalladioL-Bold\".",
+" For TrueType fonts, this is not so easy since the font name is stored in a",
+" binary format. In addition, they often have spaces in the font names which",
+" is not supported by Type 1 fonts (in which a TrueType is converted on the",
+" fly). The font names are changed in order to eliminate the spaces in the",
+" fontnames. The easiest way to find out which font name is generated for",
+" use with gnuplot, start gnuplot in interactive mode and type in",
+" \"set terminal postscript fontfile '<filename.ttf>'\".",
+"",
+" For converting font files (either ttf or pfb) to pfa format, the conversion",
+" tool has to read the font from a file and write it to standard output. If",
+" the output cannot be written to standard output, on-the-fly conversion is",
+" not possible.",
+"",
+" For pfb files \"pfbtops\" is a tool which can do this. If this program",
+" is installed on your system the on the fly conversion should work.",
+" Just try to encapsulate a pfb file. If the compiled in program call does",
+" not work correctly you can specify how this program is called by",
+" defining the environment variable GNUPLOT_PFBTOPFA e.g. to",
+" \"pfbtops %s\". The `%s` will be replaced by the font file name and thus",
+" has to exist in the string.",
+"",
+" If you don't want to do the conversion on the fly but get a pfa file of",
+" the font you can use the tool \"pfb2pfa\" which is written in simple c",
+" and should compile with any c compiler.",
+" It is available from many ftp servers, e.g.",
+"^ <a href=\"ftp://ftp.dante.de/tex-archive/fonts/utilities/ps2mf/\">",
+" ftp://ftp.dante.de/tex-archive/fonts/utilities/ps2mf/",
+"^ </a>",
+" In fact, \"pfbtopfa\" and \"pfb2ps\" do the same job. \"pfbtopfa\" puts",
+" the resulting pfa code into a file, whereas \"pfbtops\" writes it to",
+" standard output.",
+"",
+" TrueType fonts are converted into Type 1 pfa format, e.g.",
+" by using the tool \"ttf2pt1\" which is available from",
+"^ <a href=\"http://ttf2pt1.sourceforge.net/\">",
+" http://ttf2pt1.sourceforge.net/",
+"^ </a>",
+" If the builtin conversion does not",
+" work, the conversion command can be changed by the environment variable",
+" GNUPLOT_TTFTOPFA. For usage with ttf2pt1 it may be set to",
+" \"ttf2pt1 -a -e -W 0 %s - \". Here again, `%s` stands for the",
+" file name.",
+"",
+" For special purposes you also can use a pipe (if available for your",
+" operating system). Therefore you start the file name definition with ",
+" the character \"<\" and append a program call. This program has ",
+" to write pfa data to standard output. Thus, a pfa file may be accessed",
+" by `set fontfile \"< cat garamond.pfa\"`.",
+"",
+" For example, including Type 1 font files can be used for including the",
+" postscript output in LaTeX documents. The \"european computer modern\"",
+" font (which is a variant of the \"computer modern\" font) is available",
+" in pfb format from any CTAN server, e.g.",
+"^ <a href=\"ftp://ftp.dante.de/tex-archive/fonts/ps-type1/cm-super/\">",
+" ftp://ftp.dante.de/tex-archive/fonts/ps-type1/cm-super/",
+"^ </a>",
+" For example, the file \"sfrm1000.pfb\" contains the normal upright fonts",
+" with serifs in the design size 10pt (font name \"SFRM1000\").",
+" The computer modern fonts, which are still necessary for mathematics,",
+" are available from",
+"^ <a href=\"ftp://ftp.dante.de/tex-archive/fonts/cm/ps-type1/bluesky\">",
+" ftp://ftp.dante.de/tex-archive/fonts/cm/ps-type1/bluesky",
+"^ </a>",
+" With these you can use any character available in TeX. However, the",
+" computer modern fonts have a strange encoding. (This is why you should not",
+" use cmr10.pfb for text, but sfrm1000.pfb instead.)",
+" The usage of TeX fonts is shown in one of the demos.",
+" The file \"ps_fontfile_doc.tex\" in the /docs/psdoc subdirectory of the",
+" `gnuplot` source distribution contains a table with glyphs of the TeX",
+" mathfonts.",
+"",
+" If the font \"CMEX10\" is embedded (file \"cmex10.pfb\") gnuplot defines",
+" the additional font \"CMEX10-Baseline\". It is shifted vertically in order",
+" to fit better to the other glyphs (CMEX10 has its baseline at the top of",
+" the symbols).",
+"2 postscript prologue",
+"?commands set terminal postscript prologue",
+"?set terminal postscript prologue",
+"?terminal postscript prologue",
+"?postscript prologue",
+"?prologue",
+" Each PostScript output file includes a %%Prolog section and possibly some",
+" additional user-defined sections containing, for example, character",
+" encodings. These sections are copied from a set of PostScript prologue files",
+" which are either compiled in the gnuplot executable or stored elsewhere on your",
+" computer. This behaviour and the default directory where these files live are",
+" controlled at the time gnuplot is built. However, you can control this",
+" either by defining an environment variable GNUPLOT_PS_DIR or by using the",
+" gnuplot command `set loadpath`. See `set loadpath`.",
+"",
+""
+END_HELP(post)
+#endif /* TERM_HELP */