From 82fb5c5bffc116a35736ab016275e36a1638c718 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 21 2020 08:21:20 +0000 Subject: Apply patch gnuplot-4.2.0-fonts.patch patch_name: gnuplot-4.2.0-fonts.patch present_in_specfile: true --- diff --git a/term/gd.trm b/term/gd.trm index b3a480c..bc6b437 100644 --- a/term/gd.trm +++ b/term/gd.trm @@ -1004,7 +1004,7 @@ PNG_options() if (external_default) png_state.ttffont = gp_strdup(external_default); else /* Might as well try some plausible font; it's no worse than failing immediately */ - png_state.ttffont = gp_strdup("arial"); + png_state.ttffont = gp_strdup("/usr/share/fonts/dejavu/DejaVuSans.ttf"); free(png_state.default_ttffont); png_state.default_ttffont = gp_strdup(png_state.ttffont); diff --git a/term/gd.trm.font b/term/gd.trm.font new file mode 100644 index 0000000..b3a480c --- /dev/null +++ b/term/gd.trm.font @@ -0,0 +1,3048 @@ +/* Hello, Emacs, this is -*-C-*- + * $Id: gd.trm,v 1.189 2016/12/06 05:17:18 sfeam Exp $ + */ + +/* GNUPLOT -- gd.trm */ + +/*[ + * Copyright 1998, 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 file is included by ../term.c. + * + * This terminal driver supports PNG and JPEG output using + * GD library version 2 + * + * To Use: + * + * set terminal png ?options ...? + * + * Where an option is: + * + * transparent - generate transparent PNGs. The first color will + * be the transparent one. + * + * interlace - generate interlaced PNGs. + * + * image size (in pixels) + * + * font size (tiny,small,medium,large,giant) + * + * font name (TrueType or Adobe Type 1 font name is passed to libgd) + * + * EAM Dec 2010: Obsolete! + * xrrggbb - sets the next color. x is the literal character 'x', + * rrggbb are the red green and blue components in hex. For example + * x00ff00 is green. The background color is set first, then the + * color borders, then the X & Y axis, then the plotting colors. + * (The wierd color spec is in order to get around limitations + * in gnuplot's scanner.) + * + * This driver is modeled after the PBM driver pbm.trm. + * + * AUTHORS + * Sam Shen + * Alex Woo + * Ethan A Merritt + * + * CONTRIBUTORS + * Alfred Reibenschuh or + * Ben Laurie + * + * This version outputs either indexed or truecolor (24-bit RGB) images + * The default size is 640x480 pixels. + * + ****************************************************************************** + * PLEASE READ * + * This driver uses the gd library, available from http://www.libgd.org * + * This driver allows you to use TrueType, OpenType, or Adobe Type 1 fonts. * + * If you have libgd version 2.0.36 or later, you may also be able to access * + * any fonts that are managed by the fontconfig utility. * + * You can use this driver without having any TrueType fonts installed, * + * but the default fonts are comparatively limited. * + ****************************************************************************** + * + * Petr Mikulik, Jan 1999: terminal entries for PM3D functionality + * Ethan Merritt, May 2001: modified gd/gif driver to produce png instead; + * added support for line width and TrueType fonts + * Shige Takeno, Mar 2011: deal with libgd built to use SJIS rather than UTF-8 + * Ethan Merritt, Apr 2012: Don't claim to support versions 1.x of libgd + * kmiya@culti, Nov 2016: sixelgd terminal + */ + +#define GD_DEFINED_COLORS 96 /* Must not exceed size of pm3d_color_names_tbl[] */ + +#include "driver.h" + +#ifdef TERM_REGISTER +register_term(png) +#endif + +#ifdef TERM_PROTO +TERM_PUBLIC void PNG_options __PROTO((void)); +TERM_PUBLIC void PNG_init __PROTO((void)); +TERM_PUBLIC void PNG_graphics __PROTO((void)); +TERM_PUBLIC void PNG_text __PROTO((void)); +TERM_PUBLIC void PNG_linetype __PROTO((int linetype)); +TERM_PUBLIC void PNG_linewidth __PROTO((double linewidth)); +TERM_PUBLIC void PNG_move __PROTO((unsigned int x, unsigned int y)); +TERM_PUBLIC void PNG_vector __PROTO((unsigned int x, unsigned int y)); +TERM_PUBLIC void PNG_put_text __PROTO((unsigned int x, unsigned int y, const char str[])); +TERM_PUBLIC int PNG_justify_text __PROTO((enum JUSTIFY mode)); +TERM_PUBLIC void PNG_point __PROTO((unsigned int x, unsigned int y, int number)); +TERM_PUBLIC int PNG_text_angle __PROTO((int ang)); +TERM_PUBLIC void PNG_reset __PROTO((void)); +TERM_PUBLIC int PNG_set_font __PROTO((const char *fontname)); +TERM_PUBLIC void PNG_pointsize __PROTO((double ptsize)); +TERM_PUBLIC void PNG_boxfill(int, unsigned int, unsigned int, unsigned int, unsigned int); +TERM_PUBLIC int PNG_make_palette (t_sm_palette *); +/* TERM_PUBLIC void PNG_previous_palette (void); */ +TERM_PUBLIC void PNG_set_color (t_colorspec *); +TERM_PUBLIC void PNG_filled_polygon (int, gpiPoint *); +TERM_PUBLIC void PNG_image __PROTO((unsigned int, unsigned int, coordval *, gpiPoint *, t_imagecolor)); + +/* To support "set term png enhanced" */ +TERM_PUBLIC void ENHGD_put_text __PROTO((unsigned int x, unsigned int y, const char str[])); +TERM_PUBLIC void ENHGD_OPEN __PROTO((char * fontname, double fontsize, + double base, TBOOLEAN widthflag, TBOOLEAN showflag, + int overprint)); +TERM_PUBLIC void ENHGD_FLUSH __PROTO((void)); + +#ifdef EAM_BOXED_TEXT +TERM_PUBLIC void ENHGD_boxed_text __PROTO((unsigned int, unsigned int, int)); +#endif + +#include +/* Include files for bitmap fonts */ +#include +#include +#include +#include +#include + +/* some version test macros */ +#define GD_NUM_VERSION(major, minor, release) \ + (((major) * 10000) + ((minor) * 100) + (release)) +#define GD_THIS_VERSION \ + GD_NUM_VERSION(GD_MAJOR_VERSION, GD_MINOR_VERSION, GD_RELEASE_VERSION) +#define GD_MIN_VERSION(major, minor, release) \ + (GD_THIS_VERSION >= GD_NUM_VERSION(major, minor,release)) + +/* Before version 2.0.36, the libgd function gdFTUseFontConfig() didn't */ +/* do what we need. Test for earlier versions and ignore it. */ +#if GD_MIN_VERSION(2,0,36) +# define gdUseFontConfig(x) gdFTUseFontConfig(x) +#endif +#ifndef gdUseFontConfig +# define gdUseFontConfig(x) 0 +#endif + +/* These intermediate functions are necessary on Windows since + the shared version of libgd uses a different calling convention + and there is no proper macro defined. +*/ +#if defined(WIN32) && !defined(NONDLL) +static void gp_gdImagePolygon(gdImagePtr, gdPointPtr, int, int); +static void gp_gdImageFilledPolygon(gdImagePtr, gdPointPtr, int, int); +#else +# define gp_gdImagePolygon gdImagePolygon +# define gp_gdImageFilledPolygon gdImageFilledPolygon +#endif + +static void PNG_PointX __PROTO((unsigned int, unsigned int)); +static void PNG_PointPlus __PROTO((unsigned int, unsigned int)); +static void PNG_Triangle(unsigned int x, unsigned int y, int direction, + void (*draw_func)(gdImagePtr, gdPointPtr, int, int)); +static void PNG_Diamond(unsigned int x, unsigned int y, + void (*draw_func)(gdImagePtr, gdPointPtr, int, int)); +static void PNG_init_brush __PROTO((int)); + +#define GREG_XMAX 640 +#define GREG_YMAX 480 + +/* This will be the default font */ +#define gdfont gdFontMediumBold +#define PNG_VCHAR 13 +#define PNG_HCHAR 7 + +#define PNG_TICSIZE (GREG_YMAX/100) + +#define PNG_MAX_COLORS 256 +#define GOT_NEXT_PROTO +#endif + +#ifndef TERM_PROTO_ONLY +#ifdef TERM_BODY + +static TBOOLEAN PNG_initialized = FALSE; /* Set when terminal first initialized */ + +static struct { + gdImagePtr image; + gdFontPtr font; + unsigned int x, y; + int height; + int charh, charw; + int color; /* Magic index returned by libgd */ + int rgb; /* Our guess at the corresponding rgb */ + int n_colors; + int color_table[PNG_MAX_COLORS]; + int rgb_table[PNG_MAX_COLORS]; + int angle; + enum JUSTIFY justify; + int flags; + int linetype; + int linewidth; + TBOOLEAN capbutt; /* use capbutt on lines with GD2, 20051205 MWS*/ + TBOOLEAN use_builtin; + double ttfsize; + char *ttffont; + gdFontPtr default_font; + char * default_ttffont; + double default_ttfsize; + double fontscale; + TBOOLEAN TrueColor; + double dashfraction; /* Where in a dot-dash pattern we left off */ + /* Variables for animated gif support: */ + TBOOLEAN animate; /* Only gif supports animation */ + int loop_count; /* Number of times to repeat sequence */ + int frame_count; /* Number of frames in animation */ + int frame_delay; /* Time between frames in .01 seconds */ + TBOOLEAN frame_optimization; + gdImagePtr previous_image; /* Needed to encode animation as a series of deltas */ +} png_state; + +#define PNG_USE_TRANSPARENT 1 +#define PNG_USE_INTERLACE 2 +#define PNG_USE_CROP 4 + +enum PNG_id { + PNG_TRANSPARENT, PNG_NOTRANSPARENT, + PNG_INTERLACE, PNG_NOINTERLACE, + PNG_CROP, PNG_NOCROP, + /* Font size */ + PNG_TINY, PNG_SMALL, PNG_MEDIUM, PNG_LARGE, PNG_GIANT, + PNG_FONT, PNG_FONTSCALE, + PNG_SIZE, PNG_BACKGROUND, + PNG_ENHANCED, PNG_NOENHANCED, + PNG_TRUECOLOR, PNG_NOTRUECOLOR, + PNG_LINEWIDTH, PNG_BUTT, PNG_ROUNDED, PNG_DASHLENGTH, + GIF_ANIMATE, GIF_DELAY, GIF_LOOP, GIF_NOOPT, GIF_OPT, + PNG_OTHER +}; + +#ifdef Y +# undef Y +#endif +#define Y(y) (png_state.height - (y)) + +static int PNG_XMAX = GREG_XMAX; +static int PNG_YMAX = GREG_YMAX; +static const int PNG_POINT_SCALE = 3; +static int PNG_ps = 3; + +#ifdef EAM_BOXED_TEXT + unsigned int bounding_box[4]; +#define GD_TEXTBOX_MARGIN 1.0 + double bounding_xmargin = GD_TEXTBOX_MARGIN; + double bounding_ymargin = GD_TEXTBOX_MARGIN; +#endif + +static TBOOLEAN ENHgd_show = TRUE; +static TBOOLEAN ENHgd_sizeonly = FALSE; + +static struct gen_table PNG_opts[] = +{ + { "trans$parent", PNG_TRANSPARENT }, + { "notran$sparent", PNG_NOTRANSPARENT }, + { "inter$lace", PNG_INTERLACE }, + { "nointer$lace", PNG_NOINTERLACE }, + { "crop", PNG_CROP }, + { "nocrop", PNG_NOCROP }, + { "ti$ny", PNG_TINY }, + { "s$mall", PNG_SMALL }, + { "m$edium", PNG_MEDIUM }, + { "l$arge", PNG_LARGE }, + { "g$iant", PNG_GIANT }, + { "fontscale", PNG_FONTSCALE }, + { "fo$nt", PNG_FONT }, + { "si$ze", PNG_SIZE }, + { "enh$anced", PNG_ENHANCED }, + { "noenh$anced", PNG_NOENHANCED }, + { "true$color", PNG_TRUECOLOR }, + { "notrue$color", PNG_NOTRUECOLOR }, + { "linew$idth", PNG_LINEWIDTH }, + { "anim$ate", GIF_ANIMATE }, /* gif animation options */ + { "delay", GIF_DELAY }, + { "loop", GIF_LOOP }, + { "noopt$imize", GIF_NOOPT }, + { "opt$imize", GIF_OPT }, /* end of gif animation options */ + { "lw", PNG_LINEWIDTH }, + { "butt", PNG_BUTT}, + { "round$ed", PNG_ROUNDED}, + { "dashl$ength", PNG_DASHLENGTH}, + { "dl", PNG_DASHLENGTH}, + { "backg$round", PNG_BACKGROUND}, + { NULL, PNG_OTHER } +}; + +#undef MAXLINEWIDTH +#define MAXLINEWIDTH 100 +static double PNG_linewidth_factor = 1.0; +static double PNG_dashlength_factor = 1.0; + +/* shige takeno: + * libgd can be built to prefer UTF-8 or SJIS encoding for Japanese. + * If it wants SJIS and we are currently in UTF8, convert. + * If it wants UTF8 and we are currently in SJIS, convert. + * conditional compilation flags: + * HAVE_ICONV (iconv library) + * JIS_GDLIB (using gdlib configured with -DJISX0208) + */ +#ifdef HAVE_ICONV +#include +#endif +static void gd_iconv __PROTO((char **string)); + +/* EAM - gdImage structure to hold brushes for linewidth */ +/* We will allocate and initialize these on demand */ +typedef struct { + gdImagePtr im; + unsigned int last_rgb; + int bgnd; + int fgnd; +} PNG_BRUSH; + +static PNG_BRUSH *PNG_brush[MAXLINEWIDTH+1]; + +typedef struct { + gdImagePtr im; + unsigned int last_rgb; + int fillpar; +} PNG_FILL_TILE; + +static PNG_FILL_TILE PNG_fill_tile = { (gdImagePtr)0, 0, 0 }; + +/* To be used with libgd 2.0.34 to request Symbol encoding */ +#ifdef gdFTEX_Adobe_Custom +static gdFTStringExtra PNG_FONT_INFO = {0,0,0,0,0,NULL,NULL}; +#endif + +#if defined(WIN32) && !defined(NONDLL) +static void +gp_gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c) +{ + gdImagePolygon(im, p, n, c); +} + +static void +gp_gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c) +{ + gdImageFilledPolygon(im, p, n, c); +} +#endif + + +/* Common code to crop the image around its bounding box, just before writing + down the file. +*/ +static void +image_do_crop () +{ + if (png_state.flags & PNG_USE_CROP) { + int x, y, x1, y1, x2, y2, flag; + int bg = png_state.color_table[0]; /* index of the background color */ + gdImagePtr im_crop; + for (flag=0, x1=0; x1 < gdImageSX(png_state.image)-1; x1++) { + for (y=0; y < gdImageSY(png_state.image); y++) + if (gdImageGetPixel(png_state.image, x1, y) != bg) { flag = 1; break; } + if (flag) break; + } + for (flag=0, x2=gdImageSX(png_state.image)-1; x2 >= x1; x2--) { + for (y=0; y < gdImageSY(png_state.image); y++) + if (gdImageGetPixel(png_state.image, x2, y) != bg) { flag = 1; break; } + if (flag) break; + } + for (flag=0, y1=0; y1 < gdImageSY(png_state.image)-1; y1++) { + for (x=x1; x <= x2; x++) + if (gdImageGetPixel(png_state.image, x, y1) != bg) { flag = 1; break; }; + if (flag) break; + } + for (flag=0, y2=gdImageSY(png_state.image)-1; y2 >= y1; y2--) { + for (x=x1; x <= x2; x++) + if (gdImageGetPixel(png_state.image, x, y2) != bg) { flag = 1; break; }; + if (flag) break; + } + x = x2 - x1 + 1; /* width */ + y = y2 - y1 + 1; /* height */ + + if (png_state.TrueColor) + im_crop = gdImageCreateTrueColor(x,y); + else + im_crop = gdImageCreate(x,y); + if (!im_crop) { + int_warn(NO_CARET,"libgd: failed to create cropped image structure"); + return; + } + bg = gdImageColorAllocateAlpha(im_crop,255,255,255,127); + + /* FIXME: getting black background for truecolor & transparent */ + gdImagePaletteCopy(im_crop, png_state.image); + if (png_state.flags & PNG_USE_TRANSPARENT) { + gdImageColorTransparent(im_crop, bg); + /* WARNING: This is a work-around for strangeness in libgd, */ + /* which doesn't copy transparent pixels in TrueColor images. */ + if (png_state.TrueColor) + gdImageColorTransparent(png_state.image, -1); + } else + gdImageColorTransparent(im_crop, -1); + + gdImageCopy(im_crop, png_state.image, 0, 0, x1, y1, x, y); + gdImageDestroy(png_state.image); + png_state.image = im_crop; + /* Re-set transparency for sixelgd */ + if (strcmp("sixelgd", term->name) == 0 && + png_state.TrueColor && (png_state.flags & PNG_USE_TRANSPARENT)) { + gdImageColorTransparent(png_state.image, png_state.color_table[0]); + } + } +} + + +static int PNG_FillSolid __PROTO((int fillpar)); +static int PNG_FillPattern __PROTO((int fillpar)); +static int PNG_FillTransparent __PROTO((int fillpar)); + +static int +PNG_FillSolid(int fillpar) +{ + int red = (png_state.rgb >> 16) & 0xff; + int green = (png_state.rgb >> 8) & 0xff; + int blue = png_state.rgb & 0xff; + + double fact = (double)(100 - fillpar) * 0.01; + + int color; + + if (fact <= 0 || fact >= 1.0) + return png_state.color; + + red += (0xff - red) * fact; + green += (0xff - green) * fact; + blue += (0xff - blue) * fact; + + color = gdImageColorExact(png_state.image, red, green, blue); + if (color < 0) { + color = gdImageColorAllocate(png_state.image, red, green, blue); + } + if (color < 0) { + color = gdImageColorClosest(png_state.image, red, green, blue); + } + + return color; +} + +static int +PNG_FillTransparent(int fillpar) +{ + int red = (png_state.rgb >> 16) & 0xff; + int green = (png_state.rgb >> 8) & 0xff; + int blue = png_state.rgb & 0xff; + int alpha = 127 * (float)(100-fillpar) / 100.; + + return gdImageColorExactAlpha(png_state.image, red, green, blue, alpha); +} + +static int +PNG_FillPattern(int style) +{ + int rgb = png_state.rgb; + int brgb = png_state.rgb_table[0]; + int fillpar = (style >> 4) % 8; + style = style & 0xf; + + if (!PNG_fill_tile.im || rgb != PNG_fill_tile.last_rgb || PNG_fill_tile.fillpar != fillpar) { + + int foreground, background; + + if (PNG_fill_tile.im) { + gdImageDestroy(PNG_fill_tile.im); + PNG_fill_tile.im = (gdImagePtr)0; + } + + /* save new values */ + PNG_fill_tile.fillpar = fillpar; + PNG_fill_tile.last_rgb = rgb; + + /* create new tile */ + if (!((PNG_fill_tile.im = gdImageCreate(8, 8)))) + int_error(NO_CARET,"libgd: failed to create pattern-fill tile"); + + background = gdImageColorAllocate(PNG_fill_tile.im, + (brgb >> 16) & 0xff, (brgb >> 8) & 0xff, brgb & 0xff); + if (style == FS_TRANSPARENT_PATTERN) + gdImageColorTransparent(PNG_fill_tile.im, background); + gdImageFilledRectangle(PNG_fill_tile.im, 0, 0, 7, 7, background); + + /* foreground */ + foreground = gdImageColorAllocate(PNG_fill_tile.im, + (rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff); + + switch (fillpar) { + case 0: /* no fill */ + default: + break; + case 1: /* cross-hatch */ + gdImageLine(PNG_fill_tile.im, 0, 0, 7, 7, foreground); + gdImageLine(PNG_fill_tile.im, 0, 6, 6, 0, foreground); + break; + case 2: /* double cross-hatch */ + gdImageLine(PNG_fill_tile.im, 0, 0, 7, 7, foreground); + gdImageLine(PNG_fill_tile.im, 0, 6, 6, 0, foreground); + gdImageLine(PNG_fill_tile.im, 0, 2, 2, 0, foreground); + gdImageLine(PNG_fill_tile.im, 7, 3, 3, 7, foreground); + gdImageLine(PNG_fill_tile.im, 4, 0, 7, 3, foreground); + gdImageLine(PNG_fill_tile.im, 0, 4, 3, 7, foreground); + break; + case 3: /* solid */ + gdImageFilledRectangle(PNG_fill_tile.im, 0, 0, 7, 7, foreground); + break; + case 4: + gdImageLine(PNG_fill_tile.im, 0, 0, 7, 7, foreground); + break; + case 5: + gdImageLine(PNG_fill_tile.im, 0, 7, 7, 0, foreground); + break; + case 6: + gdImageLine(PNG_fill_tile.im, 0, 0, 3, 7, foreground); + gdImageLine(PNG_fill_tile.im, 4, 0, 7, 7, foreground); + break; + case 7: + gdImageLine(PNG_fill_tile.im, 0, 7, 3, 0, foreground); + gdImageLine(PNG_fill_tile.im, 4, 7, 7, 0, foreground); + break; + case 8: + gdImageLine(PNG_fill_tile.im, 0, 0, 7, 3, foreground); + gdImageLine(PNG_fill_tile.im, 0, 4, 7, 7, foreground); + break; + case 9: + gdImageLine(PNG_fill_tile.im, 0, 3, 7, 0, foreground); + gdImageLine(PNG_fill_tile.im, 0, 7, 7, 4, foreground); + break; + } + } + + gdImageSetTile(png_state.image, PNG_fill_tile.im); + return (int)gdTiled; +} + +static void +PNG_PointX(unsigned int x, unsigned int y) +{ + gdImageLine(png_state.image, x - PNG_ps, y - PNG_ps, + x + PNG_ps, y + PNG_ps, png_state.color); + gdImageLine(png_state.image, x + PNG_ps, y - PNG_ps, + x - PNG_ps, y + PNG_ps, png_state.color); +} + +static void +PNG_PointPlus(unsigned int x, unsigned int y) +{ + gdImageLine(png_state.image, x - PNG_ps, y, + x + PNG_ps, y, png_state.color); + gdImageLine(png_state.image, x, y - PNG_ps, + x, y + PNG_ps, png_state.color); +} + +static void +PNG_Triangle( + unsigned int x, unsigned int y, + int direction, + void (*draw_func)(gdImagePtr, gdPointPtr, int, int)) +{ + int delta = (int)((1.33 * (double)PNG_ps) + 0.5); + int delta_ = (int)((0.67 * (double)PNG_ps) + 0.5); + + gdPoint points[4]; + points[0].x = x; + points[0].y = y - direction * delta; + points[1].x = x - delta; + points[1].y = y + direction * delta_; + points[2].x = x + delta; + points[2].y = y + direction * delta_; + points[3].x = points[0].x; + points[3].y = points[0].y; + draw_func(png_state.image, points, 4, png_state.color); +} + +static void +PNG_Diamond( + unsigned int x, unsigned int y, + void (*draw_func)(gdImagePtr, gdPointPtr, int, int)) +{ + gdPoint points[5]; + points[0].x = x; + points[0].y = y - PNG_ps; + points[1].x = x + PNG_ps; + points[1].y = y; + points[2].x = x; + points[2].y = y + PNG_ps; + points[3].x = x - PNG_ps; + points[3].y = y; + points[4].x = points[0].x; + points[4].y = points[0].y; + draw_func(png_state.image, points, 5, png_state.color); +} + +/* + * _options() Called when terminal type is selected. + * This procedure should parse options on the command line. A list of the + * currently selected options should be stored in term_options[] in a form + * suitable for use with the set term command. term_options[] is used by + * the save command. Use options_null() if no options are available. + */ +TERM_PUBLIC void +PNG_options() +{ + double tmp; + char *string; + unsigned long color; + TBOOLEAN gif_anim_option = FALSE; /* set to TRUE if an animated gif option given */ + + if (!PNG_initialized) { + PNG_initialized = TRUE; + term_options[0] = '\0'; + term->h_char = PNG_HCHAR; /* Default to medium font */ + png_state.default_font = gdfont; + png_state.n_colors = 0; + png_state.flags = 0; + png_state.use_builtin = FALSE; + png_state.ttffont = NULL; + png_state.default_ttffont = NULL; + png_state.default_ttfsize = 0; + png_state.fontscale = 1; + png_state.justify = CENTRE; + png_state.TrueColor = FALSE; + PNG_linewidth_factor = 1.0; + PNG_dashlength_factor = 1.0; + png_state.capbutt = FALSE; /* to preserve previous default behavior */ +#ifdef _WIN32 + /* Set the default search path for fonts to something useful. */ + if (getenv("GDFONTPATH") == NULL) { + const char fonts[] = "\\fonts"; + char *windir = getenv("windir"); + if (windir) { + char *gdfontpath = (char *) + gp_alloc(strlen(windir) + strlen(fonts) + 1, "GDFONTPATH"); + if (gdfontpath) { + strcpy(gdfontpath, windir); + strcat(gdfontpath, fonts); + SetEnvironmentVariableA("GDFONTPATH", gdfontpath); + free(gdfontpath); + } + } + } +#endif + } else { + /* FIXME EAM - these should never happen! */ + if (!png_state.default_font) { + fprintf(stderr,"gd.trm: caught initialization error\n"); + png_state.default_font = gdfont; + } + } + + /* Annoying hack to handle the case of 'set termoption' after */ + /* we are already in animation mode. */ + if (almost_equals(c_token-1, "termopt$ion")) + FPRINTF((stderr,"gif: Maintaining animation state\n")); + else { + /* Otherwise reset animation parameters */ + if (png_state.previous_image) + gdImageDestroy(png_state.previous_image); + png_state.animate = FALSE; + png_state.previous_image = NULL; + png_state.frame_optimization = FALSE; + png_state.loop_count = 0; + /* And default font size */ + term->h_char = PNG_HCHAR; + png_state.default_ttfsize = 0; + PNG_linewidth_factor = 1.0; + PNG_dashlength_factor = 1.0; + /* Default to enhanced text */ + term->flags |= TERM_ENHANCED_TEXT; + term->put_text = ENHGD_put_text; + } + + while (!END_OF_COMMAND) { + switch(lookup_table(&PNG_opts[0],c_token)) { + case PNG_TRANSPARENT: + png_state.flags |= PNG_USE_TRANSPARENT; + ++c_token; + break; + case PNG_NOTRANSPARENT: + png_state.flags &= ~PNG_USE_TRANSPARENT; + ++c_token; + break; + case PNG_INTERLACE: + png_state.flags |= PNG_USE_INTERLACE; + ++c_token; + break; + case PNG_NOINTERLACE: + png_state.flags &= ~PNG_USE_INTERLACE; + ++c_token; + break; + case PNG_CROP: + png_state.flags |= PNG_USE_CROP; + ++c_token; + break; + case PNG_NOCROP: + png_state.flags &= ~PNG_USE_CROP; + ++c_token; + break; + +#ifdef HAVE_GD_TTF +# define UNSET_TTF_FONT \ + free(png_state.ttffont); \ + png_state.ttffont = NULL; \ + png_state.default_ttfsize = 2 * term->h_char - 2; \ + png_state.use_builtin = TRUE; +#else +# define UNSET_TTF_FONT \ + ; /* nothing to do */ +#endif + + case PNG_TINY: + png_state.default_font = gdFontGetTiny(); + term->v_char = png_state.default_font->h; + term->h_char = png_state.default_font->w; + ++c_token; + UNSET_TTF_FONT; + break; + case PNG_SMALL: + png_state.default_font = gdFontGetSmall(); + term->v_char = png_state.default_font->h; + term->h_char = png_state.default_font->w; + ++c_token; + UNSET_TTF_FONT; + break; + case PNG_MEDIUM: + png_state.default_font = gdFontGetMediumBold(); + term->v_char = png_state.default_font->h; + term->h_char = png_state.default_font->w; + ++c_token; + UNSET_TTF_FONT; + break; + case PNG_LARGE: + png_state.default_font = gdFontGetLarge(); + term->v_char = png_state.default_font->h; + term->h_char = png_state.default_font->w; + ++c_token; + UNSET_TTF_FONT; + break; + case PNG_GIANT: + png_state.default_font = gdFontGetGiant(); + term->v_char = png_state.default_font->h; + term->h_char = png_state.default_font->w; + ++c_token; + UNSET_TTF_FONT; + break; + + case PNG_FONT: + c_token++; +#ifdef HAVE_GD_TTF + if (END_OF_COMMAND) { + free(png_state.ttffont); + png_state.ttffont = NULL; + png_state.default_ttfsize = 0; + } else { + int brect[8]; + char *err; + char *s; + + if (isstringvalue(c_token) && (s = try_to_get_string())) { + char *comma = strrchr(s,','); + double fontsize; + if (comma && (1 == sscanf(comma+1,"%lf",&fontsize))) { + png_state.default_ttfsize = fontsize; + png_state.ttfsize = png_state.default_ttfsize; + *comma = '\0'; + } + if (*s) { + free(png_state.ttffont); + png_state.ttffont = s; + } else { + continue; + } + } else { + free(png_state.ttffont); + png_state.ttffont = gp_alloc(token_len(c_token)+1,"new font"); + copy_str(png_state.ttffont, c_token, token_len(c_token)+1); + c_token++; + } + free(png_state.default_ttffont); + png_state.default_ttffont = gp_strdup(png_state.ttffont); + + /* First try the old GDFONTPATH mechanism for locating fonts */ + (void)gdUseFontConfig(0); + err = gdImageStringFT(NULL, &brect[0], 0, + png_state.ttffont, png_state.default_ttfsize*png_state.fontscale, + 0.0, 0, 0, "test"); + + /* If that didn't work, try again using the fontconfig mechanism */ + if (err && gdUseFontConfig(1)) { + err = gdImageStringFT(NULL, &brect[0], 0, + png_state.ttffont, png_state.default_ttfsize*png_state.fontscale, + 0.0, 0, 0, "test"); + } + + /* If we still haven't found the font, punt to the internal non-TTF default set */ + if (err) { + fprintf(stderr, "%s when opening font %s, trying default\n", + err, png_state.ttffont); + free(png_state.ttffont); + free(png_state.default_ttffont); + png_state.ttffont = NULL; + png_state.default_ttffont = NULL; + } + + } +#else + c_token++; + fprintf(stderr,"No TTF font support, using internal non-scalable font\n"); +#endif + break; +# undef UNSET_TTF_FONT + + case PNG_FONTSCALE: + c_token++; + png_state.fontscale = END_OF_COMMAND ? 1 : real_expression(); + if (png_state.fontscale <= 0) + png_state.fontscale = 1.; + break; + + case PNG_SIZE: + c_token++; + if (END_OF_COMMAND) { + PNG_XMAX = GREG_XMAX; + PNG_YMAX = GREG_YMAX; + } else { + PNG_XMAX = real_expression(); + if (equals(c_token, ",")) { + c_token++; + PNG_YMAX = real_expression(); + } + if (PNG_XMAX <= 0) + PNG_XMAX = GREG_XMAX; + if (PNG_YMAX <= 0) + PNG_YMAX = GREG_YMAX; + } + term->ymax = PNG_YMAX; + term->xmax = PNG_XMAX; + /* EAM Apr 2003 - same tic size on both x and y axes */ + term->v_tic = (PNG_XMAX < PNG_YMAX) ? PNG_XMAX/100 : PNG_YMAX/100; + if (term->v_tic < 1) + term->v_tic = 1; + term->h_tic = term->v_tic; + break; + case PNG_ENHANCED: + term->flags |= TERM_ENHANCED_TEXT; + term->put_text = ENHGD_put_text; + ++c_token; + break; + case PNG_NOENHANCED: + term->flags &= ~TERM_ENHANCED_TEXT; + term->put_text = PNG_put_text; + ++c_token; + break; + case PNG_TRUECOLOR: + png_state.TrueColor = TRUE; + term->flags |= TERM_ALPHA_CHANNEL; + c_token++; + break; + case PNG_NOTRUECOLOR: + png_state.TrueColor = FALSE; + term->flags &= ~TERM_ALPHA_CHANNEL; + c_token++; + break; + case PNG_LINEWIDTH: + c_token++; + PNG_linewidth_factor = real_expression(); + if (PNG_linewidth_factor < 0) + PNG_linewidth_factor = 1.0; + break; + case PNG_DASHLENGTH: + c_token++; + PNG_dashlength_factor = real_expression(); + if (PNG_dashlength_factor <= 0.2) + PNG_dashlength_factor = 1.0; + break; + + /* parse gif animation options */ + case GIF_ANIMATE: + if (strncmp("gif",term->name,3) == 0) + gif_anim_option = 1; + else if (strncmp("sixel",term->name,5) != 0) + int_error(c_token,"Only the gif terminal supports animation"); + c_token++; + png_state.animate = TRUE; + png_state.frame_count = 0; + png_state.frame_delay = 10; + png_state.frame_optimization = FALSE; + break; + case GIF_DELAY: + if (strncmp("gif",term->name,3)) + int_error(c_token,"Only the gif terminal supports animation"); + c_token++; + png_state.frame_delay = int_expression(); + if (png_state.frame_delay <= 0) + png_state.frame_delay = 10; + gif_anim_option = 1; + break; + case GIF_LOOP: + if (strncmp("gif",term->name,3)) + int_error(c_token,"Only the gif terminal supports animation"); + c_token++; + png_state.loop_count = int_expression(); + gif_anim_option = 1; + break; + case GIF_NOOPT: + if (strncmp("gif",term->name,3)) + int_error(c_token,"Only the gif terminal supports animation"); + c_token++; + png_state.frame_optimization = FALSE; + gif_anim_option = 1; + break; + case GIF_OPT: + if (strncmp("gif",term->name,3)) + int_error(c_token,"Only the gif terminal supports animation"); + c_token++; + png_state.frame_optimization = TRUE; + gif_anim_option = 1; + break; + + case PNG_BUTT: + png_state.capbutt = TRUE; + c_token++; + break; + + case PNG_ROUNDED: + png_state.capbutt = FALSE; + c_token++; + break; + + case PNG_BACKGROUND: + c_token++; + png_state.rgb_table[0] = parse_color_name(); + png_state.n_colors = 1; + break; + + case PNG_OTHER: + default: + /* not "size" */ + string = gp_input_line + token[c_token].start_index; + +#ifdef HAVE_GD_TTF + /* Check for explicit TTF font size */ + if (sscanf(string, "%lf", &tmp) == 1) { + if (tmp > 0 && tmp < 999) + png_state.default_ttfsize = tmp; + else + int_warn(c_token,"illegal font size"); + c_token++; + break; + } +#endif + + if (sscanf(string, "x%lx", &color) == 1) + int_error(c_token, "obsolete color option"); + else + int_error(c_token, "unrecognized terminal option"); + break; + } + } + + if (gif_anim_option) { +#ifndef GIF_ANIMATION /* animated gifs not supported by the current GD library */ + png_state.animate = FALSE; + int_warn(NO_CARET, "gif animation options ignored (not compiled into this binary)"); +#endif + } + +#ifdef HAVE_GD_TTF + /* If no font has been chosen but there is a default, use it */ + if (!png_state.ttffont && !png_state.use_builtin) { + char *external_default = getenv("GNUPLOT_DEFAULT_GDFONT"); + int brect[8]; + char *err; + + if (external_default) + png_state.ttffont = gp_strdup(external_default); + else /* Might as well try some plausible font; it's no worse than failing immediately */ + png_state.ttffont = gp_strdup("arial"); + + free(png_state.default_ttffont); + png_state.default_ttffont = gp_strdup(png_state.ttffont); + if (png_state.default_ttfsize == 0) + png_state.default_ttfsize = 2 * term->h_char - 2; + + /* First try the old GDFONTPATH mechanism for locating fonts */ + (void)gdUseFontConfig(0); + err = gdImageStringFT(NULL, &brect[0], 0, + png_state.ttffont, png_state.default_ttfsize*png_state.fontscale, + 0.0, 0, 0, "test"); + + /* If that didn't work, try again using fontconfig mechanism */ + if (err && gdUseFontConfig(1)) { + err = gdImageStringFT(NULL, &brect[0], 0, + png_state.ttffont, png_state.default_ttfsize*png_state.fontscale, + 0.0, 0, 0, "test"); + } + + /* If we still haven't found the font, punt to the internal non-TTF default set */ + if (err) { + fprintf(stderr,"%s when opening font \"%s\", using internal non-scalable font\n", + err, png_state.ttffont); + free(png_state.ttffont); + free(png_state.default_ttffont); + png_state.ttffont = NULL; + png_state.default_ttffont = NULL; + } + + } + + /* If no explicit TTF font size found, generate default */ + if (!(png_state.default_ttfsize > 0)) + png_state.default_ttfsize = 2 * term->h_char - 2; + png_state.ttfsize = png_state.default_ttfsize; + + /* Find approximate character width of selected TTF font */ + /* This is needed in order to set appropriate border width */ + if (png_state.default_ttffont) { + int brect[8]; + char *err; + err = gdImageStringFT(NULL, &brect[0], 0, + png_state.default_ttffont, png_state.default_ttfsize*png_state.fontscale, + 0.0, 0, 0, "f00000000g"); + if (!err) { + term->h_char = .11 * (float)(brect[2] - brect[0]) + 0.5; + term->v_char = 1.1 * (float)(brect[1] - brect[7]) + 0.5; + } + } +#endif + + /* This code is shared by png, gif, and jpeg terminal types */ + if (!strcmp(term->name,"jpeg")) + png_state.flags &= ~PNG_USE_TRANSPARENT; + + /* now generate options string */ + + if (png_state.flags & PNG_USE_TRANSPARENT) { + strcat(term_options, "transparent "); + } + if (png_state.flags & PNG_USE_INTERLACE) { + strcat(term_options, "interlace "); + } + /* JPEG files are always 24-bit color */ + if (strcmp(term->name, "jpeg") == 0) { + png_state.TrueColor = TRUE; + term->flags |= TERM_ALPHA_CHANNEL; + } else if (png_state.TrueColor) { + strcat(term_options, "truecolor "); + } + if (!(png_state.flags & PNG_USE_CROP)) { + strcat(term_options, "no"); + } + strcat(term_options, "crop "); + + if (term->flags & TERM_ENHANCED_TEXT) { + strcat(term_options, "enhanced "); + } + + if (PNG_linewidth_factor != 1.0) + sprintf(term_options + strlen(term_options), + "linewidth %3.1f ", PNG_linewidth_factor); + + if (PNG_dashlength_factor != 1.0) + sprintf(term_options + strlen(term_options), + "dashlength %3.1f ", PNG_dashlength_factor); + + if (png_state.capbutt) { + sprintf(term_options + strlen(term_options), + "butt "); + } + + if (png_state.animate) { + if (strncmp("sixel",term->name,5) == 0) + sprintf(term_options + strlen(term_options), "animate "); + else + sprintf(term_options + strlen(term_options), + "animate delay %d loop %d %soptimize ", + png_state.frame_delay, png_state.loop_count, + png_state.frame_optimization ? "" : "no"); + } + + sprintf(term_options + strlen(term_options), + "size %d,%d ", PNG_XMAX, PNG_YMAX); + + if (png_state.n_colors == 1) + sprintf(term_options + strlen(term_options), + "background \"#%06x\" ", png_state.rgb_table[0]); + + if (png_state.ttffont) { + if (png_state.fontscale != 1.0) + sprintf(term_options + strlen(term_options), + "fontscale %.1f ", png_state.fontscale); + if (strlen(term_options) + strlen(png_state.ttffont) < sizeof(term_options) - 32) + sprintf(term_options + strlen(term_options), + "font \"%s,%.1f\" ", png_state.ttffont, png_state.ttfsize); + } else switch (term->h_char) { + case 5: + strcat(term_options,"tiny "); + break; + case 6: + strcat(term_options, "small "); + break; + case 7: + default: + strcat(term_options, "medium "); + break; + case 8: + strcat(term_options, "large "); + break; + case 9: + strcat(term_options,"giant "); + break; + } + +} + + +/* + * _init() Called once, when the device is first selected. This procedure + * should set up things that only need to be set once, like handshaking and + * character sets etc... + */ +TERM_PUBLIC void +PNG_init() +{ +int i; + + png_state.linetype = 0; + png_state.linewidth = 1; + + /* Clear brush array, then initialize a few small ones */ + for (i=2; i<=MAXLINEWIDTH; i++) + PNG_brush[i] = NULL; +} + +/* + * Internal helper routine to initialize brushes used for stroking linewidth > 1 + */ +static void +PNG_init_brush(int width) +{ + PNG_BRUSH *brush = PNG_brush[width]; + + if (!brush) { + brush = gp_alloc(sizeof(PNG_BRUSH),"gd brush"); + PNG_brush[width] = brush; + brush->last_rgb = -99; /* Something invalid */ + if (!((brush->im = gdImageCreate(width,width)))) + int_error(NO_CARET,"libgd: failed to create brush structure"); + brush->bgnd = gdImageColorAllocate( brush->im, 255, 255, 255 ); + gdImageFill(brush->im, 0, 0, brush->bgnd); + gdImageColorTransparent(brush->im, brush->bgnd); + } + + if (png_state.color != brush->last_rgb) { + brush->fgnd = gdImageColorResolve(brush->im, + gdImageRed(png_state.image,png_state.color), + gdImageGreen(png_state.image,png_state.color), + gdImageBlue(png_state.image,png_state.color) ); + brush->last_rgb = png_state.color; + + /* EAM - quick and dirty is to fill the entire brush (square nib) */ + /* It might be better to approximate a circular nib by selectively */ + /* coloring the individual pixels of the brush image. */ + gdImageFilledRectangle(brush->im, 0, 0, width-1, width-1, brush->fgnd); + } +} + +/* + * _reset() Called when gnuplot is exited, the output device changed or + * the terminal type changed. This procedure should reset the device, + * possibly flushing a buffer somewhere or generating a form feed. + */ +TERM_PUBLIC void +PNG_reset() +{ + int i; + /* EAM - Clean up the brushes used for linewidth */ + for (i=2; i<=MAXLINEWIDTH; i++) { + if (PNG_brush[i]) { + if (PNG_brush[i]->im) + gdImageDestroy(PNG_brush[i]->im); + PNG_brush[i] = NULL; + } + } + if (PNG_fill_tile.im) { + gdImageDestroy(PNG_fill_tile.im); + PNG_fill_tile.im = (gdImagePtr)0; + } +#ifdef GIF_ANIMATION + if (png_state.animate && !strncmp(term->name,"gif",3)) { + gdImageGifAnimEnd(gpoutfile); + fprintf(stderr,"%d frames in animation sequence\n", png_state.frame_count); + png_state.frame_count = 0; + png_state.animate = FALSE; + } +#endif +} + +#if 0 +/* use #if 1 that's just for debugging */ +void +PNG_show_current_palette() +{ + int i; + + fprintf(stderr, "*****\n SHOW THE PALETTE! total=%i\n", + gdImageColorsTotal(png_state.image)); + for (i=0; i < gdImageColorsTotal(png_state.image); i++) { + /* Use access macros to learn colors. */ + fprintf(stderr, "%i\tr=%d\t g=%d\tb=%d\n", + i, + gdImageRed(png_state.image,i), + gdImageGreen(png_state.image,i), + gdImageBlue(png_state.image,i)); + } +} +#endif + +/* +How this works: Gray interval [0;1] will be mapped to interval +[0;sm_palette.colors-1] those r,g,b components are mapped by the array +below palette.offset equals 0 since png_smooth_color[0..colors] are +from ColorAllocate +*/ +static int png_smooth_color[gdMaxColors]; + + /* TODO: how to recover from a multiplot with two colour pm3d maps? + They must use the same palette! Or palette size must be + restricted to certain number of colours---a new user's option + */ + +TERM_PUBLIC int PNG_make_palette (t_sm_palette *palette) +{ + int i; + if (palette == NULL) { + /* If the output format is TrueColor there in no color limit */ + if (png_state.TrueColor) + return(0); + + /* return maximal number of colours in a PNG palette */ + i = gdMaxColors /*256*/ - gdImageColorsTotal(png_state.image); + /* the latter is the number of currently allocated colours. We want + to allocate the rest */ + /*BACK PLEASE fprintf(stderr,"colors in PNG palette=%i\n",(int)gdMaxColors); */ + if (i == 0) { + i = (sm_palette.colors <= 0) ? -1 : sm_palette.colors; + /* (no more colorus) : (previous palette (obviously multiplot mode)) */ + } + return i; + } + if (0 == gdMaxColors /*256*/ - gdImageColorsTotal(png_state.image)) + return 0; /* reuse previous palette (without warning) */ + for (i = 0; i < sm_palette.colors; i++) { + png_smooth_color[i] = gdImageColorAllocate(png_state.image, + (int)( palette->color[i].r * 255 + 0.5 ), /* r,g,b values for png */ + (int)( palette->color[i].g * 255 + 0.5 ), /* terminal are [0;255] */ + (int)( palette->color[i].b * 255 + 0.5 ) ); + } + return 0; +} + + +TERM_PUBLIC +void PNG_set_color (t_colorspec *colorspec) +{ + double gray = colorspec->value; + int save; + + switch (colorspec->type) { + + case TC_LT: + save = png_state.linetype; + PNG_linetype(colorspec->lt); + png_state.linetype = save; + break; + + case TC_RGB: + png_state.rgb = colorspec->lt; + if (png_state.TrueColor) + png_state.color = gdImageColorExactAlpha(png_state.image, + (colorspec->lt >> 16) & 0xff, + (colorspec->lt >> 8) & 0xff, + colorspec->lt & 0xff, + (colorspec->lt >> 25) & 0x7f); + else + png_state.color = gdImageColorResolve(png_state.image, + (colorspec->lt >> 16) & 0xff, + (colorspec->lt >> 8) & 0xff, + colorspec->lt & 0xff); + break; + + case TC_FRAC: + if (png_state.TrueColor) { + rgb255_color color; + rgb255maxcolors_from_gray(gray, &color); + png_state.color = gdImageColorResolve(png_state.image, + (int)color.r, (int)color.g, (int)color.b); + png_state.rgb = (color.r << 16) + (color.g << 8) +color.b; + return; + } else { + int png_color = (gray <= 0) ? 0 : (int)(gray * sm_palette.colors); + if (png_color >= sm_palette.colors) + png_color = sm_palette.colors - 1; + /* map [0;1] to interval [0;png_smooth_colors-1] */ + png_state.color = png_smooth_color[ png_color ]; + } + break; + + default: + break; + } + + /* This is correct, but currently the resulting gdAntiAliased is not used */ + gdImageSetAntiAliased(png_state.image, png_state.color); +} + +TERM_PUBLIC +void PNG_filled_polygon(int points, gpiPoint *corners) +{ + int i; + int fillpar = corners->style >> 4; + int color = png_state.color; + + /* since gpiPoint carries more than just x and y if + * we have EXTENDED_COLOR_SPECS defined, we need to + * copy it to the gdPointPtr struct; make it static + * so that is faster (joze) */ + static gdPointPtr gd_corners = (gdPointPtr) 0; + static unsigned int size = 0; + if (points > size) { + size = points; + gd_corners = gp_realloc(gd_corners, sizeof(gdPoint) * size, + "PNG_filled_polygon->gd_corners"); + } + for (i = 0; i < points; i++) { + gd_corners[i].x = corners[i].x; + gd_corners[i].y = Y(corners[i].y); + } + + switch (corners->style & 0xf) { + case FS_EMPTY: /* fill with background color */ + color = png_state.color_table[0]; + break; + case FS_SOLID: /* solid fill */ + color = PNG_FillSolid(fillpar); + break; + case FS_TRANSPARENT_SOLID: + if (png_state.TrueColor) + color = PNG_FillTransparent(fillpar); + else + color = PNG_FillSolid(fillpar); + break; + case FS_PATTERN: /* pattern fill */ + case FS_TRANSPARENT_PATTERN: + color = PNG_FillPattern(corners->style); + break; + default: + color = png_state.color; + break; + } + + gdImageFilledPolygon(png_state.image, gd_corners, points, color); +} + +/* + * This function is used for filledboxes + * style parameter is some garbled hash combining fillstyle and filldensity + */ +TERM_PUBLIC void +PNG_boxfill( + int style, + unsigned int x, unsigned int y, + unsigned int width, unsigned int height) +{ + unsigned int x1, y1, x2, y2; + int color; + + /* fillpar: + * - solid : 0 - 100 + * - pattern : 0 - 100 + */ + int fillpar = style >> 4; + + switch (style & 0xf) { + case FS_EMPTY: /* fill with background color */ + color = png_state.color_table[0]; + break; + case FS_SOLID: /* solid fill */ + color = PNG_FillSolid(fillpar); + break; + case FS_TRANSPARENT_SOLID: + if (png_state.TrueColor) + color = PNG_FillTransparent(fillpar); + else + color = PNG_FillSolid(fillpar); + break; + case FS_PATTERN: /* pattern fill */ + case FS_TRANSPARENT_PATTERN: + color = PNG_FillPattern(style); + break; + default: + /* should never happen */ + color = png_state.color; + break; + } + + x1 = x; + x2 = x + width - 1; + y2 = Y(y); + y1 = y2 - height + 1; + gdImageFilledRectangle(png_state.image, x1, y1, x2, y2, color); +} + +/* + * _graphics() Called just before a plot is going to be displayed. This + * procedure should set the device into graphics mode. Devices which can't + * be used as terminals (like plotters) will probably be in graphics mode + * always and therefore won't need this. + */ +TERM_PUBLIC void +PNG_graphics() +{ + int i; + unsigned int rgb; + unsigned int n_colors = GD_DEFINED_COLORS; + + /* avoid to pre-allocate colors for the sixel terminal in indexed mode */ + if ((strcmp("sixelgd", term->name) == 0) && !png_state.TrueColor) + n_colors = 1; + + for (i = png_state.n_colors; i < n_colors; i++) + png_state.rgb_table[i] = pm3d_color_names_tbl[i].value; + if (png_state.n_colors < n_colors) + png_state.n_colors = n_colors; + + /* TrueColor images default to a black background; load white instead. */ + /* If PNG_USE_TRANSPARENT, store the background alpha in the output file */ + /* but apply alpha for the rest of the image internally. Otherwise you */ + /* see only background through the topmost transparent layer. */ + if (png_state.TrueColor) { + unsigned int brgb = png_state.rgb_table[0]; + png_state.image = gdImageCreateTrueColor(PNG_XMAX, PNG_YMAX); + if (!png_state.image) + int_error(NO_CARET,"libgd: failed to create output image structure"); + if (png_state.flags & PNG_USE_TRANSPARENT) { + rgb = gdImageColorAllocateAlpha(png_state.image, + (brgb >> 16) & 0xff, (brgb >> 8) & 0xff, brgb & 0xff, 127); + gdImageSaveAlpha(png_state.image, 1); + gdImageAlphaBlending(png_state.image, 0); + } else { + rgb = gdImageColorAllocate(png_state.image, + (brgb >> 16) & 0xff, (brgb >> 8) & 0xff, brgb & 0xff); + } + gdImageFill(png_state.image, 1, 1, rgb); + gdImageAlphaBlending(png_state.image, 1); + + } else + png_state.image = gdImageCreate(PNG_XMAX, PNG_YMAX); + if (!png_state.image) + int_error(NO_CARET,"libgd: failed to create output image structure"); + + png_state.height = PNG_YMAX - 1; + png_state.charw = term->h_char; /* png_state.font->w; */ + png_state.charh = term->v_char; /* png_state.font->h; */ + png_state.font = png_state.default_font; + png_state.color = 0; + png_state.dashfraction = -1.0; + + for (i = 0; i < png_state.n_colors; i++) { + rgb = png_state.rgb_table[i]; + png_state.color_table[i] = + gdImageColorAllocate(png_state.image, (rgb >> 16) & 0xff, + (rgb >> 8) & 0xff, rgb & 0xff); + } + if (png_state.flags & PNG_USE_TRANSPARENT) + gdImageColorTransparent(png_state.image, png_state.color_table[0]); + else + gdImageColorTransparent(png_state.image, -1); + + /* Fix for truecolor and transparent options */ + if (strcmp("sixelgd", term->name) == 0 && + png_state.TrueColor && png_state.flags & PNG_USE_TRANSPARENT) { + gdImageAlphaBlending(png_state.image, 0); + gdImageFill(png_state.image, 1, 1, png_state.color_table[0]); + gdImageAlphaBlending(png_state.image, 1); + } +} + +/* + * _text() Called immediately after a plot is displayed. This procedure + * should set the device back into text mode if it is also a terminal, so + * that commands can be seen as they're typed. Again, this will probably + * do nothing if the device can't be used as a terminal. + */ +TERM_PUBLIC void +PNG_text() +{ + image_do_crop(); + if (png_state.flags & PNG_USE_INTERLACE) + gdImageInterlace(png_state.image, 1); + gdImagePng(png_state.image, gpoutfile); + gdImageDestroy(png_state.image); +} + +/* _move(x,y) Called at the start of a line. The cursor should move to the + * (x,y) position without drawing. + */ +TERM_PUBLIC void +PNG_move(unsigned int x, unsigned int y) +{ + png_state.x = x; + png_state.y = y; +} + +/* _vector(x,y) Called when a line is to be drawn. This should display a line + * from the last (x,y) position given by _move() or _vector() to this new (x,y) + * position. + */ +TERM_PUBLIC void +PNG_vector(unsigned int x, unsigned int y) +{ + int lw = png_state.linewidth; + + /* This terminal does not support dashed lines in general, but does */ + /* render LT_AXIS as a dotted line, used for zeroaxis and grid lines. */ + /* Nov 2014 - rewritten using the algorithm from the canvas terminal. */ + /* FIXME: should either fix this up the rest of the way to support */ + /* general dash patterns or simplify it back for dotted lines only. */ + if (png_state.linetype == LT_AXIS) { + static int last_lw = -1; + static int last_color = -1; + static double dashpattern[4] = {0.1, 0.5, 0.6, 1.0}; + + double delx = (int)x - (int)png_state.x; + double dely = (int)y - (int)png_state.y; + double stride = sqrt(delx*delx + dely*dely) / (8. * PNG_dashlength_factor * lw); + + double new_x, new_y; + double last_x = (int)png_state.x, last_y = (int)png_state.y; + int i; + double this_step; + + /* Adjust the style when linewidth or color has changed. */ + if (png_state.dashfraction < 0 || lw != last_lw || last_color != png_state.color) { + PNG_init_brush(lw); + gdImageSetBrush(png_state.image, PNG_brush[lw]->im); + last_lw = lw; + last_color = png_state.color; + png_state.dashfraction = 0.0; + } + + while (stride > 0) { + for (i=0; dashpattern[i] <= png_state.dashfraction; i++); + this_step = dashpattern[i] - png_state.dashfraction; + if (stride > this_step) { + new_x = last_x + delx * this_step / stride; + new_y = last_y + dely * this_step / stride; + stride -= this_step; + png_state.dashfraction = dashpattern[i]; + delx = x - new_x; + dely = y - new_y; + } else { + new_x = x; + new_y = y; + png_state.dashfraction += stride; + stride = 0; + } + if (i%2 == 0) { + /* dashes are fine for thin lines, but true dots look better */ + /* when the line is thick. */ + if (lw > 2) { + if (png_state.dashfraction >= dashpattern[0]) + gdImageFilledArc(png_state.image, + (int)(new_x + 0.5), Y((int)(new_y + 0.5)), + 2 * lw, 2 * lw, + 0, 360, png_state.color, gdArc); + } else { + gdImageLine(png_state.image, + (int)(last_x + 0.5), Y((int)(last_y + 0.5)), + (int)(new_x + 0.5), Y((int)(new_y + 0.5)), + gdBrushed ); + } + } + last_x = new_x; + last_y = new_y; + if (png_state.dashfraction >= 1.0) + png_state.dashfraction = 0.0; + } + + /* All other (not dashed) vectors */ + } else { + if (png_state.linewidth == 1) { +#if defined(gdAntiAliased) + gdImageSetThickness(png_state.image,1); + gdImageSetAntiAliased(png_state.image, png_state.color); + gdImageLine(png_state.image, png_state.x, Y(png_state.y), + x, Y(y), gdAntiAliased); +#else + gdImageLine(png_state.image, png_state.x, Y(png_state.y), + x, Y(y), png_state.color); +#endif + + } else if (png_state.capbutt){ + + gdImageSetThickness(png_state.image,png_state.linewidth); + gdImageLine(png_state.image, png_state.x, Y(png_state.y), + x, Y(y), png_state.color); + + } else { + /* EAM - Implement linewidth by using a brush */ + PNG_init_brush(lw); + gdImageSetBrush(png_state.image, PNG_brush[lw]->im); + gdImageLine(png_state.image, png_state.x, Y(png_state.y), + x, Y(y), gdBrushed ); + } + } + + png_state.x = x; + png_state.y = y; +} + +/* _linetype(lt) Called to set the line type before text is displayed or + * line(s) plotted. + * Negative linetypes are defined in gadgets.h + * lt 0 and upwards are used for plots 0 and upwards. + * If _linetype() is called with lt greater than the available line types, + * it should map it to one of the available line types. + */ +TERM_PUBLIC void +PNG_linetype(int type) +{ + if (type >= (GD_DEFINED_COLORS - 3)) + type %= (GD_DEFINED_COLORS - 3); + if (type <= LT_BACKGROUND) /* LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED */ + type = -3; /* Draw in background color */ + + if (type + 3 >= png_state.n_colors) { + int rgb = pm3d_color_names_tbl[type + 3].value; + png_state.color = gdImageColorResolve(png_state.image, + (rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff); + png_state.rgb = rgb; + } else { + png_state.color = png_state.color_table[type + 3]; + png_state.rgb = png_state.rgb_table[type + 3]; + } + png_state.linetype = type; + + if (type == LT_AXIS) + png_state.dashfraction = -1.0; +} + +/* Use the "brush" tools in the gd library to control line width. + * Pre-define brushes for linewidths 2, 3, 4, 5, 6 (1 doesn't need a brush!). + * Here we just remember the state. + */ +TERM_PUBLIC void +PNG_linewidth(double linewidth) +{ + png_state.linewidth = (int)(PNG_linewidth_factor * linewidth+0.49); + if (png_state.linewidth > MAXLINEWIDTH) png_state.linewidth = MAXLINEWIDTH; + if (png_state.linewidth < 1) png_state.linewidth = 1; +} + +/* _put_text(x,y,str) Called to display text at the (x,y) position, + * while in graphics mode. The text should be vertically (with respect + * to the text) justified about (x,y). The text is rotated according + * to _text_angle and then horizontally (with respect to the text) + * justified according to _justify_text. + */ +#ifdef HAVE_GD_TTF +TERM_PUBLIC void +PNG_put_text(unsigned int x, unsigned int y, const char *string) +{ + /* Mar 2011 - added to handle SJIS/UTF8 conversion */ + if (contains8bit(string)) { + gd_iconv((char **)(&string)); + } + + if (png_state.ttffont) { + int brect[8]; char *err; + /* Draw once with a NULL image to get the bounding rectangle */ + /* then draw it again, centered. */ + err = gdImageStringFT(NULL, brect, png_state.color, + png_state.ttffont, png_state.ttfsize*png_state.fontscale, + (double)png_state.angle * M_PI_2 / 90. , + x, Y(y), (char *)string); + if (err) { + fprintf(stderr,"gdImageStringFT: %s while printing string %s with font %s\n", + err,string,png_state.ttffont); + } else { + x += sin((double)png_state.angle * M_PI_2/90.) * (double)png_state.charh/4.; + y -= cos((double)png_state.angle * M_PI_2/90.) * (double)png_state.charh/4.; + switch (png_state.justify) { + case RIGHT: + x -= (brect[2]-brect[0]); + y += (brect[3]-brect[1]); + break; + case CENTRE: + x -= (brect[2]-brect[0]) / 2.; + y += (brect[3]-brect[1]) / 2.; + break; + case LEFT: + default: break; + } + err = gdImageStringFT(png_state.image, brect, png_state.color, + png_state.ttffont, png_state.ttfsize*png_state.fontscale, + (double)png_state.angle * M_PI_2 / 90., + x, Y(y), (char *)string); + if (err) + fprintf(stderr,"gdImageStringFT: %s while printing string %s with font %s\n", + err,string,png_state.ttffont); + +#ifdef EAM_BOXED_TEXT + if (!ENHgd_sizeonly) { + int xmax = GPMAX(brect[2],brect[6]); + int xmin = GPMIN(brect[0],brect[4]); + int ymax = GPMIN(brect[1],brect[3]); + int ymin = GPMAX(brect[5],brect[7]); + if (xmin < bounding_box[0]) bounding_box[0] = xmin; + if (xmax > bounding_box[2]) bounding_box[2] = xmax; + if (ymin < bounding_box[1]) bounding_box[1] = ymin; + if (ymax > bounding_box[3]) bounding_box[3] = ymax; + } +#endif + + } + } else if (png_state.angle != 0) { + x -= png_state.charh / 2; + switch (png_state.justify) { + case RIGHT: y -= png_state.charw * strlen(string); + break; + case CENTRE:y -= png_state.charw * strlen(string) / 2; + break; + case LEFT: + default: break; + } + gdImageStringUp(png_state.image, png_state.font, + x, Y(y), + (unsigned char *)string, png_state.color); + } else { + y += png_state.charh / 2; + switch (png_state.justify) { + case RIGHT: x -= png_state.charw * strlen(string); + break; + case CENTRE:x -= png_state.charw * strlen(string) / 2; + break; + case LEFT: + default: break; + } + gdImageString(png_state.image, png_state.font, + x, Y(y), + (unsigned char *)string, png_state.color); + } + +} + +#else /* not HAVE_GD_TTF */ + +TERM_PUBLIC void +PNG_put_text(unsigned int x, unsigned int y, const char *string) +{ + if (png_state.angle == 0) { + y += png_state.charh / 2; + gdImageString(png_state.image, png_state.font, + x, Y(y), + (unsigned char *)string, png_state.color); + } else { + x -= png_state.charh / 2; + gdImageStringUp(png_state.image, png_state.font, + x, Y(y), + (unsigned char *)string, png_state.color); + } +} + +#endif /* HAVE_GD_TTF */ + + +TERM_PUBLIC int +PNG_text_angle(int ang) +{ + while (ang < -180) ang += 360; /* Should not be needed, but reported to */ + while (ang > 180) ang -= 360; /* avoid a bug in some libgd versions */ + png_state.angle = ang; + return TRUE; +} + +TERM_PUBLIC int +PNG_justify_text(enum JUSTIFY mode) +{ +#ifdef HAVE_GD_TTF + png_state.justify = mode; + return TRUE; +#else + return null_justify_text(mode); +#endif +} + +TERM_PUBLIC void +PNG_point(unsigned int x, unsigned int y, int number) +{ + int save_color = png_state.color; + + if (number < 0) { /* Dot */ + gdImageSetPixel(png_state.image, x, Y(y), png_state.color); + return; + } + /* Use current linewidth to draw the point symbol */ + if (png_state.linewidth > 1) { + /* EAM - Implement linewidth by using a brush */ + int lw = png_state.linewidth; + PNG_init_brush(lw); + gdImageSetBrush(png_state.image, PNG_brush[lw]->im); + png_state.color = gdBrushed; + } + + y = Y(y); + + switch (number % 13) { + case 0: /* plus */ + default: + PNG_PointPlus(x, y); + break; + case 1: /* X */ + PNG_PointX(x, y); + break; + case 2: /* star */ + PNG_PointPlus(x, y); + PNG_PointX(x, y); + break; + case 3: /* box */ + gdImageRectangle(png_state.image, x - PNG_ps, y - PNG_ps, + x + PNG_ps, y + PNG_ps, png_state.color); + break; + case 4: /* box filled */ + gdImageFilledRectangle(png_state.image, x - PNG_ps, y - PNG_ps, + x + PNG_ps, y + PNG_ps, png_state.color); + break; + case 5: /* circle */ + gdImageArc(png_state.image, x, y, 2 * PNG_ps, 2 * PNG_ps, + 0, 360, png_state.color); + break; + case 6: /* circle (disk) filled */ + gdImageFilledArc(png_state.image, x, y, 2 * PNG_ps, 2 * PNG_ps, + 0, 360, png_state.color, gdArc); + break; + case 7: /* triangle */ + PNG_Triangle(x, y, 1, gp_gdImagePolygon); + break; + case 8: /* triangle filled */ + PNG_Triangle(x, y, 1, gp_gdImageFilledPolygon); + break; + case 9: /* upside down triangle */ + PNG_Triangle(x, y, -1, gp_gdImagePolygon); + break; + case 10: /* upside down triangle filled */ + PNG_Triangle(x, y, -1, gp_gdImageFilledPolygon); + break; + case 11: /* diamond */ + PNG_Diamond(x, y, gp_gdImagePolygon); + break; + case 12: /* diamond filled */ + PNG_Diamond(x, y, gp_gdImageFilledPolygon); + break; + } + + png_state.color = save_color; +} + +TERM_PUBLIC int +PNG_set_font(const char *fontname) +{ + int sep; + double size; + gdFontPtr font = png_state.default_font; + char *name = gp_strdup(fontname); + + sep = strcspn(fontname,","); + name[sep] = '\0'; + size = png_state.default_ttfsize; + if (fontname[sep] == ',') + sscanf(&(fontname[sep+1]),"%lf",&size); + + if (!strcmp(name,"small")) + font = gdFontGetSmall(); + else if (!strcmp(name,"medium")) + font = gdFontGetMediumBold(); + else if (!strcmp(name,"large")) + font = gdFontGetLarge(); + else if (!strcmp(name,"giant")) + font = gdFontGetGiant(); + else if (!strcmp(name,"tiny")) + font = gdFontGetTiny(); + else if (*name) { + /* New ttf font */ + free(png_state.ttffont); + png_state.ttffont = gp_strdup(name); + png_state.ttfsize = size; + } else { + /* Restore initial default font */ + free(png_state.ttffont); + png_state.ttffont = gp_strdup(png_state.default_ttffont); + png_state.ttfsize = size; + } + free(name); + + png_state.font = font; + png_state.charw = font->w; + png_state.charh = font->h; + +/* EAM 9-Feb-2003 Make new font size visible to higher level routines like write_multiline */ + term->h_char = font->w; + term->v_char = font->h; +#ifdef HAVE_GD_TTF + /* Find approximate character width and height of selected TTF font */ + if (png_state.ttffont) { + int brect[8]; + char *err; + /* First try the old GDFONTPATH mechanism for locating fonts */ + (void)gdUseFontConfig(0); + err = gdImageStringFT(NULL, &brect[0], 0, + png_state.ttffont, png_state.ttfsize*png_state.fontscale, + 0.0, 0, 0, "f00000000g"); + /* If that didn't work, try again using fontconfig mechanism */ + if (err && gdUseFontConfig(1)) { + FPRINTF((stderr,"DEBUG1: gd.trm:3: gdUseFontConfig(1) (%s)\n", + png_state.ttffont)); + err = gdImageStringFT(NULL, &brect[0], 0, + png_state.ttffont, + png_state.default_ttfsize*png_state.fontscale, + 0.0, 0, 0, "f00000000g"); + } + if (!err) { + term->h_char = .11 * (float)(brect[2] - brect[0]) + 0.5; + term->v_char = 1.1 * (float)(brect[1] - brect[7]) + 0.5; + } + } +#endif + + return TRUE; +} + +TERM_PUBLIC void +PNG_pointsize(double ptsize) +{ + if (ptsize < 0) + ptsize = 1; + PNG_ps = (int)(((double)PNG_POINT_SCALE * ptsize) + 0.5); +} + +/* + * Ethan A Merritt November 2003 + * - Support for enhanced text mode + * BUGS: + * - placement of overprinted characters is not correct; + * the overprinted text (pass 2) should be centered, not left-justified + * PROBLEMS: + * - the Symbol font encoding didn't work in libgd until 2.0.21 + * - Placement of superscripts and subscripts relies on information + * in the font description that is not always reliable + * - the TTF character encoding for non-keyboard characters does + * not always match the PostScript standard. + * - Spacing of rotated text is incorrect; I believe this is a due + * to a problem in the text rotation code (aspect ratio??). + */ + +static TBOOLEAN ENHgd_opened_string; + +/* used in determining height of processed text */ +static float ENHgd_base; + +/* use these so that we don't over-write the current font settings in png_state */ +static double ENHgd_fontsize; +static char *ENHgd_font; + +static int ENHgd_overprint = 0; +static TBOOLEAN ENHgd_widthflag = TRUE; +static unsigned int ENHgd_xsave, ENHgd_ysave; + +TERM_PUBLIC void +ENHGD_OPEN( + char *fontname, + double fontsize, double base, + TBOOLEAN widthflag, + TBOOLEAN showflag, + int overprint) +{ + /* If the overprint code requests a save or restore, that's all we do */ + if (overprint == 3) { + ENHgd_xsave = png_state.x; + ENHgd_ysave = png_state.y; + return; + } else if (overprint == 4) { + PNG_move(ENHgd_xsave, ENHgd_ysave); + return; + } + + if (!ENHgd_opened_string) { + ENHgd_opened_string = TRUE; + enhanced_cur_text = &enhanced_text[0]; + ENHgd_font = fontname; + ENHgd_fontsize = fontsize; + ENHgd_base = base; + ENHgd_show = showflag; + ENHgd_overprint = overprint; + ENHgd_widthflag = widthflag; + } +} + +/* Write a string fragment and update the current position */ +TERM_PUBLIC void +ENHGD_FLUSH() +{ + int brect[8]; char *err; + unsigned int x, y; + char *fragment = enhanced_text; + + if (!ENHgd_opened_string) + return; + + ENHgd_opened_string = FALSE; + *enhanced_cur_text = '\0'; + + /* Mar 2011 - added to handle SJIS/UTF8 conversion */ + if (contains8bit(fragment)) { + gd_iconv(&fragment); + } + + x = png_state.x; + y = png_state.y; + x -= sin((double)png_state.angle * M_PI_2/90.) * ENHgd_base; + y += cos((double)png_state.angle * M_PI_2/90.) * ENHgd_base; + x += sin((double)png_state.angle * M_PI_2/90.) * (double)png_state.charh/4.; + y -= cos((double)png_state.angle * M_PI_2/90.) * (double)png_state.charh/4.; + + /* First try the old GDFONTPATH mechanism for locating fonts */ + (void)gdUseFontConfig(0); +#ifdef gdFTEX_Adobe_Custom + /* libgd defaults to UTF-8 encodings. We have limited options for */ + /* over-riding this, but we can try */ + if (encoding != S_ENC_UTF8 && ENHgd_font && !strcmp(ENHgd_font,"Symbol")) { + PNG_FONT_INFO.flags |= gdFTEX_CHARMAP; + PNG_FONT_INFO.charmap = gdFTEX_Adobe_Custom; + } else { + PNG_FONT_INFO.flags &= ~gdFTEX_CHARMAP; + PNG_FONT_INFO.charmap = 0; /* gdFTEX_Adobe_Custom */ + } + err = gdImageStringFTEx( + (ENHgd_show && !ENHgd_sizeonly) ? png_state.image : NULL, + brect, png_state.color, + ENHgd_font, ENHgd_fontsize, + (double)png_state.angle * M_PI_2/90., + x, Y(y), fragment, &PNG_FONT_INFO); + if (err && gdUseFontConfig(1)) { + err = gdImageStringFTEx( + (ENHgd_show && !ENHgd_sizeonly) ? png_state.image : NULL, + brect, png_state.color, + ENHgd_font, ENHgd_fontsize, + (double)png_state.angle * M_PI_2/90., + x, Y(y), fragment, &PNG_FONT_INFO); + } +#else + err = gdImageStringFT( + (ENHgd_show && !ENHgd_sizeonly) ? png_state.image : NULL, + brect, png_state.color, + ENHgd_font, ENHgd_fontsize, + (double)png_state.angle * M_PI_2/90., + x, Y(y), fragment); + if (err && gdUseFontConfig(1)) { + err = gdImageStringFT( + (ENHgd_show && !ENHgd_sizeonly) ? png_state.image : NULL, + brect, png_state.color, + ENHgd_font, ENHgd_fontsize, + (double)png_state.angle * M_PI_2/90., + x, Y(y), fragment); + } +#endif + if (err) + fprintf(stderr,"gdImageStringFT: %s while printing string %s with font %s\n", + err,enhanced_text,ENHgd_font); + +#ifdef EAM_BOXED_TEXT + if (!ENHgd_sizeonly) { + int xmax = GPMAX(brect[2],brect[6]); + int xmin = GPMIN(brect[0],brect[4]); + int ymax = GPMIN(brect[1],brect[3]); + int ymin = GPMAX(brect[5],brect[7]); + if (xmin < bounding_box[0]) bounding_box[0] = xmin; + if (xmax > bounding_box[2]) bounding_box[2] = xmax; + if (ymin < bounding_box[1]) bounding_box[1] = ymin; + if (ymax > bounding_box[3]) bounding_box[3] = ymax; + } +#endif + + if (ENHgd_overprint == 1) { + png_state.x += ((brect[2] - brect[0]))/2; + png_state.y -= (brect[3] - brect[1]); + } else if (ENHgd_widthflag) { + png_state.x += (brect[2] - brect[0]); + png_state.y -= (brect[3] - brect[1]); + } +} + +TERM_PUBLIC void +ENHGD_put_text(unsigned int x, unsigned int y, const char *str) +{ + char *original_string = (char *)str; + + if (ignore_enhanced_text || !png_state.ttffont) { + PNG_put_text(x,y,str); + return; + } + + if (!strlen(str)) + return; + + /* if there are no magic characters, we should just be able + * punt the string to PNG_put_text() + */ + if (!strpbrk(str, "{}^_@&~")) { + /* FIXME: do something to ensure default font is selected */ + PNG_put_text(x,y,str); + return; + } + + PNG_move(x,y); + + /* set up the global variables needed by enhanced_recursion() */ + enhanced_fontscale = png_state.fontscale; + strncpy(enhanced_escape_format,"&#x%2.2x;",sizeof(enhanced_escape_format)); + + ENHgd_opened_string = FALSE; + ENHgd_show = TRUE; + ENHgd_overprint = 0; + + /* EAM - post.trm wasn't doing this, but how else do they get initialized? */ + ENHgd_font = png_state.ttffont; + ENHgd_fontsize = png_state.ttfsize; + + /* EAM - Software text justification requires two passes */ + if (png_state.justify == RIGHT || png_state.justify == CENTRE) + ENHgd_sizeonly = TRUE; + + /* 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. + */ + while (*(str = enhanced_recursion((char *)str, TRUE, + ENHgd_font, ENHgd_fontsize * png_state.fontscale, + 0.0, TRUE, TRUE, 0))) { + (term->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 */ + } + + /* We can do text justification by running the entire top level string */ + /* through 2 times, with the ENHgd_sizeonly flag set the first time. */ + /* After seeing where the final position is, we then offset the start */ + /* point accordingly and run it again without the flag set. */ + if (png_state.justify == RIGHT || png_state.justify == CENTRE) { + int justification = png_state.justify; + int x_offset = png_state.x - x; + int y_offset = 0; + + if (png_state.angle != 0) + y_offset = png_state.y - y; + png_state.justify = LEFT; + ENHgd_sizeonly = FALSE; + + if (justification == RIGHT) { + ENHGD_put_text(x - x_offset, y - y_offset, original_string); + } else if (justification == CENTRE) { + ENHGD_put_text(x - x_offset/2, y - y_offset/2, original_string); + } + png_state.justify = justification; + } + +} + +#ifdef EAM_BOXED_TEXT +TERM_PUBLIC void +ENHGD_boxed_text(unsigned int x, unsigned int y, int option) +{ + switch (option) { + case TEXTBOX_INIT: + /* Initialize bounding box for this text string */ + bounding_box[0] = bounding_box[2] = x; + bounding_box[1] = bounding_box[3] = Y(y); + break; + case TEXTBOX_OUTLINE: + /* Stroke the outline of the bounding box for previous text */ + gdImageLine(png_state.image, + bounding_box[0]-bounding_xmargin, bounding_box[1]-bounding_ymargin, + bounding_box[0]-bounding_xmargin, bounding_box[3]+bounding_ymargin, + png_state.color); + gdImageLine(png_state.image, + bounding_box[0]-bounding_xmargin, bounding_box[3]+bounding_ymargin, + bounding_box[2]+bounding_xmargin, bounding_box[3]+bounding_ymargin, + png_state.color); + gdImageLine(png_state.image, + bounding_box[2]+bounding_xmargin, bounding_box[3]+bounding_ymargin, + bounding_box[2]+bounding_xmargin, bounding_box[1]-bounding_ymargin, + png_state.color); + gdImageLine(png_state.image, + bounding_box[2]+bounding_xmargin, bounding_box[1]-bounding_ymargin, + bounding_box[0]-bounding_xmargin, bounding_box[1]-bounding_ymargin, + png_state.color); + break; + case TEXTBOX_BACKGROUNDFILL: + /* Fill the box with current color. */ + gdImageFilledRectangle(png_state.image, + bounding_box[0] - bounding_xmargin, + bounding_box[1] - bounding_ymargin, + bounding_box[2] + bounding_xmargin, + bounding_box[3] + bounding_ymargin, + png_state.color); + break; + case TEXTBOX_MARGINS: + /* Change the text margins */ + bounding_xmargin = GD_TEXTBOX_MARGIN * (double)x / 100.; + bounding_ymargin = GD_TEXTBOX_MARGIN * (double)y / 100.; + break; + default: + break; + } +} +#endif + + + +#undef gdfont + +TERM_PUBLIC void +PNG_image (unsigned int M, unsigned int N, coordval * image, gpiPoint * corner, t_imagecolor color_mode) +{ + int m, n, mout, nout; + int x1,y1,x2,y2; + int xclip1, xclip2, yclip1, yclip2; + int pixel; + gdImagePtr im; + + if (png_state.TrueColor) { + im = gdImageCreateTrueColor(M, N); + if (!im) + int_error(NO_CARET,"libgd: failed to create image structure"); + } else { + im = gdImageCreate(M, N); + if (!im) + int_error(NO_CARET,"libgd: failed to create image structure"); + gdImagePaletteCopy(im, png_state.image); + } + + /* Set clipping bound for area into which we will copy */ + xclip1 = GPMIN(corner[2].x, corner[3].x); + xclip2 = GPMAX(corner[2].x, corner[3].x); + yclip1 = GPMIN(Y(corner[2].y), Y(corner[3].y)); + yclip2 = GPMAX(Y(corner[2].y), Y(corner[3].y)); + gdImageGetClip(png_state.image, &x1, &y1, &x2, &y2); + gdImageSetClip(png_state.image, xclip1, yclip1, xclip2, yclip2); + + /* Initialize image area with current contents of plot. */ + mout = abs( (int)corner[1].x - (int)corner[0].x ); + nout = abs( (int)corner[1].y - (int)corner[0].y ); + + if (color_mode == IC_RGBA) { + /* RGB + Alpha channel + * Resize explicitly in a loop rather than calling a library + * routine in order not to apply the alpha correction more than + * once when building up any given output pixel. + */ + for (n=0; n>1); /* input is [0:255] but gd wants [127:0] */ + rgb255_from_rgb1( rgb1, &rgb255 ); + pixel = gdImageColorResolveAlpha( png_state.image, + (int)rgb255.r, (int)rgb255.g, (int)rgb255.b, alpha); + gdImageSetPixel( png_state.image, m + corner[0].x, n + Y(corner[0].y), pixel ); + } + } + + } else if (color_mode == IC_RGB) { + /* TrueColor 24-bit color mode */ + for (n=0; n Shift_JIS by iconv */ + len2 = len1; + iconv_string = gp_alloc(len2, "iconv string"); + stmp = iconv_string; + if ((cd = iconv_open("Shift_JIS", "UTF-8")) == (iconv_t)-1) + int_warn(NO_CARET, "iconv_open failed"); + else { + if (iconv(cd, (void *)string, &len1, &stmp, &len2) == (size_t)-1) + int_warn(NO_CARET, "iconv failed"); + else + *string = iconv_string; + iconv_close(cd); + } + } +#else /* ! JIS_GDLIB */ + if (encoding == S_ENC_SJIS) { /* Shift_JIS -> UTF-8 by iconv */ + len2 = len1*3/2+2; + iconv_string = gp_alloc(len2, "iconv string"); + stmp = iconv_string; + if ((cd = iconv_open("UTF-8", "Shift_JIS")) == (iconv_t)-1) + int_warn(NO_CARET, "iconv_open failed"); + else { + if (iconv(cd, (void *)string, &len1, &stmp, &len2) == (size_t)-1) + int_warn(NO_CARET, "iconv failed"); + else + *string = iconv_string; + iconv_close(cd); + } + } +#endif /* JIS_GDLIB */ +#else /* ! HAVE_ICONV */ +#ifdef JIS_GDLIB + if (encoding == S_ENC_UTF8) + int_warn(NO_CARET, + "This gdlib supports Shift_JIS encoding, but not UTF-8."); +#else /* ! JIS_GDLIB */ + if (encoding == S_ENC_SJIS) /* Shift_JIS -> UTF-8 */ + int_warn(NO_CARET, + "This gdlib supports UTF-8 encoding, but not Shift_JIS."); +#endif /* JIS_GDLIB */ +#endif /* HAVE_ICONV */ +} + +#undef MAXLINEWIDTH +#undef Y + +#endif /* TERM_BODY */ +#ifdef TERM_TABLE + +TERM_TABLE_START(png_driver) + "png", "PNG images using libgd and TrueType fonts", + GREG_XMAX, GREG_YMAX, PNG_VCHAR, PNG_HCHAR, + PNG_TICSIZE, PNG_TICSIZE, PNG_options, PNG_init, PNG_reset, + PNG_text, null_scale, PNG_graphics, PNG_move, PNG_vector, + PNG_linetype, PNG_put_text, PNG_text_angle, + PNG_justify_text, PNG_point, do_arrow, PNG_set_font, + PNG_pointsize, + TERM_CAN_MULTIPLOT|TERM_BINARY|TERM_LINEWIDTH|TERM_FONTSCALE, /* TERM_ALPHA_CHANNEL only if truecolor */ + 0 /*suspend*/, 0 /*resume*/, + PNG_boxfill /*EAM - fillbox*/, + PNG_linewidth /*EAM - linewidth*/ +#ifdef USE_MOUSE + , 0, 0, 0, 0, 0 /* no mouse support */ +#endif + , PNG_make_palette, + 0, /* previous_palette() ... no, single array of 256 colours for PNG */ + PNG_set_color, + PNG_filled_polygon + , PNG_image + , ENHGD_OPEN, ENHGD_FLUSH, do_enh_writec + , NULL /* layering */ + , NULL /* path */ + , 0.0 /* tscale */ + , NULL /* hypertext */ +#ifdef EAM_BOXED_TEXT + , ENHGD_boxed_text +#endif +TERM_TABLE_END(png_driver) + +#undef LAST_TERM +#define LAST_TERM png_driver + +#endif /* TERM_TABLE */ +#endif /* TERM_PROTO_ONLY */ + +#ifndef JPEG_HELP_ONLY +#ifdef TERM_HELP +START_HELP(png) +"1 png", +"?commands set terminal png", +"?set terminal png", +"?set term png", +"?terminal png", +"?term png", +"?png", +" Syntax:", +" set terminal png ", +" {{no}enhanced}", +" {{no}transparent} {{no}interlace}", +" {{no}truecolor} {rounded|butt}", +" {linewidth } {dashlength
}", +" {tiny | small | medium | large | giant}", +" {font \" {,}\"} {fontscale }", +" {size ,} {{no}crop}", +" {background }", +"", +" PNG, JPEG and GIF images are created using the external library libgd.", +" PNG plots may be viewed interactively by piping the output to the", +" 'display' program from the ImageMagick package as follows:", +" set term png", +" set output '| display png:-'", +" You can view the output from successive plot commands interactively by typing", +" in the display window. To save the current plot to a file,", +" left click in the display window and choose `save`.", +"", +" `transparent` instructs the driver to make the background color transparent.", +" Default is `notransparent`.", +"", +" `interlace` instructs the driver to generate interlaced PNGs.", +" Default is `nointerlace`.", +"", +" The `linewidth` and `dashlength` options are scaling factors that affect all", +" lines drawn, i.e. they are multiplied by values requested in various drawing", +" commands.", +"", +" By default output png images use 256 indexed colors. The `truecolor` option", +" instead creates TrueColor images with 24 bits of color information per pixel.", +" Transparent fill styles require the `truecolor` option. See `fillstyle`.", +" A transparent background is possible in either indexed or TrueColor images.", +"", +" `butt` instructs the driver to use a line drawing method that does", +" not overshoot the desired end point of a line. This setting is only", +" applicable for line widths greater than 1. This setting is most useful when", +" drawing horizontal or vertical lines. Default is `rounded`.", +"", +" The details of font selection are complicated.", +" Two equivalent simple examples are given below:", +" set term png font arial 11", +" set term png font \"arial,11\"", +" For more information please see the separate section under `fonts`.", +"", +" The output plot size is given in pixels---it defaults to 640x480.", +" Please see additional information under `canvas` and `set size`.", +" Blank space at the edges of the finished plot may be trimmed using the `crop`", +" option, resulting in a smaller final image size. Default is `nocrop`.", +"", +"2 examples", +"?set term png examples", +" set terminal png medium size 640,480 background '#ffffff'", +"", +" Use the medium size built-in non-scaleable, non-rotatable font.", +" Use white (24-bit RGB in hexadecimal) for the non-transparent background.", +"", +" set terminal png font arial 14 size 800,600", +"", +" Searches for a scalable font with face name 'arial' and sets the font", +" size to 14pt. Please see `fonts` for details of how the font search", +" is done.", +"", +" set terminal png transparent truecolor enhanced", +"", +" Use 24 bits of color information per pixel, with a transparent background.", +" Use the `enhanced text` mode to control the layout of strings to be printed.", +"" +END_HELP(png) +#endif /* TERM_HELP */ +#endif /* JPEG_HELP_ONLY */ + +/* + * JPEG support comes almost for free. + * We just piggy-back on the PNG routines, since they both go via libgd + */ +#ifdef HAVE_GD_JPEG + +#ifdef TERM_REGISTER +register_term(jpeg) +#endif + +#ifdef TERM_PROTO +TERM_PUBLIC void JPEG_text __PROTO((void)); +#define GOT_NEXT_PROTO +#endif + +#ifndef TERM_PROTO_ONLY + +#ifdef TERM_BODY + +#include +/* + * All functions except the final write to file + * are actually performed by the PNG driver code + */ +TERM_PUBLIC void +JPEG_text() +{ +int quality = 90; + + image_do_crop(); + if (png_state.flags & PNG_USE_INTERLACE) + gdImageInterlace(png_state.image, 1); + gdImageJpeg(png_state.image, gpoutfile, quality); + gdImageDestroy(png_state.image); +} + +#endif /* TERM_BODY */ + +#ifdef TERM_TABLE + +TERM_TABLE_START(jpeg_driver) + "jpeg", "JPEG images using libgd and TrueType fonts", + GREG_XMAX, GREG_YMAX, PNG_VCHAR, PNG_HCHAR, + PNG_TICSIZE, PNG_TICSIZE, PNG_options, PNG_init, PNG_reset, + JPEG_text, null_scale, PNG_graphics, PNG_move, PNG_vector, + PNG_linetype, PNG_put_text, PNG_text_angle, + PNG_justify_text, PNG_point, do_arrow, PNG_set_font, + PNG_pointsize, + TERM_CAN_MULTIPLOT|TERM_BINARY|TERM_ALPHA_CHANNEL|TERM_LINEWIDTH|TERM_FONTSCALE, + 0 /*suspend*/, 0 /*resume*/, + PNG_boxfill /*EAM - fillbox*/, + PNG_linewidth /*EAM - linewidth*/ +#ifdef USE_MOUSE + , 0, 0, 0, 0, 0 /* no mouse support */ +#endif + , PNG_make_palette, + 0, /* previous_palette() ... no, single array of 256 colours for PNG */ + PNG_set_color, + PNG_filled_polygon + , PNG_image + , ENHGD_OPEN, ENHGD_FLUSH, do_enh_writec + , NULL /* layering */ + , NULL /* path */ + , 0.0 /* tscale */ + , NULL /* hypertext */ +#ifdef EAM_BOXED_TEXT + , ENHGD_boxed_text +#endif +TERM_TABLE_END(jpeg_driver) + +#undef LAST_TERM +#define LAST_TERM jpeg_driver + +#endif /* TERM_TABLE */ +#endif /* TERM_PROTO_ONLY */ + +#ifdef TERM_HELP +START_HELP(jpeg) +"1 jpeg", +"?commands set terminal jpeg", +"?set terminal jpeg", +"?set term jpeg", +"?terminal jpeg", +"?term jpeg", +"?jpeg", +" Syntax:", +" set terminal jpeg ", +" {{no}enhanced}", +" {{no}interlace}", +" {linewidth } {dashlength
} {rounded|butt}", +" {tiny | small | medium | large | giant}", +" {font \" {,}\"} {fontscale }", +" {size ,} {{no}crop}", +" {background }", +"", +" PNG, JPEG and GIF images are created using the external library libgd.", +" In most cases, PNG is to be preferred for single plots, and GIF for", +" animations. Both are loss-less image formats, and produce better image", +" quality than the lossy JPEG format. This is in particular noticeable", +" for solid color lines against a solid background, i.e. exactly the sort", +" of image typically created by gnuplot.", +"", +" The `interlace` option creates a progressive JPEG image.", +" Default is `nointerlace`.", +"", +" The `linewidth` and `dashlength` options are scaling factors that affect all", +" lines drawn, i.e. they are multiplied by values requested in various drawing", +" commands.", +"", +" `butt` instructs the driver to use a line drawing method that does", +" not overshoot the desired end point of a line. This setting is only", +" applicable for line widths greater than 1. This setting is most useful when", +" drawing horizontal or vertical lines. Default is `rounded`.", +"", +" The details of font selection are complicated.", +" Two equivalent simple examples are given below:", +" set term jpeg font arial 11", +" set term jpeg font \"arial,11\"", +" For more information please see the separate section under `fonts`.", +"", +" The output plot size is given in pixels---it defaults to 640x480.", +" Please see additional information under `canvas` and `set size`.", +" Blank space at the edges of the finished plot may be trimmed using the `crop`", +" option, resulting in a smaller final image size. Default is `nocrop`.", +"" +END_HELP(jpeg) +#endif /* TERM_HELP */ +#endif /* HAVE_GD_JPEG */ + +#ifdef HAVE_GD_GIF +/* + * GIF support comes almost for free. + * We just piggy-back on the PNG routines, since they both go via libgd. + * Required libgd version is 2.0.28 or newer. + */ +#ifdef HAVE_GD_GIF + +#ifdef TERM_REGISTER +register_term(gif) +#endif + +#ifdef TERM_PROTO +TERM_PUBLIC void GIF_text __PROTO((void)); +#define GOT_NEXT_PROTO +#endif + +#ifndef TERM_PROTO_ONLY + +#ifdef TERM_BODY + +#include +/* + * All functions except the final write to file + * are actually performed by the PNG driver code + */ +TERM_PUBLIC void +GIF_text() +{ + image_do_crop(); + +#ifdef GIF_ANIMATION + if (png_state.animate) { + /* Note - using a global colormap saves space, but it breaks */ + /* if later frames add new colors to the palette. */ + if (png_state.frame_count == 0) { + gdImageGifAnimBegin(png_state.image, gpoutfile, + 1, /* Load Global Colormap even if it isn't used */ + png_state.loop_count ); + } + gdImageGifAnimAdd(png_state.image, gpoutfile, + png_state.frame_optimization ? 0 /* use global map */ + : 1, /* use private map */ + 0, 0 /* No offset */, + png_state.frame_delay, + (png_state.flags & PNG_USE_TRANSPARENT) + ? gdDisposalRestorePrevious + : gdDisposalNone, + (png_state.frame_optimization && !(png_state.flags & PNG_USE_TRANSPARENT)) + ? png_state.previous_image : NULL); + png_state.frame_count++; + if (png_state.previous_image) + gdImageDestroy(png_state.previous_image); + png_state.previous_image = png_state.image; + return; + } +#endif + + gdImageGif(png_state.image, gpoutfile); + gdImageDestroy(png_state.image); +} + +#endif /* TERM_BODY */ + +#ifdef TERM_TABLE + +TERM_TABLE_START(gif_driver) + "gif", "GIF images using libgd and TrueType fonts", + GREG_XMAX, GREG_YMAX, PNG_VCHAR, PNG_HCHAR, + PNG_TICSIZE, PNG_TICSIZE, PNG_options, PNG_init, PNG_reset, + GIF_text, null_scale, PNG_graphics, PNG_move, PNG_vector, + PNG_linetype, PNG_put_text, PNG_text_angle, + PNG_justify_text, PNG_point, do_arrow, PNG_set_font, + PNG_pointsize, + TERM_CAN_MULTIPLOT|TERM_BINARY|TERM_LINEWIDTH|TERM_FONTSCALE, + 0 /*suspend*/, 0 /*resume*/, + PNG_boxfill /*EAM - fillbox*/, + PNG_linewidth /*EAM - linewidth*/ +#ifdef USE_MOUSE + , 0, 0, 0, 0, 0 /* no mouse support */ +#endif + , PNG_make_palette, + 0, /* previous_palette() ... no, single array of 256 colours for PNG */ + PNG_set_color, + PNG_filled_polygon + , PNG_image + , ENHGD_OPEN, ENHGD_FLUSH, do_enh_writec + , NULL /* layering */ + , NULL /* path */ + , 0.0 /* tscale */ + , NULL /* hypertext */ +#ifdef EAM_BOXED_TEXT + , ENHGD_boxed_text +#endif +TERM_TABLE_END(gif_driver) + +#undef LAST_TERM +#define LAST_TERM gif_driver + +#endif /* TERM_TABLE */ +#endif /* TERM_PROTO_ONLY */ + + +#ifdef TERM_HELP +START_HELP(gif) +"1 gif", +"?commands set terminal gif", +"?set terminal gif", +"?set term gif", +"?terminal gif", +"?term gif", +"?gif", +" Syntax:", +" set terminal gif ", +" {{no}enhanced}", +" {{no}transparent} {rounded|butt}", +" {linewidth } {dashlength
}", +" {tiny | small | medium | large | giant}", +" {font \" {,}\"} {fontscale }", +" {size ,} {{no}crop}", +" {animate {delay } {loop } {{no}optimize}}", +" {background }", +"", +" PNG, JPEG and GIF images are created using the external library libgd.", +" GIF plots may be viewed interactively by piping the output to the", +" 'display' program from the ImageMagick package as follows:", +" set term gif", +" set output '| display gif:-'", +" You can view the output from successive plot commands interactively by typing", +" in the display window. To save the current plot to a file,", +" left click in the display window and choose `save`.", +"", +" `transparent` instructs the driver to make the background color transparent.", +" Default is `notransparent`.", +"", +" The `linewidth` and `dashlength` options are scaling factors that affect all", +" lines drawn, i.e. they are multiplied by values requested in various drawing", +" commands.", +"", +" `butt` instructs the driver to use a line drawing method that does", +" not overshoot the desired end point of a line. This setting is only", +" applicable for line widths greater than 1. This setting is most useful when", +" drawing horizontal or vertical lines. Default is `rounded`.", +"", +" The details of font selection are complicated.", +" Two equivalent simple examples are given below:", +" set term gif font arial 11", +" set term gif font \"arial,11\"", +" For more information please see the separate section under `fonts`.", +"", +" The `animate` option is available only if your local gd library supports", +" the creation of animated gifs. The default delay between display of", +" successive images may be specified in units of 1/100 second (default 5).", +" The actual delay may vary depending on the program used as a viewer.", +" Number of animation loops can be specified, default 0 means infinity.", +" An animation sequence is terminated by the next `set output` or `set term`", +" command. The `optimize` option has two effects on the animation.", +"", +" 1) A single color map is used for the entire animation. This requires", +" that all colors used in any frame of the animation are already", +" defined in the first frame.", +"", +" 2) If possible, only the portions of a frame that differ from the", +" previous frame are stored in the animation file. This space saving", +" may not be possible if the animation uses transparency.", +"", +" Both of these optimizations are intended to produce a smaller output file,", +" but the decrease in size is probably only significant for long animations", +" or very small frame sizes.", +" The `nooptimize` option turns off both of the effects just described.", +" Each frame is stored in its entirety along with a private color map.", +" Note that it is possible to post-process a non-optimized animation", +" using external utilities, and this post-processing can yield a smaller", +" file than gnuplot's internal optimization mode.", +" The default is `nooptimize`.", +"", +" The output plot size is given in pixels---it defaults to 640x480.", +" Please see additional information under `canvas` and `set size`.", +" Blank space at the edges of the finished plot may be trimmed using the `crop`", +" option, resulting in a smaller final image size. Default is `nocrop`.", +"", +"2 examples", +"?set term gif examples", +" set terminal gif medium size 640,480 background '#ffffff'", +"", +" Use the medium size built-in non-scaleable, non-rotatable font.", +" Use white (24 bit RGB in hexadecimal) for the non-transparent background.", +"", +" set terminal gif font arial 14 enhanced", +"", +" Searches for a scalable font with face name 'arial' and sets the font", +" size to 14pt. Please see `fonts` for details of how the font search", +" is done. Because this is a scalable font, we can use enhanced text mode.", +"", +" set term gif animate transparent opt delay 10 size 200,200", +" load \"animate2.dem\"", +"", +" Open the gif terminal for creation of an animated gif file. The individual", +" frames of the animation sequence are created by the script file animate2.dem", +" from the standard collection of demos.", +"" +END_HELP(gif) +#endif /* TERM_HELP */ +#endif /* HAVE_GD_GIF */ +#endif + + +#define WITH_GD_SIXEL +#ifdef WITH_GD_SIXEL +/* + * Sixel support comes almost for free. + * We just piggy-back on the libgd PNG routines. + */ + +#ifdef TERM_REGISTER +register_term(sixelgd) +#endif + +#ifdef TERM_PROTO +TERM_PUBLIC void SIXELGD_text(void); +#define GOT_NEXT_PROTO +#endif + +#ifndef TERM_PROTO_ONLY + +#ifdef TERM_BODY + +#include "sixel.c" + +/* + * All functions except the final write to file + * are actually performed by the PNG driver code + */ +TERM_PUBLIC void +SIXELGD_text() +{ + image_do_crop(); + + /* The 'animate' option makes each plot write in place rather than scrolling */ + if (png_state.animate) + fprintf(gpoutfile, "\033[H"); + + /* maximum number of palette colors (256), no truecolor images, fill optimization */ + if (png_state.TrueColor) + gdImageSixel(png_state.image, gpoutfile, 256, FALSE, TRUE); + else + gdImageSixel(png_state.image, gpoutfile, 16, FALSE, TRUE); + gdImageDestroy(png_state.image); +} + +#endif /* TERM_BODY */ + +#ifdef TERM_TABLE + +TERM_TABLE_START(sixelgd_driver) + "sixelgd", "sixel using libgd and TrueType fonts", + GREG_XMAX, GREG_YMAX, PNG_VCHAR, PNG_HCHAR, + PNG_TICSIZE, PNG_TICSIZE, PNG_options, PNG_init, PNG_reset, + SIXELGD_text, null_scale, PNG_graphics, PNG_move, PNG_vector, + PNG_linetype, PNG_put_text, PNG_text_angle, + PNG_justify_text, PNG_point, do_arrow, PNG_set_font, + PNG_pointsize, + TERM_CAN_MULTIPLOT|TERM_BINARY|TERM_ALPHA_CHANNEL|TERM_LINEWIDTH|TERM_FONTSCALE, + 0 /*suspend*/, 0 /*resume*/, + PNG_boxfill, + PNG_linewidth, +#ifdef USE_MOUSE + 0, 0, 0, 0, 0, /* no mouse support */ +#endif + PNG_make_palette, + 0, /* previous_palette() ... no, single array of 256 colours for PNG */ + PNG_set_color, + PNG_filled_polygon, + PNG_image, + ENHGD_OPEN, ENHGD_FLUSH, do_enh_writec, + NULL, /* layering */ + NULL, /* path */ + 0.0, /* tscale */ + NULL /* hypertext */ +#ifdef EAM_BOXED_TEXT + , ENHGD_boxed_text +#endif +TERM_TABLE_END(sixelgd_driver) + +#undef LAST_TERM +#define LAST_TERM sixelgd_driver + +#endif /* TERM_TABLE */ +#endif /* TERM_PROTO_ONLY */ + + +#ifdef TERM_HELP +START_HELP(sixelgd) +"1 sixelgd", +"?commands set terminal sixelgd", +"?set terminal sixelgd", +"?set term sixelgd", +"?terminal sixelgd", +"?term sixelgd", +"?sixelgd", +" Syntax:", +" set terminal sixelgd", +" {{no}enhanced}", +" {{no}transparent} {rounded|butt}", +" {linewidth } {dashlength
}", +" {tiny | small | medium | large | giant}", +" {font \" {,}\"} {fontscale }", +" {size ,} {{no}crop} {animate}", +" {background }", +"", +" The `sixel` output format was originally used by DEC terminals and printers.", +" This driver produces a sixel output stream by converting a PNG image created", +" internally using the gd library. The sixel output stream can be viewed in the", +" terminal as it is created or it can be written to a file so that it can be", +" replayed later by echoing the file to the terminal.", +"", +" The `animate` option resets the cursor position to the terminal top left at", +" the start of every plot so that successive plots overwrite the same area on", +" the screen rather than having earlier plots scroll off the top. This may be", +" desirable in order to create an in-place animation.", +"", +" `transparent` instructs the driver to make the background color transparent.", +" Default is `notransparent`.", +"", +" The `linewidth` and `dashlength` options are scaling factors that affect all", +" lines drawn, i.e. they are multiplied by values requested in various drawing", +" commands.", +"", +" By default the sixel output uses 16 indexed colors. The `truecolor` option", +" instead creates a TrueColor png image that is mapped down onto 256 colors", +" in the output sixel image. Transparent fill styles require the `truecolor`", +" option. See `fillstyle`.", +" A `transparent` background is possible in either indexed or TrueColor images.", +"", +" `butt` instructs the driver to use a line drawing method that does", +" not overshoot the desired end point of a line. This setting is only", +" applicable for line widths greater than 1. This setting is most useful when", +" drawing horizontal or vertical lines. Default is `rounded`.", +"", +" The details of font selection are complicated.", +" For more information please see `fonts`.", +"", +" The output plot size is given in pixels---it defaults to 640x480.", +" Please see additional information under `canvas` and `set size`.", +" Blank space at the edges of the finished plot may be trimmed using the `crop`", +" option, resulting in a smaller final image size. Default is `nocrop`." +"", +" The terminal has been sucessfully tested with the xterm, mlterm and mintty", +" terminals. The later two support the `truecolor` mode using 256 sixel", +" colors out of box. Distributed copies of xterm may or may not have been", +" configured to support sixel graphics and 256 colors." +END_HELP(sixelgd) +#endif /* TERM_HELP */ +#endif /* WITH_GD_SIXEL */