[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/gnuplot/gnuplot/master/term/pdf.trm [Back]  [Original]

/* Hello, Emacs, this is -*-C-*- */

/*------------------------------
	GNUPLOT - pdf.trm

	This file is included by ../term.c.

	This driver uses PDFlib from www.pdflib.com

	Author:

		Hans-Bernhard Br"oker
		broeker@physik.rwth-aachen.de

	Licence: see the gnuplot copyright (to be merged into here...)

	Options: can #define PDF_DONT_COMPRESS to avoid PDF output
	generated being compressed (by the 'deflate' algorithm as used
	in 'zip' or 'gzip'). That helps in debugging.

------------------------------*/

/* CODEME: Add patterned lines (?). */

/* PM3D support by Johannes Zellner , May-15-2002 */
/* set_color fixes by Petr Mikulik , June-10-2002 */
/* image support by Ethan A Merritt , March 2003 */

/* Text rotation 24-Jul-2002 Ethan A Merritt  */
/* Revised fill patterns 02-Apr-2003 Ethan A Merritt */
/* Enhanced text mode support November 2003 Ethan A Merritt */

#include "driver.h"

#ifdef TERM_REGISTER
register_term(pdf)
#endif

#ifdef TERM_PROTO
TERM_PUBLIC void PDF_options(void);
TERM_PUBLIC void PDF_init(void);
TERM_PUBLIC void PDF_graphics(void);
TERM_PUBLIC void PDF_text(void);
TERM_PUBLIC void PDF_linetype(int linetype);
TERM_PUBLIC void PDF_move(unsigned int x, unsigned int y);
TERM_PUBLIC void PDF_vector(unsigned int x, unsigned int y);
TERM_PUBLIC void PDF_put_text(unsigned int x, unsigned int y, const char *str);
TERM_PUBLIC void PDF_reset(void);
TERM_PUBLIC int PDF_justify_text(enum JUSTIFY mode);
TERM_PUBLIC int PDF_text_angle(float ang);
TERM_PUBLIC void PDF_point(unsigned int x, unsigned int y, int pointstyle);
TERM_PUBLIC int PDF_set_font(const char *font);
TERM_PUBLIC void PDF_boxfill(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height);
TERM_PUBLIC void PDF_linewidth(double linewidth);
TERM_PUBLIC int PDF_make_palette(t_sm_palette *);
TERM_PUBLIC void PDF_previous_palette(void);
TERM_PUBLIC void PDF_set_color(t_colorspec *);
TERM_PUBLIC void PDF_image(unsigned int, unsigned int, coordval *, gpiPoint *, t_imagecolor);

TERM_PUBLIC void PDF_filled_polygon(int, gpiPoint *);

/* To support "set term png enhanced" */
TERM_PUBLIC void ENHPDF_put_text(unsigned int x, unsigned int y, const char *str);
TERM_PUBLIC void ENHPDF_OPEN(char * fontname, double fontsize,
			double base, TBOOLEAN widthflag, TBOOLEAN showflag,
			int overprint);
TERM_PUBLIC void ENHPDF_FLUSH(void);

#define PDF_NUM_POINTTYPES 75	/* number of point symbol types not counting the dot */

#define PDF_RESOLUTION  (20)	/* number of terminal pixels per pt */
#define PDF_XMAX	(5*72*PDF_RESOLUTION) /* 5 inches, 72 pt/inch */
#define PDF_YMAX	(3*72*PDF_RESOLUTION) /* 3 inches, 72 pt/inch */

static TBOOLEAN pdf_explicit_size = FALSE;
static size_units pdf_explicit_units = INCHES;

#endif /* TERM_PROTO */

#ifndef TERM_PROTO_ONLY
#ifdef TERM_BODY

#include 

static PDF *myPDF = NULL;

static unsigned int PDF_xLast = UINT_MAX; /* current pen horizontal position*/
static unsigned int PDF_yLast = UINT_MAX; /* current pen vertical position*/

static int PDF_LineType = LT_UNDEFINED;		/* current line type*/
static int PDF_LineCap = 0;			/* Butt ends */
static double PDF_LineWidth = 1.0;		/* current line width*/
static int PDF_TextAngle = 0;			/* current text orientation*/
static enum JUSTIFY PDF_TextJust = LEFT;	/* current text justification*/
static double PDF_linewidth_factor = 1.0;	/* multiplier for line width */
static double PDF_dashlength_factor = 1.0;	/* multiplier for dash length */
static TBOOLEAN PDF_monochrome = FALSE;		/* default all linetypes to black */
static rgb_color PDF_current_rgb = {0.,0.,0.};	/* Last color set */
static double PDF_current_gray = 0.0;		/* Last color set (mono version) */

#ifdef HAVE_NODASH_LIBPDF
static TBOOLEAN PDF_dashedlines = FALSE;	/* solid or dashed? */
#else
static TBOOLEAN PDF_dashedlines = TRUE;		/* solid or dashed? */
#endif

/* default text font family: */
static char PDF_fontNameDef[MAX_ID_LEN + 1] = "Helvetica";
static double PDF_fontSizeDef = 6;	/* default text size*/
/* current text font family: */
static char PDF_fontNameCur[MAX_ID_LEN + 1] = "Helvetica";
static double PDF_fontSizeCur = 6; /* current text size*/
static double PDF_fontscale = 1.0;

static TBOOLEAN PDF_pageIsOpen = FALSE; /* already started a page ?? */
static TBOOLEAN PDF_pathIsOpen = FALSE; /* open path flag*/

static int PDF_fontAscent = 0;	/* estimated current font ascent*/
static int PDF_fontDescent = 0;	/* estimated current font descent*/
static int PDF_fontLeading = 0;	/* estimated current font leading*/
static int PDF_fontAvWidth = 0;	/* estimated current font char average width*/
static int PDF_currentFontHandle; /* Needed for exhanced text mode */

static short PDF_Pen_RealID(int);
static void PDF_PathOpen(void);
static void PDF_PathClose(void);
static void PDF_SetFont(void);
static void PDF_DefinePatterns(void);
enum { PDF_patterns = 7 };
static int PDF_patternHandles[PDF_patterns];

#ifndef HAVE_NODASH_LIBPDF
/* Description of dash patterns (same as those in post.trm) */
static int dash1[] = {8, 8};
static int dash2[] = {4, 6};
static int dash3[] = {2, 3};
static int dash4[] = {12, 4, 2, 4};
static int dash5[] = {6, 6, 2, 6};
static int dash6[] = {4, 4, 4, 12};
static int dash7[] = {1, 4, 12, 4, 1, 4};
#endif

/*------------------------ helper functions -------------------*/

static short
PDF_Pen_RealID (int inPenCode)
{
    if (inPenCode >= 12)
	inPenCode %= 12;	/* normalize pen code*/
    if (inPenCode flags |= TERM_ENHANCED_TEXT;
    }

    while (!END_OF_COMMAND) {

	if (almost_equals(c_token, "enh$anced")) {
	    c_token++;
	    term->put_text = ENHPDF_put_text;
	    term->flags |= TERM_ENHANCED_TEXT;
	    continue;
	} else if (almost_equals(c_token, "noenh$anced")) {
	    c_token++;
	    term->put_text = PDF_put_text;
	    term->flags &= ~TERM_ENHANCED_TEXT;
	    continue;
	}

	if (almost_equals(c_token, "fn$ame") || almost_equals(c_token, "font"))  {
	    char *s, *comma;
	    c_token++;

	    if (!(s = try_to_get_string()))
		int_error(c_token,"fname: expecting font name");
	    comma = strrchr(s,',');
	    if (comma && (1 == sscanf(comma+1,"%lf",&PDF_fontSizeDef)))
		*comma = '\0';
	    if (*s)
		strncpy(PDF_fontNameDef, s, sizeof(PDF_fontNameDef));
	    free(s);
	    continue;
	}

	if (almost_equals(c_token, "fs$ize")) {
	    c_token++;

	    if (END_OF_COMMAND)
		int_error(c_token,"fsize: expecting font size");
	    PDF_fontSizeDef = real_expression();
	    continue;
	}

	if (equals(c_token, "lw") || almost_equals(c_token, "linew$idth")) {
	    c_token++;

	    if (END_OF_COMMAND)
		int_error(c_token, "expecting line width");
	    PDF_linewidth_factor = real_expression();
	    if (PDF_linewidth_factor flags &= ~TERM_MONOCHROME;
	    continue;
	}   

	if (almost_equals(c_token, "mono$chrome")) {
	    c_token++;
	    PDF_monochrome = TRUE;
	    term->flags |= TERM_MONOCHROME;
	    continue;
	}   

	if (equals(c_token, "dl") || almost_equals(c_token, "dashl$ength")) {
	    c_token++;
	    if (END_OF_COMMAND)
		int_error(c_token, "expecting dashlength multiplier");
	    PDF_dashlength_factor = real_expression();
	    if (PDF_dashlength_factor < 0.0)
		PDF_dashlength_factor = 1.0;
	    continue;
	}

	if (almost_equals(c_token, "dash$ed") || equals(c_token, "solid")) {
	    /* Version 5 always enables dashed lines */
	    c_token++;
	    continue;
	}

	if (equals(c_token, "size")) {
	    float xmax_t, ymax_t;
	    c_token++;
	    pdf_explicit_size = TRUE;
	    pdf_explicit_units = parse_term_size(&xmax_t, &ymax_t, INCHES);
	    term->xmax = xmax_t*PDF_RESOLUTION*72./gp_resolution;
	    term->ymax = ymax_t*PDF_RESOLUTION*72./gp_resolution;
	    continue;
	}

	if (equals(c_token, "fontscale")) {
	    c_token++;
	    PDF_fontscale = END_OF_COMMAND ? -1 : real_expression();
	    if (PDF_fontscale < 0)
		PDF_fontscale = 1.0;
	    continue;
	}

	int_error(c_token, "unexpected text at end of command");
    }

    /* Save options back into options string in normalized format */
    sprintf(term_options, "%s%s fname '%s'  fsize %g fontscale %3.1f linewidth %3.1f %s ",
	    PDF_monochrome ? "monochrome " : " ",
	    term->put_text == ENHPDF_put_text ? "enhanced" : "noenhanced",
	    PDF_fontNameDef, PDF_fontSizeDef, PDF_fontscale, PDF_linewidth_factor,
	    PDF_LineCap == 1 ? "rounded" : "");
    if (PDF_dashedlines)
	sprintf(&(term_options[strlen(term_options)]), "dl %3.1f",
		PDF_dashlength_factor);
    if (pdf_explicit_size) {
	if (pdf_explicit_units == CM)
	    sprintf(&(term_options[strlen(term_options)]), "size %.2fcm, %.2fcm ", 
		2.54*(float)term->xmax/(72.*PDF_RESOLUTION),
		2.54*(float)term->ymax/(72.*PDF_RESOLUTION));
	else
	    sprintf(&(term_options[strlen(term_options)]), "size %.2fin, %.2fin ", 
		(float)term->xmax/(72.*PDF_RESOLUTION),
		(float)term->ymax/(72.*PDF_RESOLUTION));
    }
}


TERM_PUBLIC void
PDF_init ()
{
    static TBOOLEAN PDFlib_booted = FALSE;
    char *gpversionstring;
    char *username;
    char *timedate;
    time_t now;

    if (!PDFlib_booted) {
	PDF_boot();
	PDFlib_booted = TRUE;
    }

    if (!myPDF)
	myPDF = PDF_new();

    /*open new PDF file */
#ifdef HAVE_LIBPDF_OPEN_FILE
    if (PDF_open_file(myPDF, outstr) == -1)
#else
    if (PDF_begin_document(myPDF, outstr?outstr:"-", 0,
			   "compatibility=1.4") == -1)
#endif /* HAVE_LIBPDF_OPEN_FILE */
	int_error(NO_CARET, "Error:cannot open PDF file .\n");

#ifdef PDF_DONT_COMPRESS
    /* for easier debugging of the output, turn off PDF stream
     * compression */
    PDF_set_value(myPDF, "compress", 0);
#endif

    gpversionstring = gp_alloc(20 + strlen(gnuplot_version) + 
			       strlen(gnuplot_patchlevel) + 1, "PDF_init");
    sprintf(gpversionstring,"gnuplot %s patchlevel %s",
	    gnuplot_version, gnuplot_patchlevel);

    time(&now);
    timedate=asctime(localtime(&now));
    timedate[strlen(timedate)-1]='\0';

    PDF_set_info(myPDF,"Creator",gpversionstring);

    username=getusername();
    if (username) {
	PDF_set_info(myPDF,"Author",username);
	free(username);
    }

    if (outstr)
	PDF_set_info(myPDF,"Title",outstr); /* FIXME: use 'set title', if any? */
    PDF_set_info(myPDF,"Subject","gnuplot plot");

    if (gpversionstring)
	free(gpversionstring);

    PDF_LineType = LT_UNDEFINED;

    /* set current font to default */
    strcpy(PDF_fontNameCur, PDF_fontNameDef);
    PDF_fontSizeCur = PDF_fontSizeDef;

#if !HAVE_OLD_LIBPDF
    PDF_DefinePatterns();
#endif

    /* Have to start the first page now, in order to know the actual
     * size of the selected font */
    PDF_graphics();

    /* set h_char, v_char*/
    term->h_char = PDF_fontAvWidth;
    term->v_char = (PDF_fontAscent + PDF_fontDescent + PDF_fontLeading);

    /* set h_tic, v_tic*/
    term->h_tic = term->v_tic = 3 * PDF_RESOLUTION;

    /* initialize terminal's pointsize from "set pointsize" value */
    term_pointsize = pointsize;

    /* Initialize other default settings */
    PDF_setlinecap(myPDF, PDF_LineCap);
    PDF_setlinejoin(myPDF, PDF_LineCap);	/* round+round or butt+mitre */
}


TERM_PUBLIC void
PDF_graphics ()
{
    if (PDF_pageIsOpen)
	return;			/* already open --> nothing to do */

    PDF_pathIsOpen = FALSE;
    PDF_xLast = PDF_yLast = UINT_MAX;

    /* set size of canvas */
    if (!pdf_explicit_size) {
	term->xmax = PDF_XMAX;
	term->ymax = PDF_YMAX;
    }

    PDF_begin_page(myPDF, (double)term->xmax / PDF_RESOLUTION,
		   (double)term->ymax / PDF_RESOLUTION);
    PDF_scale(myPDF, 1.0/PDF_RESOLUTION, 1.0/PDF_RESOLUTION);
    if (title.text && title.text[0])
	/* a title has been set --> use it as the bookmark name, too */
	PDF_add_bookmark(myPDF, title.text, 0, 1);
    PDF_pageIsOpen = TRUE;

    PDF_SetFont();
}


TERM_PUBLIC void
PDF_text ()
{
    PDF_PathClose();
    PDF_end_page(myPDF);
    PDF_pageIsOpen = FALSE;
}


TERM_PUBLIC void
PDF_reset ()
{
    assert(PDF_pageIsOpen == FALSE);
#ifdef HAVE_LIBPDF_OPEN_FILE
    PDF_close(myPDF);
#else
    PDF_end_document(myPDF, "");
#endif /* HAVE_LIBPDF_OPEN_FILE */
    PDF_delete(myPDF);
    myPDF = NULL;
}


TERM_PUBLIC void
PDF_linetype (int linetype)
{
    int dash = linetype % 8;

    linetype = PDF_Pen_RealID(linetype);
    if (linetype == PDF_LineType)
	return;
	
    PDF_PathClose ();
    PDF_LineType = linetype;

    if (PDF_monochrome) {
	PDF_current_gray = 0.0;
	PDF_setgray(myPDF, PDF_current_gray);
    } else {
	unsigned int irgb = pm3d_color_names_tbl[1+linetype].value;
	PDF_current_rgb.r = (double)((irgb >> 16) & 0xff) / 255.;
	PDF_current_rgb.g = (double)((irgb >>  8) & 0xff) / 255.;
	PDF_current_rgb.b = (double)((irgb      ) & 0xff) / 255.;
	PDF_setrgbcolor(myPDF, PDF_current_rgb.r, PDF_current_rgb.g, PDF_current_rgb.b);
    }

#ifndef HAVE_NODASH_LIBPDF
	if (PDF_dashedlines) {
	    char dashtype[64];
	    float dl = 8.0 * PDF_dashlength_factor;

	    switch (dash) {
	    default:
	    case 0:	PDF_setdash(myPDF, 0.0, 0.0);
			return;
	    case 1:	sprintf(dashtype,"dasharray={%4.1f %4.1f}",
			dl*dash1[0],dl*dash1[1]);
			break;
	    case 2:	sprintf(dashtype,"dasharray={%4.1f %4.1f}",
			dl*dash2[0],dl*dash2[1]);
			break;
	    case 3:	sprintf(dashtype,"dasharray={%4.1f %4.1f}",
			dl*dash3[0],dl*dash3[1]);
			break;
	    case 4:	sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
			dl*dash4[0],dl*dash4[1],dl*dash4[2],dl*dash4[3]);
			break;
	    case 5:	sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
			dl*dash5[0],dl*dash5[1],dl*dash5[2],dl*dash5[3]);
			break;
	    case 6:	sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f}",
			dl*dash6[0],dl*dash6[1],dl*dash6[2],dl*dash6[3]);
			break;
	    case 7:	sprintf(dashtype,"dasharray={%4.1f %4.1f %4.1f %4.1f %4.1f %4.1f}",
			dl*dash7[0],dl*dash7[1],dl*dash7[2],dl*dash7[3],dl*dash7[4],dl*dash7[5]);
			break;
	    }
	    PDF_setdashpattern(myPDF,dashtype);
	}
#endif
	
}


TERM_PUBLIC void
PDF_linewidth (double linewidth)
{
    PDF_PathClose();
    PDF_LineWidth = PDF_RESOLUTION * PDF_linewidth_factor * linewidth / 4.0;
    if (PDF_LineWidth < 0.1)
	PDF_LineWidth = 0.1;
    PDF_setlinewidth(myPDF, PDF_LineWidth);
}


TERM_PUBLIC void
PDF_move (unsigned int x, unsigned int y)
{
    if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
	return;

    PDF_PathOpen ();
    PDF_moveto(myPDF, x, y);

    PDF_xLast = x;
    PDF_yLast = y;
}


TERM_PUBLIC void
PDF_vector (unsigned int x, unsigned int y)
{
    if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
	return;

    if (!PDF_pathIsOpen) {
	PDF_PathOpen ();
	PDF_moveto(myPDF, PDF_xLast, PDF_yLast);
    }

    PDF_lineto(myPDF, x, y);

    PDF_xLast = x;
    PDF_yLast = y;
}

/* Helper function. Many symbols have an additional dot in their
 * center, so isolate its drawing into a separate function. */
static GP_INLINE void
PDF_dot (unsigned int x, unsigned int y)
{
    /* Imitate PS's way of creating a small dot by a zero-length line
     * segment with rounded endpoints */
    PDF_setlinecap(myPDF, 1); /* rounded ends */
    PDF_moveto(myPDF, x, y);
    PDF_lineto(myPDF, x, y);
    PDF_stroke(myPDF);
    PDF_setlinecap(myPDF, PDF_LineCap); /* restore ends */
}


TERM_PUBLIC void
PDF_point (unsigned int x, unsigned int y, int number)
{
    PDF_PathClose ();
    PDF_save(myPDF);

    if (number < 0 || term_pointsize 
	 * better compression and less coding for gnuplot) */
	/* NB: I use the do_pointsize() default implementation, which
	 * just stores the last set pointsize into `term_pointsize',
	 * to avoid introducing another static driver-local variable
	 * */
	PDF_translate(myPDF, x, y);
	PDF_scale(myPDF, term->h_tic / 2.0 * term_pointsize,
		  term->v_tic / 2.0 * term_pointsize);
	/* Correct linewidth to counter the scaling effect --- assume
	 * h_tic is usable, to avoid having to average h_ and v_tic */
	PDF_setlinewidth(myPDF,
			 PDF_LineWidth / (term->h_tic / 2.0 * term_pointsize));
	switch (number %= PDF_NUM_POINTTYPES) {
	case 0:			/* Plus */
	    PDF_moveto(myPDF, -1, 0);
	    PDF_lineto(myPDF, 1, 0);
	    PDF_moveto(myPDF, 0, -1);
	    PDF_lineto(myPDF, 0, 1);
	    PDF_stroke(myPDF);
	    break;
	case 2:			/* Star */
	    PDF_moveto(myPDF, -1, 0);
	    PDF_lineto(myPDF, 1, 0);
	    PDF_moveto(myPDF, 0, -1);
	    PDF_lineto(myPDF, 0, 1);
	    /* FALLTHROUGH */
	case 1:			/* Cross */
	    PDF_moveto(myPDF, -1, -1);
	    PDF_lineto(myPDF, 1, 1);
	    PDF_moveto(myPDF, 1, -1);
	    PDF_lineto(myPDF, -1, 1);
	    PDF_stroke(myPDF);
	    break;

/* For each x = 0..5, 4 shapes are defined:
 * 3 + 2*x --> hollow symbol with a dot at its center
 * 4 + 2*x --> solid symbol filled in linetype's color
 * 63 + x  --> hollow symbol without the center dot
 * 69 + x  --> symbol filled with white --> opaque symbol */

	case 63+0:		/* BoxEmpty */
	case 3+2*0:		/* Box */
	    PDF_moveto(myPDF, -1, -1);
	    PDF_lineto(myPDF, 1, -1);
	    PDF_lineto(myPDF, 1, 1);
	    PDF_lineto(myPDF, -1, 1);
	    PDF_closepath_stroke(myPDF);
	    if (number == 3) PDF_dot(0,0);
	    break;
	case 69+0:		/* BoxWhitefilled */
	    PDF_setgray_fill(myPDF, 1);
	    /* FALLTHROUGH */
	case 4+2*0:		/* BoxFilled */
	    PDF_moveto(myPDF, -1, -1);
	    PDF_lineto(myPDF, 1, -1);
	    PDF_lineto(myPDF, 1, 1);
	    PDF_lineto(myPDF, -1, 1);
	    PDF_closepath_fill_stroke(myPDF);
	    break;

	case 63+1:		/* CircleEmpty */
	case 3+2*1:		/* Circle */
	    PDF_circle(myPDF, 0, 0, 1);
	    PDF_stroke(myPDF);
	    if (number == 5) PDF_dot(0,0);
	    break;
	case 69+1:		/* CircleWhitefilled */
	    PDF_setgray_fill(myPDF, 1);
	    /* FALLTHROUGH */
	case 4+2*1:		/* CircleFilled */
	    PDF_circle(myPDF, 0, 0, 1);
	    PDF_fill_stroke(myPDF);
	    break;

	case 63+2:		/* TriangleUpEmpty */
	case 3+2*2:		/* TriangleUp */
	    PDF_moveto(myPDF, 0, 1.12);
	    PDF_lineto(myPDF, -1, -0.5);
	    PDF_lineto(myPDF, 1, -0.5);
	    PDF_closepath_stroke(myPDF);
	    if (number == 7) PDF_dot(0,0);
	    break;
	case 69+2:		/* TriangleUpWhitefilled */
	    PDF_setgray_fill(myPDF, 1);
	    /* FALLTHROUGH */
	case 4+2*2:			/* TriangleUpFilled */
	    PDF_moveto(myPDF, 0, 1.12);
	    PDF_lineto(myPDF, -1, -0.5);
	    PDF_lineto(myPDF, 1, -0.5);
	    PDF_closepath_fill_stroke(myPDF);
	    break;

	case 63+3:		/* TriangleDownEmpty */
	case 3+2*3:		/* TriangleDown */
	    PDF_moveto(myPDF, 0, -1.12);
	    PDF_lineto(myPDF, -1, 0.5);
	    PDF_lineto(myPDF, 1, 0.5);
	    PDF_closepath_stroke(myPDF);
	    if (number == 9) PDF_dot(0,0);
	    break;
	case 69+3:		/* TriangleDownWhitefilled */
	    PDF_setgray_fill(myPDF, 1);
	    /* FALLTHROUGH */
	case 4+2*3:		/* TriangleDownFilled */
	    PDF_moveto(myPDF, 0, -1.12);
	    PDF_lineto(myPDF, -1, 0.5);
	    PDF_lineto(myPDF, 1, 0.5);
	    PDF_closepath_fill_stroke(myPDF);
	    break;

	case 63+4:		/* DiamondEmpty */
	case 3+2*4:		/* Diamond */
	    PDF_moveto(myPDF, 0, -1);
	    PDF_lineto(myPDF, 1, 0);
	    PDF_lineto(myPDF, 0, 1);
	    PDF_lineto(myPDF, -1, 0);
	    PDF_closepath_stroke(myPDF);
	    if (number == 11) PDF_dot(0,0);
	    break;
	case 69+4:		/* DiamondWhitefilled */
	    PDF_setgray_fill(myPDF, 1);
	    /* FALLTHROUGH */
	case 4+2*4:		/* DiamondFilled */
	    PDF_moveto(myPDF, 0, -1);
	    PDF_lineto(myPDF, 1, 0);
	    PDF_lineto(myPDF, 0, 1);
	    PDF_lineto(myPDF, -1, 0);
	    PDF_closepath_fill_stroke(myPDF);
	    break;

	case 63+5:		/* PentagonEmpty */
	case 3+2*5:		/* Pentagon */
	    PDF_moveto(myPDF, 0, 1);
	    PDF_lineto(myPDF, -0.95, 0.31);
	    PDF_lineto(myPDF, -0.58, -0.81);
	    PDF_lineto(myPDF, +0.58, -0.81);
	    PDF_lineto(myPDF, +0.95, 0.31);
	    PDF_closepath_stroke(myPDF);
	    if (number == 13) PDF_dot(0,0);
	    break;
	case 69+5:		/* PentagonWhitefilled */
	    PDF_setgray_fill(myPDF, 1);
	    /* FALLTHROUGH */
	case 4+2*5:		/* PentagonFilled */
	    PDF_moveto(myPDF, 0, 1);
	    PDF_lineto(myPDF, -0.95, 0.31);
	    PDF_lineto(myPDF, -0.58, -0.81);
	    PDF_lineto(myPDF, +0.58, -0.81);
	    PDF_lineto(myPDF, +0.95, 0.31);
	    PDF_closepath_fill_stroke(myPDF);
	    break;

/* 15 + (0..15): circles with varying parts of'em filled. The added
 * number is a bit-pattern of the 4 quadrants: 1 signals a quadrant
 * filled */
	case 15+0:
	    PDF_moveto(myPDF, 0, 0);
	    PDF_lineto(myPDF, 0, 1);
	    PDF_arc(myPDF, 0, 0, 1, 90, 360+90);
	    PDF_closepath_stroke(myPDF);
	    break;

/* Generalize common code into a macro... */
#define CIRCLE_SINGLE_PIESLICE(x, y, angle1, angle2)		\
	    PDF_moveto(myPDF, 0, 0);				\
	    PDF_lineto(myPDF, (x), (y));			\
	    PDF_arc(myPDF, 0, 0, 1, (angle1), (angle2));	\
	    PDF_lineto(myPDF, 0, 0);				\
	    PDF_closepath(myPDF);				\
	    PDF_fill_stroke(myPDF);				\
	    PDF_arc(myPDF, 0, 0, 1, (angle2), (angle1) + 360);	\
	    PDF_stroke(myPDF);					\
	    break;

#define CIRCLE_SINGLE_QUADRANT(x, y, angle)			\
	    CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+90);
	case 15+1:
	    CIRCLE_SINGLE_QUADRANT(1, 0, 0);
	case 15+2:
	    CIRCLE_SINGLE_QUADRANT(0, 1, 90);
	case 15+4:
	    CIRCLE_SINGLE_QUADRANT(-1, 0, 180);
	case 15+8:
	    CIRCLE_SINGLE_QUADRANT(0, -1, 270);
#undef CIRCLE_SINGLE_QUADRANT

#define CIRCLE_TWO_NEIGHBOR_QUADRANTS(x, y, angle)		\
	    CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+180)
	case 15+3:
	    CIRCLE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
	case 15+6:
	    CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
	case 15+12:
	    CIRCLE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
	case 15+9:
	    CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
#undef CIRCLE_TWO_NEIGHBOR_QUADRANTS

#define CIRCLE_TWO_OPPOSING_QUADRANTS(x, y, angle)		\
	    PDF_moveto(myPDF, 0, 0);				\
	    PDF_lineto(myPDF, x, y);				\
	    PDF_arc(myPDF, 0, 0, 1, angle, angle + 90);		\
	    PDF_lineto(myPDF, 0, 0);				\
	    PDF_fill_stroke(myPDF);				\
	    PDF_moveto(myPDF, 0, 0);				\
	    PDF_lineto(myPDF, -x, -y);				\
	    PDF_arc(myPDF, 0, 0, 1, angle + 180, angle + 270);	\
	    PDF_lineto(myPDF, 0, 0);				\
	    PDF_fill_stroke(myPDF);				\
	    PDF_arc(myPDF, 0, 0, 1, angle + 90, angle + 360);	\
	    PDF_stroke(myPDF);					\
	    break;
	case 15+5:
	    CIRCLE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
	case 15+10:
	    CIRCLE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
#undef CIRCLE_TWO_OPPOSING_QUADRANTS

#define CIRCLE_THREE_QUADRANTS(x, y, angle)			\
	    CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+270)
	case 15+7:
	    CIRCLE_THREE_QUADRANTS(1, 0, 0);
	case 15+14:
	    CIRCLE_THREE_QUADRANTS(0, 1, 90);
	case 15+13:
	    CIRCLE_THREE_QUADRANTS(-1, 0, 180);
	case 15+11:
	    CIRCLE_THREE_QUADRANTS(0, -1, 270);
#undef CIRCLE_THREE_QUADRANTS
#undef CIRCLE_SINGLE_PIESLICE

	case 15+15:
	    PDF_circle(myPDF, 0, 0, 1);
	    PDF_closepath_fill_stroke(myPDF);
	    break;


/*************************************************************************/
/* 31 + (0..15): squares with different quadrants of them filled in. */
/*************************************************************************/
/*************************************************************************/
/* 47 + (0..15): diamonds with filled quadrants as given by bit pattern  */
/*   Diamonds are drawn as squares rotated by 45 degrees, so can use
 * fall-through from diamond to squares, and re-use some macros. */
/*************************************************************************/
	case 47+0:
	    PDF_rotate(myPDF, 45);
	    /* FALLTHROUGH */
	case 31+0:
	    PDF_moveto(myPDF, 0, 0);
	    PDF_lineto(myPDF, 0, 1);
	    PDF_lineto(myPDF, -1, 1);
	    PDF_lineto(myPDF, -1, -1);
	    PDF_lineto(myPDF, 1, -1);
	    PDF_lineto(myPDF, 1, 1);
	    PDF_lineto(myPDF, 0, 1);
	    PDF_stroke(myPDF);
	    break;

	case 47+15:
	    PDF_rotate(myPDF, 45);
	    /* FALLTHROUGH */
	case 31+15:
	    PDF_moveto(myPDF, -1, 1);
	    PDF_lineto(myPDF, -1, -1);
	    PDF_lineto(myPDF, 1, -1);
	    PDF_lineto(myPDF, 1, 1);
	    PDF_closepath_fill_stroke(myPDF);
	    break;

/* macros defining shapes of the partly filled symbols. Done by
 * rotating the starting point (x0, y0) by 90 degrees or 45 degrees
 * (with length adjustment).  The rotations can be done without
 * trigonometric function calls, since their values are known:
 * cos(90)=0, sin(90)=1, cos(45)=sin(45)=1/sqrt(2).  A good compiler
 * should be able to optimize away all the local variables and
 * loops...  */

#define SQUARE_SINGLE_PIESLICE(x0, y0, quadrants)			\
	    {								\
		int quadrant = 0;					\
		int x= x0, y=y0;					\
		PDF_moveto(myPDF, 0, 0);				\
		PDF_lineto(myPDF, x, y);				\
		/* poor man's rotation by 45 and 90 degrees around the	\
		 * square's outline. */					\
		while (quadrant++ < quadrants) {			\
		    int dummy;						\
		    PDF_lineto(myPDF, x-y, x+y);			\
		    dummy = x; x = -y; y = dummy;			\
		}							\
		PDF_lineto(myPDF, x, y);				\
		PDF_closepath_fill_stroke(myPDF);			\
		PDF_moveto(myPDF, x, y);				\
		while (quadrant++ enhanced_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 */
    }

    PDF_restore(myPDF);

    /* We can do text justification by running the entire top level string */
    /* through 2 times, with the ENHpdf_sizeonly flag set the first time.   */
    /* After seeing where the final position is, we then offset the start  */
    /* point accordingly and run it again.                                 */
    if (PDF_TextJust == RIGHT || PDF_TextJust == CENTRE) {
	int justification = PDF_TextJust;
	int x_offset = PDF_xLast - x;
	int y_offset = 0;

	if (PDF_TextAngle != 0)
	    y_offset = PDF_yLast - y;
	PDF_TextJust = LEFT;
	ENHpdf_sizeonly = FALSE;

	if (justification == RIGHT) {
	    ENHPDF_put_text(x - x_offset, y - y_offset, original_string);
	} else if (justification == CENTRE) {
	    ENHPDF_put_text(x - x_offset/2, y - y_offset/2, original_string);
	}
	PDF_TextJust = justification;
    }

}

#endif /* TERM_BODY */

#ifdef TERM_TABLE
TERM_TABLE_START (pdf_driver)
    "pdf", "PDF (Portable Document File) file driver",
    0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ ,
    0 /* vtic */ , 0 /* htic */ ,
    PDF_options, PDF_init, PDF_reset, PDF_text, null_scale, PDF_graphics,
    PDF_move, PDF_vector, PDF_linetype, PDF_put_text, PDF_text_angle,
    PDF_justify_text, PDF_point, do_arrow, PDF_set_font, do_pointsize,
    TERM_BINARY|TERM_CAN_DASH|TERM_LINEWIDTH|TERM_FONTSCALE,
    0 /* suspend */, 0 /* resume */ , PDF_boxfill, PDF_linewidth
#   ifdef USE_MOUSE
   , 0, 0, 0, 0, 0 /* no mouse support for pdf */
#   endif
   , PDF_make_palette,
   PDF_previous_palette,
   PDF_set_color,
   PDF_filled_polygon
   , PDF_image
   , ENHPDF_OPEN, ENHPDF_FLUSH, do_enh_writec
TERM_TABLE_END (pdf_driver)
#undef LAST_TERM
#define LAST_TERM pdf_driver
#endif /* TERM_TABLE */

#endif /* TERM_PROTO_ONLY */

#ifdef TERM_HELP
START_HELP(pdf)
"1 pdf",
"?commands set terminal pdf",
"?set terminal pdf",
"?set term pdf",
"?terminal pdf",
"?term pdf",
"?pdf",
" [DEPRECATED] This terminal uses the non-free library PDFlib (GmbH Munchen)"
" to produce files in Portable Document Format. Unless you have a commercial",
" license for PDFlib and need some special feature it provides you would do",
" better to use the cairo pdf terminal instead.  Gnuplot can also export PDF",
" files from wxt or qt interactive terminal sessions.",
"",
" Syntax:",
"       set terminal pdf {monochrome|color|colour}",
"                        {{no}enhanced}",
"                        {fname \"\"} {fsize }",
"                        {font \"{,}\"} {fontscale }",
"                        {linewidth } {rounded|butt}",
"                        {dl }}",
"                        {size {unit},{unit}}",
"",
" The default is to use a different color for each line type. Selecting",
" `monochome` will use black for all linetypes, Even in in mono mode",
" you can still use explicit colors for filled areas or linestyles.",
"",
" where  is the name of the default font to use (default Helvetica)",
" and  is the font size (in points, default 12).",
" For help on which fonts are available or how to install new ones, please",
" see the documentation for your local installation of pdflib.",
"",
" The `enhanced` option enables enhanced text processing features",
" (subscripts, superscripts and mixed fonts). See `enhanced`.",
"",
" The width of all lines in the plot can be increased by the factor ",
" specified in `linewidth`. Similarly `dashlength` is a multiplier for the",
" default dash spacing.",
"",
" `rounded` sets line caps and line joins to be rounded; `butt` is the",
" default, butt caps and mitered joins.",
"",
" The default size for PDF output is 5 inches by 3 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 possible (currently only cm).",
""
END_HELP(pdf)
#endif

Web Proxy Viewer  |  New URL  |  Original Page