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

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

/*------------------------------------------------------------------------------------------------------------------------------------
	GNUPLOT - svg.trm

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

	This terminal driver supports:
		W3C Scalable Vector Graphics

	AUTHOR

		Amedeo Farello
		afarello@libero.it

	HEAVILY MODIFIED by

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

	DomTerm support

		Per Bothner  

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

/* PM3D support by Johannes Zellner , May-16-2002 */
/* set_color fixes by Petr Mikulik , June-10-2002 */
/* ISO-Latin encoding, Font selection fixes, option "fixed|dynamic" by
 * Wilhelm Braunschober , Feb-21-2002 */

/*
 * Additional code for gnuplot versions 4.2 and 4.3
 * Ethan Merritt  
 *
 *   Tweaked code for compatibility with Sodipodi svg viewer/editor.
 *   Added enhanced text support.
 *   Additional line properties.
 *   Increase resolution by adding a coordinate scale factor.
 *   Support dashed lines, TC_* color model.
 *   Change path markup from      to   attribute='foo'
 *
 * Additional code for gnuplot versions 4.5
 * Ethan Merritt  
 *
 *   Wrap each plot in a named group 
 *   Set the name using 'set term svg name "foo"'
 *   Background option
 *   Bitmap image support by creating and linking to external png files
 *   Mouse-tracking with coordinate readout.
 *   Version 4.7 (April 2012) hypertext support
 *
 * Contributed by 
 *   Javascript code to toggle plots on/off
 *
 * Revised font sizing Oct 2012
 *   specify font-size without "pt" units.
 *
 * Inline image data in Base64 encoding
 *   Daniel Sebald May 2016
 *
 * Transition to SVG 2.0
 *   remove DTD
 *   remove option "fontfile" and references to SVG fonts
 */

/*
 * Code for gnuplot version 4.5
 *   Bold -> font-weight:bold
 *   Italic -> font-style:italic
 * Rich Seymour 
 */

#include "driver.h"

#ifdef TERM_REGISTER
register_term(svg)
#endif

#ifdef TERM_PROTO
TERM_PUBLIC void SVG_options(void);
TERM_PUBLIC void SVG_init(void);
TERM_PUBLIC void SVG_graphics(void);
TERM_PUBLIC void SVG_text(void);
TERM_PUBLIC void SVG_linetype(int linetype);
TERM_PUBLIC void SVG_dashtype(int type, t_dashtype *custom_dash_type);
TERM_PUBLIC void SVG_move(unsigned int x, unsigned int y);
TERM_PUBLIC void SVG_vector(unsigned int x, unsigned int y);
TERM_PUBLIC void SVG_put_text(unsigned int x, unsigned int y, const char *str);
TERM_PUBLIC void SVG_reset(void);
TERM_PUBLIC int SVG_justify_text(enum JUSTIFY mode);
TERM_PUBLIC int SVG_text_angle(float ang);
TERM_PUBLIC void SVG_point(unsigned int x, unsigned int y, int pointstyle);
TERM_PUBLIC int SVG_set_font(const char *font);
/* TERM_PUBLIC void SVG_pointsize(double pointsize); */
TERM_PUBLIC void SVG_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height);
TERM_PUBLIC void SVG_linewidth(double linewidth);
TERM_PUBLIC int SVG_make_palette(t_sm_palette *);
TERM_PUBLIC void SVG_previous_palette(void);
TERM_PUBLIC void SVG_set_color(t_colorspec *);
TERM_PUBLIC void SVG_filled_polygon(int, gpiPoint *);
TERM_PUBLIC void SVG_layer(t_termlayer syncpoint);

TERM_PUBLIC void ENHsvg_OPEN(char *, double, double, TBOOLEAN, TBOOLEAN, int);
TERM_PUBLIC void ENHsvg_FLUSH(void);
TERM_PUBLIC void ENHsvg_put_text(unsigned int, unsigned int, const char *);
TERM_PUBLIC void ENHsvg_writec(int);

TERM_PUBLIC void SVG_path(int p);
TERM_PUBLIC void SVG_hypertext(int, const char *);

#ifdef WRITE_PNG_IMAGE
TERM_PUBLIC void SVG_image(unsigned m, unsigned n, coordval *image, gpiPoint *corner, t_imagecolor color_mode);
#endif

#define SVG_SCALE	100.	/* Coordinate accuracy is 1/SVG_SCALE pixel */
#define PREC		2	/* Decimal places needed for SVG_SCALEd values */
#define Y(y) ((float)((int)term->ymax - (int)y) / SVG_SCALE)
#define X(x) ((float)(x) / SVG_SCALE)

#define SVG_XMAX	(600 * SVG_SCALE)
#define SVG_YMAX	(480 * SVG_SCALE)

#endif /* TERM_PROTO */

#ifndef TERM_PROTO_ONLY
#ifdef TERM_BODY

static t_sm_palette SVG_palette;
static unsigned char SVG_red = 0;
static unsigned char SVG_green = 0;
static unsigned char SVG_blue = 0;
static double SVG_alpha = 0.0;
static unsigned char SVG_color_mode = TC_DEFAULT;
static unsigned int SVG_rgb = 0;
static unsigned int SVG_patterncolor[8];
static char *SVG_linecolor = NULL;
static char *SVG_name = NULL;
static char *SVG_scriptdir = NULL;
static TBOOLEAN SVG_mouseable = FALSE;
static TBOOLEAN SVG_standalone = FALSE;
static TBOOLEAN SVG_domterm = FALSE;
static TBOOLEAN SVG_emit_doctype = TRUE;
static TBOOLEAN SVG_animate = FALSE;

static TBOOLEAN SVG_groupFilledIsOpen = FALSE; /* open pm3d group flag*/
static TBOOLEAN SVG_inTextBox = FALSE;

struct SVG_PEN
{
    double width;
    char color[8];
};

static unsigned int SVG_xSize = SVG_XMAX; /* plot horizontal size */
static unsigned int SVG_ySize = SVG_YMAX; /* plot vertical size*/
static TBOOLEAN SVG_fixed_size = TRUE;  /* make SVG viewer size fixed */

static unsigned int SVG_xLast = UINT_MAX; /* current pen horizontal position*/
static unsigned int SVG_yLast = UINT_MAX;	/* current pen vertical position*/

static int SVG_LineType = LT_NODRAW;	/* current line type*/
static double SVG_LineWidth = 1.0; /* current line width*/
static double SVG_linewidth_factor = 1.0; /* Multiplier for linewidths */
static double SVG_dashlength = 1.0; /* Multiplier for dash patterns */
static t_linecap SVG_linecap = BUTT; /* linejoin and linecap */
static float SVG_TextAngle = 0;	/* current text orientation*/
static enum JUSTIFY SVG_TextJust = LEFT; /* current text justification*/

/* default text font family: */
static char *SVG_fontNameDef = NULL;
static char *SVG_fontStyleDef = NULL; /* default font style */
static char *SVG_fontWeightDef = NULL; /* default font weight */
static double SVG_fontSizeDef = 12;	/* default text size*/
/* current text font family: */
static char *SVG_fontNameCur = NULL;
static char *SVG_fontStyleCur = NULL; /* current font style */
static char *SVG_fontWeightCur = NULL; /* current font weight */
static double SVG_fontSizeCur = 12;	/* current text size*/
static double SVG_fontscale = 1.0;	/* multiplier for nominal font size */
static TBOOLEAN SVG_groupIsOpen = FALSE; /* open group flag*/
static TBOOLEAN SVG_pathIsOpen = FALSE; /* open path flag*/
static unsigned int SVG_path_count = 0;	/* size of current path*/
static struct SVG_PEN SVG_pens[16];	/* pen descriptors*/

static int SVG_fillPattern = -1; /* active fill pattern (-1 == undefined) */
static unsigned int SVG_fillPatternIndex = 0;
static int SVG_background = -1;
static int SVG_plotno = 0;
static TBOOLEAN SVG_gridline = FALSE;
static TBOOLEAN SVG_hasgrid = FALSE;

static double SVG_fontAscent  = 0;	/* estimated current font ascent*/
static double SVG_fontDescent = 0;	/* estimated current font descent*/
static double SVG_fontLeading = 0;	/* estimated current font leading*/
static double SVG_fontAvWidth = 0;	/* estimated current font char average width*/

static short SVG_Pen_RealID(int);
static void SVG_PathOpen(void);
static void SVG_PathClose(void);
static void SVG_AddSpaceOrNewline(void);
static void SVG_GroupOpen(void);
static void SVG_GroupClose(void);
static void SVG_SetFont(const char *name, double size);
static void SVG_GroupFilledOpen(void);
static void SVG_GroupFilledClose(void);
static void SVG_StyleColor(const char*);
static void SVG_StyleFillColor(void);
static void SVG_local_reset(void);
static void SVG_DefineFillPattern(int fillpat);
static void SVG_MoveForced(unsigned int x, unsigned int y);
static void SVG_write_preamble(void);

/* Stuff for enhanced text mode */
static int ENHsvg_string_state = 0;
static double ENHsvg_x_offset = 0;
static TBOOLEAN ENHsvg_preserve_spaces = FALSE;

/* Support for dashed lines */
#define SVG_dashtypes 5
static char *SVG_defaultdashpattern[SVG_dashtypes] = {
    "", " 5,8", " 2,4", " 8,4,2,4", " 9,4,1,4,1,4"
};
static char *SVG_axis_dashpattern = "2,4";
static int SVG_dasharray[SVG_dashtypes][7] = {
	{ 0,0,0,0,0,0,0},
	{5,8, 0,0,0,0,0},
	{2,4, 0,0,0,0,0},
	{8,4,2,4, 0,0,0},
	{9,4,1,4,1,4, 0}
};
static char *SVG_dashpattern = NULL;
static char  SVG_custom_dash_pattern[64];

/* Hypertext support */
static double SVG_hypertext_fontSize = 0;
static char *SVG_hypertext_fontName = NULL;
static char *SVG_hypertext_fontStyle = NULL;
static char *SVG_hypertext_fontWeight = NULL;

/* Support for embedded hypertext */
static char *SVG_hypertext_text = NULL;

/*------------------------------------------------------------------------------------------------------------------------------------
	SVG_Pen_RealID
------------------------------------------------------------------------------------------------------------------------------------*/
static short
SVG_Pen_RealID (int inPenCode)
{
    if (inPenCode >= 13)
	inPenCode %= 13;	/* normalize pen code*/
    inPenCode += 3;
    if (inPenCode < 0)
	inPenCode = 0;		/* LT_BACKGROUND should use background color */

    return (inPenCode);
}

/*------------------------------------------------------------------------------------------------------------------------------------
	SVG_GroupOpen
------------------------------------------------------------------------------------------------------------------------------------*/
static void
SVG_GroupOpen ()
{
    SVG_GroupFilledClose();
    if (!SVG_groupIsOpen) {

	fprintf (gpoutfile, "\n");

	SVG_groupIsOpen = TRUE;
    }
}

/*------------------------------------------------------------------------------------------------------------------------------------
	SVG_GroupClose
------------------------------------------------------------------------------------------------------------------------------------*/
static void
SVG_GroupClose ()
{
    SVG_GroupFilledClose();
    if (SVG_groupIsOpen) {
	  fputs ("\n", gpoutfile);
	  SVG_groupIsOpen = FALSE;
	  SVG_fillPattern = -1;
      }
}

/*------------------------------------------------------------------------------------------------------------------------------------
	SVG_PathOpen
------------------------------------------------------------------------------------------------------------------------------------*/
static void
SVG_PathOpen ()
{
    if (!SVG_pathIsOpen) {
	SVG_GroupFilledClose();

	fputs ("\t");
	SVG_path_count = 0;
	SVG_pathIsOpen = FALSE;
    }
}

/*------------------------------------------------------------------------------------------------------------------------------------
	SVG_AddSpaceOrNewline
------------------------------------------------------------------------------------------------------------------------------------*/
static void
SVG_AddSpaceOrNewline ()
{
    if (SVG_path_count % 8 == 0)	/* avoid excessive line length*/
	fputs ("\n\t\t", gpoutfile);
    else
      fputs (" ", gpoutfile);
}

/*------------------------------------------------------------------------------------------------------------------------------------
	SVG_SetFont
------------------------------------------------------------------------------------------------------------------------------------*/
static void
SVG_SetFont (const char *name, double size)
{
    if (name != SVG_fontNameCur) {
	free(SVG_fontNameCur);
	SVG_fontNameCur = gp_strdup(name);
    }
    SVG_fontSizeCur = size;

/* since we cannot interrogate SVG about text properties and according
 * to SVG 1.0 W3C Candidate Recommendation 2 August 2000 the
 * "line-height" of the 'text' element is defined to be equal to the
 * 'font-size' (!), we have to to define font properties in a less
 * than optimal way */

    SVG_fontAscent  = (SVG_fontSizeCur * 0.90 * SVG_SCALE);
    SVG_fontDescent = (SVG_fontSizeCur * 0.25 * SVG_SCALE);
    SVG_fontLeading = (SVG_fontSizeCur * 0.35 * SVG_SCALE);
    SVG_fontAvWidth = (SVG_fontSizeCur * 0.70 * SVG_SCALE);

    term->h_char = SVG_fontAvWidth;
    term->v_char = (SVG_fontAscent + SVG_fontDescent + SVG_fontLeading);
}

static void
SVG_GroupFilledOpen()
{
    if (!SVG_groupFilledIsOpen) {
	SVG_PathClose();
	fputs("\t\n",
	      gpoutfile);
	SVG_groupFilledIsOpen = TRUE;
    }
}

static void
SVG_GroupFilledClose()
{
    if (SVG_groupFilledIsOpen) {
	fputs("\t\n", gpoutfile);
	SVG_groupFilledIsOpen = FALSE;
    }
}

static void
SVG_StyleColor(const char* paint)
{
    if (SVG_color_mode == TC_RGB)
	fprintf(gpoutfile, "%s = 'rgb(%3d, %3d, %3d)'", paint, SVG_red, SVG_green, SVG_blue);
    else if (SVG_color_mode == TC_LT)
	fprintf(gpoutfile, "%s = '%s'", paint, SVG_linecolor);
    else
	fprintf(gpoutfile, "%s = 'currentColor'", paint);
}

static void
SVG_StyleFillColor()
{
    SVG_StyleColor("fill");
}

static void
SVG_DefineFillPattern(int fillpat)
{
    char *path;
    char *;
    unsigned int newcolor;

    fillpat %= 8;

    if (SVG_color_mode == TC_RGB || SVG_color_mode == TC_LT)
	newcolor = SVG_rgb;
    else
	newcolor = SVG_patterncolor[fillpat];

    if (fillpat != SVG_fillPattern || newcolor != SVG_patterncolor[fillpat]) {
	SVG_fillPattern = fillpat;
	SVG_patterncolor[fillpat] = newcolor;
	SVG_PathClose();
	SVG_fillPatternIndex++;

	fprintf(gpoutfile,
	    "\t\n"
	    "\t\t\n",
	    SVG_fillPatternIndex);
	switch (fillpat) {
	    default:
	    case 0:
		    path="";
		    break;
	    case 1:
		    path="M0,0 L8,8 M0,8 L8,0";
		    break;
	    case 2:
		    path="M0,0 L8,8 M0,8 L8,0 M0,4 L4,8 L8,4 L4,0 L0,4";
		    break;
	    case 3:
		    path="M0,0 L0,8 L8,8 L8,0 L0,0";
		    ;
		    break;
	    case 4:
		    path="M-4,0 L8,12 M0,-4 L12,8";
		    break;
	    case 5:
		    path="M-4,8 L8,-4 M0,12 L12,0";
		    break;
	    case 6:
		    path="M-2,8 L4,-4 M0,12 L8,-4 M4,12 L10,0";
		    break;
	    case 7:
		    path="M-2,0 L4,12 M0,-4 L8,12 M4,-4 L10,8";
		    break;
	}
	if (*path) {
	    char *figure = "fill:none;";
	    if (!strcmp(style,"fill")) figure = "stroke:none;";
	    if (SVG_color_mode == TC_RGB || SVG_color_mode == TC_LT)
		fprintf(gpoutfile,"\t\t\t\n",
			figure, style,
			(newcolor >> 16) & 0xff, (newcolor >> 8) & 0xff, newcolor & 0xff,
			path);
	    else
		fprintf(gpoutfile, "\t\t\t\n",
			figure, style, path);
	}
	fputs("\t\t\n" "\t\n", gpoutfile);
    }
}

static void
SVG_MoveForced(unsigned int x, unsigned int y)
{
    if (SVG_path_count > 512)
	SVG_PathClose();

    SVG_PathOpen ();

    fprintf (gpoutfile, "M%.*f,%.*f", PREC, X(x), PREC, Y(y));
    SVG_path_count++;

    SVG_AddSpaceOrNewline ();

    SVG_xLast = x;
    SVG_yLast = y;
}

/*------------------------------------------------------------------------------------------------------------------------------------
	SVG_options
------------------------------------------------------------------------------------------------------------------------------------*/
TERM_PUBLIC void
SVG_options ()
{
    /* Annoying hack to handle the case of 'set termoption' after */
    /* we have already initialized the terminal settings.         */
    if (!almost_equals(c_token-1, "termopt$ion"))
	SVG_local_reset();

    if (strcmp(term->name, "domterm") == 0) {
        SVG_emit_doctype = FALSE;
        SVG_domterm = TRUE;
    } else {
        SVG_emit_doctype = TRUE;
        SVG_domterm = FALSE;
    }

    /* Minimal initialization in case we error out of options parsing */
    SVG_set_font("");

    while (!END_OF_COMMAND) {
	if (almost_equals(c_token, "s$ize")) {
	    double value;

	    c_token++;

	    if (END_OF_COMMAND)
		int_error(c_token,"expecting x size");
	    value = real_expression();
	    if (value < 2)
		int_error(c_token,"x size out of range");
	    SVG_xSize = value * SVG_SCALE;

	    if (equals(c_token,","))
		c_token++;
	    if (END_OF_COMMAND)
		int_error(c_token,"expecting y size");
	    value = real_expression();
	    if (value < 2)
		int_error(c_token,"y size out of range");
	    SVG_ySize = value * SVG_SCALE;
	    continue;
	}

	if (equals(c_token, "mouse") || almost_equals(c_token, "mous$ing")) {
	    c_token++;
	    SVG_mouseable = TRUE;
	    continue;
	}

	if (almost_equals(c_token, "stand$alone")) {
	    c_token++;
	    SVG_standalone = TRUE;
	    continue;
	}

	if (equals(c_token, "name")) {
	    c_token++;
	    SVG_name = try_to_get_string();
	    if (!SVG_name)
		    int_error(c_token,"expecting a plot name");
	    if (SVG_name[strspn(SVG_name,
		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_1234567890")])
		    int_error(c_token-1,"name must contain only alphanumerics or _");
	    continue;
	}

	if (equals(c_token, "jsdir")) {
	    c_token++;
	    SVG_scriptdir = try_to_get_string();
	    continue;
	}

	if (almost_equals(c_token, "d$ynamic")) {
	    c_token++;
	    SVG_fixed_size = FALSE;
	    continue;
	}

	if (almost_equals(c_token, "fi$xed")){
	    c_token++;
	    SVG_fixed_size = TRUE;
	    continue;
	}

	if (almost_equals(c_token, "enh$anced")) {
	    c_token++;
	    term->put_text = ENHsvg_put_text;
	    term->flags |= TERM_ENHANCED_TEXT;
	    continue;
	}

	if (almost_equals(c_token, "noenh$anced")) {
	    c_token++;
	    term->put_text = SVG_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,"expecting font name");
	    comma = strrchr(s,',');
	    if (comma && (1 == sscanf(comma + 1, "%lf", &SVG_fontSizeDef)))
		*comma = '\0';

	    if (*s) {
		char *bold, *italic;

		if (!((bold = strstr(s," bold"))))
		    bold = strstr(s," Bold");

		if (!((italic = strstr(s," italic"))))
		    italic = strstr(s," Italic");

		free(SVG_fontNameDef);
		SVG_fontNameDef = s;
		if (italic) {
		    SVG_fontStyleDef = "italic";
		    SVG_fontNameDef[strlen(s) - strlen(italic)] = NUL;
		} else  {
		    SVG_fontStyleDef = "normal";
		}
		if (bold) {
		    SVG_fontWeightDef="bold";
		    SVG_fontNameDef[strlen(s) - strlen(bold)] = NUL;
		} else {
		    SVG_fontWeightDef = "normal";
		}
	    } else
		free(s);
	    continue;
	}

	if (equals(c_token, "fontscale")) {
	    c_token++;
	    SVG_fontscale = real_expression();
	    if (SVG_fontscale 

Web Proxy Viewer  |  New URL  |  Original Page