/* * $Id: $ */ /* GNUPLOT -- gif.trm */ /*[ * Copyright 1998 * * 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: * GD GIF library 1.2 & 1.3 * * To Use: * * set terminal gif ?options ...? * * Where an option is: * * transparent - generate transparent GIFs. The first color will * be the transparent one. * * interlace - generate interlaced GIFs. * * size (in pixels) * * font (small,medium,large) * * 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 * * CONTRIBUTORS * Alfred Reibenschuh or * * send your comments or suggestions to: * info-gnuplot@cs.dartmouth.edu * * This version outputs either color or monochrome GIFs. The default * is 640x480 pixels. * * link with -Lterm/gd -lgd if your directory structure is gnuplot/term/gd * * gd is not distributed with gnuplot, because of the UNISYS license thing. * * find out about gd from http://www.boutell.com/gd/ * * [Update: as of version 1.3, gd does not use any more UNISYS licensed * code. The gnuplot team may decide to include this version some day.] * */ #include "driver.h" #ifdef TERM_REGISTER register_term(gif) #endif #ifdef TERM_PROTO TERM_PUBLIC void GIF_options __PROTO((void)); TERM_PUBLIC void GIF_init __PROTO((void)); TERM_PUBLIC void GIF_graphics __PROTO((void)); TERM_PUBLIC void GIF_text __PROTO((void)); TERM_PUBLIC void GIF_linetype __PROTO((int linetype)); TERM_PUBLIC void GIF_move __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void GIF_vector __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void GIF_put_text __PROTO((unsigned int x, unsigned int y, char str[])); TERM_PUBLIC int GIF_text_angle __PROTO((int ang)); TERM_PUBLIC void GIF_reset __PROTO((void)); #include "gd.h" extern gdFontPtr gdFontSmall; /* 6x12 */ extern gdFontPtr gdFontLarge; /* 8x16 */ extern gdFontPtr gdFontMediumBold; /* 7x13 */ #define GREG_XMAX 640 #define GREG_YMAX 480 int GIF_XMAX = GREG_XMAX; int GIF_YMAX = GREG_YMAX; #define GIF_FONT_SMALL 1 #ifdef GIF_FONT_SMALL # define gdfont gdFontSmall # define GIF_VCHAR 12 # define GIF_HCHAR 6 #else # define gdfont gdFontMediumBold # define GIF_VCHAR 13 # define GIF_HCHAR 7 #endif static gdFontPtr GIF_font; #define GIF_VTIC (GREG_YMAX/100) #define GIF_HTIC (GREG_XMAX/150) #define GIF_MAX_COLORS 256 #define GOT_NEXT_PROTO #endif #ifndef TERM_PROTO_ONLY #ifdef TERM_BODY static struct { gdImagePtr image; gdFontPtr font; unsigned int x, y; int height; int charh, charw; int color; int n_colors; int color_table[GIF_MAX_COLORS]; int rgb_table[GIF_MAX_COLORS]; int angle; int flags; int linetype; } gif_state; #define GIF_USE_TRANSPARENT 1 #define GIF_USE_INTERLACE 2 static unsigned int gif_color_rgbs[] = { 0xffffff, /* background: white */ 0x000000, /* borders: black */ 0x404040, /* x & y axes: grey */ 0xff0000, /* color 01: red */ 0x00c000, /* color 02: dark green */ 0x0080ff, /* color 03: dark blue */ 0xc000ff, /* color 04: dark magenta */ 0xc0ff40, /* color 05: yellow */ 0xc04000, /* color 06: orange */ 0x40ff80, /* color 07: sea green */ 0x2020c0, /* color 08: royal blue */ 0x8000c0, /* color 09: dark violet */ /* please note: these colors are optimized for web216 compatibility */ 0x006080, /* DeepSkyBlue4 */ 0x008000, /* green4 */ 0x008040, /* SpringGreen4 */ 0x008080, /* dark cyan, turquoise4 */ 0x00c060, /* SpringGreen3 */ 0x00c0c0, /* cyan3, turquoise3 */ 0x00ff00, /* green */ 0x208020, /* forest green */ 0x306080, /* SteelBlue4 */ 0x404040, /* grey25-31 */ 0x408000, /* chartreuse4 */ 0x000080, /* dark blue, navy blue */ 0x806000, /* DarkGoldenrod4 */ 0x806010, /* goldenrod4 */ 0x806060, /* pink4 */ 0x806080, /* plum4 */ 0x0000c0, /* medium blue */ 0x0000ff, /* blue */ 0x006000, /* dark green */ 0x40c080, /* SeaGreen3 */ 0x60a0c0, /* SkyBlue3 */ 0x60c000, /* chartreuse3 */ 0x60c0a0, /* medium aquamarine */ 0x800000, /* dark red */ 0x800080, /* dark magenta */ 0x602080, /* DarkOrchid4 */ 0x606060, /* dim grey */ 0x00ffff, /* cyan1, turquoise1 */ 0x202020, /* grey13-18 */ 0x204040, /* dark slate grey */ 0x204080, /* RoyalBlue4 */ 0x608020, /* olive drab */ 0x608060, /* DarkSeaGreen4 */ 0x608080, /* LightBlue4, PaleTurquoise4 */ 0x808040, /* LightGoldenrod4, khaki4 */ 0x808080, /* grey51-56 */ 0xa0a0a0, /* dark grey, grey63-68 */ 0xa0d0e0, /* light blue */ 0xc02020, /* firebrick3 */ 0xc06000, /* DarkOrange3 */ 0x80c0e0, /* sky blue */ 0xc060c0, /* orchid3 */ 0xc08000, /* orange3 */ 0xc08060, /* LightSalmon3 */ 0xff4000, /* orange red */ 0xff4040, /* brown1, tomato */ 0x80c0ff, /* light sky blue */ 0xff8060, /* salmon */ 0xff8080, /* light coral */ 0xc0a000, /* gold3 */ 0xc0c0c0, /* grey76-81, honeydew3, ivory3, snow3 */ 0xc0ffc0, /* DarkSeaGreen1 */ 0xff0000, /* red */ 0xff00ff, /* magenta */ 0xff80a0, /* PaleVioletRed1 */ 0xff80ff, /* orchid1 */ 0xc0c0a0, /* LemonChiffon3 */ 0xff6060, /* IndianRed1 */ 0xff8000, /* dark orange */ 0xffa000, /* orange */ 0x80e0e0, /* CadetBlue2, DarkSlateGray2 */ 0xa0e0e0, /* pale turquoise */ 0xa0ff20, /* green yellow */ 0xc00000, /* red3 */ 0xc000c0, /* magenta3 */ 0xa02020, /* brown */ 0xa020ff, /* purple */ 0x802000, /* OrangeRed4 */ 0x802020, /* brown4 */ 0x804000, /* DarkOrange4 */ 0x804020, /* sienna4 */ 0x804080, /* orchid4 */ 0x8060c0, /* MediumPurple3 */ 0x8060ff, /* SlateBlue1 */ 0x808000, /* yellow4 */ 0xa080ff, /* MediumPurple1 */ 0xc06080, /* PaleVioletRed3 */ 0xc0c000, /* yellow3 */ 0xff8040, /* sienna1 */ 0xffa040, /* tan1 */ 0xffa060, /* sandy brown */ 0xffa070, /* light salmon */ 0xffc020, /* goldenrod1 */ 0xffc0c0, /* RosyBrown1, pink */ 0xffff00, /* yellow */ 0xffff80, /* khaki1 */ 0xffffc0 /* lemon chiffon */ }; #define GIF_N_DEFAULT_COLORS (sizeof(gif_color_rgbs)/sizeof(gif_color_rgbs[0])) /* * _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 GIF_options() { int gif_font, i; term_options[0] = NUL; gif_state.n_colors = 0; gif_state.flags = 0; gif_font = 1; GIF_font = gdfont; while (!END_OF_COMMAND) { if (almost_equals(c_token, "t$ransparent")) { gif_state.flags |= GIF_USE_TRANSPARENT; ++c_token; } else if (almost_equals(c_token, "i$nterlace")) { gif_state.flags |= GIF_USE_INTERLACE; ++c_token; } else if (almost_equals(c_token, "s$mall")) { GIF_font = gdFontSmall; gif_font = 1; term->v_char = (unsigned int) (12); term->h_char = (unsigned int) (6); ++c_token; } else if (almost_equals(c_token, "m$edium")) { GIF_font = gdFontMediumBold; gif_font = 2; term->v_char = (unsigned int) (13); term->h_char = (unsigned int) (7); ++c_token; } else if (almost_equals(c_token, "l$arge")) { GIF_font = gdFontLarge; gif_font = 3; term->v_char = (unsigned int) (16); term->h_char = (unsigned int) (8); ++c_token; } else if (almost_equals(c_token, "si$ze")) { struct value s; c_token++; if (END_OF_COMMAND) { GIF_XMAX = GREG_XMAX; GIF_YMAX = GREG_YMAX; term->v_tic = GIF_YMAX / 80; term->h_tic = GIF_XMAX / 80; } else { GIF_XMAX = real(const_express(&s)); if (equals(c_token, ",")) { c_token++; GIF_YMAX = real(const_express(&s)); term->v_tic = GIF_YMAX / 80; term->h_tic = GIF_XMAX / 80; term->ymax = GIF_YMAX; term->xmax = GIF_XMAX; } } } else { /* not "size" */ char *string = input_line + token[c_token].start_index; unsigned long color; if (sscanf(string, "x%lx", &color) != 1) { int_error("invalid color spec, must be xRRGGBB", c_token); } else if (gif_state.n_colors == GIF_MAX_COLORS) { int_warn("too many colors, ingoring", c_token); ++c_token; } else { gif_state.rgb_table[gif_state.n_colors++] = color; ++c_token; } } } /* now generate options string */ if (gif_state.flags & GIF_USE_TRANSPARENT) { strcat(term_options, "transparent "); } if (gif_state.flags & GIF_USE_INTERLACE) { strcat(term_options, "interlace "); } switch (gif_font) { case 1: strcat(term_options, "small "); break; case 2: strcat(term_options, "medium "); break; case 3: strcat(term_options, "large "); break; } sprintf(term_options + strlen(term_options), "size %d,%d ", GIF_XMAX, GIF_YMAX); for (i = 0; i < gif_state.n_colors; i++) { sprintf(term_options + strlen(term_options), "x%06x ", gif_state.rgb_table[i]); } } /* * _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 GIF_init() { gif_state.linetype = 0; } /* * _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 GIF_reset() { } /* * _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 GIF_graphics() { int i; unsigned int rgb; gif_state.font = GIF_font; gif_state.color = 0; gif_state.image = gdImageCreate((int) (xsize * GIF_XMAX), (int) (ysize * GIF_YMAX)); gif_state.height = (int) (ysize * GIF_YMAX); gif_state.charw = term->h_char; /* gif_state.font->w; */ gif_state.charh = term->v_char; /* gif_state.font->h; */ for (i = gif_state.n_colors; i < GIF_N_DEFAULT_COLORS; i++) gif_state.rgb_table[i] = gif_color_rgbs[i]; if (gif_state.n_colors < GIF_N_DEFAULT_COLORS) gif_state.n_colors = GIF_N_DEFAULT_COLORS; for (i = 0; i < gif_state.n_colors; i++) { rgb = gif_state.rgb_table[i]; gif_state.color_table[i] = gdImageColorAllocate(gif_state.image, (rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff); } if (gif_state.flags & GIF_USE_TRANSPARENT) gdImageColorTransparent(gif_state.image, gif_state.color_table[0]); else gdImageColorTransparent(gif_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 GIF_text() { if (gif_state.flags & GIF_USE_INTERLACE) gdImageInterlace(gif_state.image, 1); gdImageGif(gif_state.image, gpoutfile); gdImageDestroy(gif_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 GIF_move(unsigned int x, unsigned int y) { gif_state.x = x; gif_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 GIF_vector(unsigned int x, unsigned int y) { int gif_linetype_dotted[5]; if (gif_state.linetype == -1) { gif_linetype_dotted[0] = gif_state.color_table[2]; gif_linetype_dotted[1] = gif_state.color_table[2]; gif_linetype_dotted[2] = gif_state.color_table[0]; gif_linetype_dotted[3] = gif_state.color_table[0]; gif_linetype_dotted[4] = gif_state.color_table[0]; gdImageSetStyle(gif_state.image, gif_linetype_dotted, 5); gdImageLine(gif_state.image, gif_state.x, gif_state.height - gif_state.y, x, gif_state.height - y, gdStyled); } else { gdImageLine(gif_state.image, gif_state.x, gif_state.height - gif_state.y, x, gif_state.height - y, gif_state.color); } gif_state.x = x; gif_state.y = y; } /* _linetype(lt) Called to set the line type before text is displayed or * line(s) plotted. This procedure should select a pen color or line * style if the device has these capabilities. * lt is an integer from -2 to 0 or greater. * An lt of -2 is used for the border of the plot. * An lt of -1 is used for the X and Y axes. * 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. * Most drivers provide 9 different linetypes (lt is 0 to 8). */ TERM_PUBLIC void GIF_linetype(int type) { if (type >= (gif_state.n_colors - 3)) type %= (gif_state.n_colors - 3); gif_state.color = gif_state.color_table[type + 3]; gif_state.linetype = type; } /* _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. */ TERM_PUBLIC void GIF_put_text(unsigned int x, unsigned int y, char *string) { if (gif_state.angle == 1) { x -= gif_state.charh / 2; gdImageStringUp(gif_state.image, gif_state.font, x, gif_state.height - y, string, gif_state.color); } else { y += gif_state.charh / 2; gdImageString(gif_state.image, gif_state.font, x, gif_state.height - y, string, gif_state.color); } } /* _text_angle(ang) Called to rotate the text angle when placing the y label. * If ang = 0 then text is horizontal. If ang = 1 then text is vertically * upwards. Returns TRUE if text can be rotated, FALSE otherwise. */ TERM_PUBLIC int GIF_text_angle(int ang) { gif_state.angle = ang; return TRUE; } /* * Local Variables: * mode:C * End: */ #endif /* TERM_BODY */ #ifdef TERM_TABLE TERM_TABLE_START(gif_driver) "gif", "GIF format [mode] [fontsize] [size] [colors]", GREG_XMAX, GREG_YMAX, GIF_VCHAR, GIF_HCHAR, GIF_VTIC, GIF_HTIC, GIF_options, GIF_init, GIF_reset, GIF_text, null_scale, GIF_graphics, GIF_move, GIF_vector, GIF_linetype, GIF_put_text, GIF_text_angle, null_justify_text, do_point, do_arrow, set_font_null, 0, /* pointsize */ TERM_CAN_MULTIPLOT | TERM_BINARY 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", " The `gif` terminal driver generates output in GIF format. It uses Thomas", " Boutell's gd library, which is available from http://www.boutell.com/gd/", "", " Syntax:", " set terminal gif {transparent} {interlace}", " {small | medium | large}", " {size ,}", " { ...}", "", " `transparent` instructs the driver to generate transparent GIFs. The first", " color will be the transparent one.", "", " `interlace` instructs the driver to generate interlaced GIFs.", "", " The choice of fonts is `small` (6x12 pixels), `medium` (7x13 Bold) or `large`", " (8x16).", "", " The size is given in pixels---it defaults to 640x480. The number of", " pixels can be also modified by scaling with the `set size` command.", "", " Each color must be of the form 'xrrggbb', where x is the literal character", " 'x' and 'rrggbb' are the red, green and blue components in hex. For example,", " 'x00ff00' is green. The background color is set first, then the border", " colors, then the X & Y axis colors, then the plotting colors. The maximum", " number of colors that can be set is 256.", "", " Examples:", " set terminal gif small size 640,480 \\", " xffffff x000000 x404040 \\", " xff0000 xffa500 x66cdaa xcdb5cd \\", " xadd8e6 x0000ff xdda0dd x9500d3 # defaults", "", " which uses white for the non-transparent background, black for borders, gray", " for the axes, and red, orange, medium aquamarine, thistle 3, light blue, blue,", " plum and dark violet for eight plotting colors.", "", " set terminal gif transparent xffffff \\", " x000000 x202020 x404040 x606060 \\", " x808080 xA0A0A0 xC0C0C0 xE0E0E0 \\", " which uses white for the transparent background, black for borders, dark", " gray for axes, and a gray-scale for the six plotting colors.", "", " The page size is 640x480 pixels. The `gif` driver can create either color", " or monochromatic output, but you have no control over which is produced.", "", " The current version of the `gif` driver does not support animated GIFs." END_HELP(gif) #endif /* TERM_HELP */