1 /* Hello, Emacs, this is -*-C-*-
2 * $Id: gd.trm,v 1.95.2.16 2009/03/03 02:43:52 sfeam Exp $
3 * based on gif.trm,v 1.26.2.1 2000/05/01 00:17:20 joze
6 /* GNUPLOT -- gd.trm */
9 * Copyright 1998, 2001, 2004
11 * Permission to use, copy, and distribute this software and its
12 * documentation for any purpose with or without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and
14 * that both that copyright notice and this permission notice appear
15 * in supporting documentation.
17 * Permission to modify the software is granted, but not the right to
18 * distribute the complete modified source code. Modifications are to
19 * be distributed as patches to the released version. Permission to
20 * distribute binaries produced by compiling modified sources is granted,
22 * 1. distribute the corresponding source modifications from the
23 * released version in the form of a patch file along with the binaries,
24 * 2. add special version identification to distinguish your version
25 * in addition to the base release version number,
26 * 3. provide your name and address as the primary contact for the
27 * support of your modified version, and
28 * 4. retain our contact information in regard to use of the base
30 * Permission to distribute the released version of the source code along
31 * with corresponding source modifications in the form of a patch file is
32 * granted with same provisions 2 through 4 for binary distributions.
34 * This software is provided "as is" without express or implied warranty
35 * to the extent permitted by applicable law.
39 * This file is included by ../term.c.
41 * This terminal driver supports PNG and JPEG output using
46 * set terminal png ?options ...?
50 * transparent - generate transparent PNGs. The first color will
51 * be the transparent one.
53 * interlace - generate interlaced PNGs.
55 * image size (in pixels)
57 * font size (tiny,small,medium,large,giant)
59 * font name (TrueType or Adobe Type 1 font name is passed to libgd)
61 * xrrggbb - sets the next color. x is the literal character 'x',
62 * rrggbb are the red green and blue components in hex. For example
63 * x00ff00 is green. The background color is set first, then the
64 * color borders, then the X & Y axis, then the plotting colors.
65 * (The wierd color spec is in order to get around limitations
66 * in gnuplot's scanner.)
68 * This driver is modeled after the PBM driver pbm.trm.
71 * Sam Shen <sls@mh1.lbl.gov>
72 * Alex Woo <woo@playfair.stanford.edu>
73 * Ethan A Merritt <merritt@u.washington.edu>
76 * Alfred Reibenschuh <alfred.reibenschuh@it-austria.com> or <fredo@blackbox.at>
77 * Ben Laurie <ben@algroup.co.uk>
79 * This version outputs either color or monochrome PNGs.
80 * The default is 640x480 pixels.
82 ******************************************************************************
84 * This driver uses the gd library, available from http://www.boutell.com/gd/ *
85 * Earlier versions of the gd library produced GIF images, but starting with *
86 * version 1.6 the gd library no longer supports creation of GIF images due *
87 * to licensing issues. Hence this modified driver, which uses the old gd/gif *
88 * code to produce PNG images instead. *
91 * libgd version 1.8 or greater http://www.boutell.com/gd/ *
92 * libfreetype version 2 http://www.freetype.org/ *
94 * This driver allows you to use TrueType fonts. You can use this driver *
95 * without having any TrueType fonts installed, but the default fonts are *
96 * comparatively limited. *
97 ******************************************************************************
99 * Petr Mikulik, Jan 1999: terminal entries for PM3D functionality
100 * Ethan Merritt, May 2001: modified gd/gif driver to produce png instead;
101 * added support for line width and TrueType fonts
111 TERM_PUBLIC void PNG_options __PROTO((void));
112 TERM_PUBLIC void PNG_init __PROTO((void));
113 TERM_PUBLIC void PNG_graphics __PROTO((void));
114 TERM_PUBLIC void PNG_text __PROTO((void));
115 TERM_PUBLIC void PNG_linetype __PROTO((int linetype));
116 TERM_PUBLIC void PNG_linewidth __PROTO((double linewidth));
117 TERM_PUBLIC void PNG_move __PROTO((unsigned int x, unsigned int y));
118 TERM_PUBLIC void PNG_vector __PROTO((unsigned int x, unsigned int y));
119 TERM_PUBLIC void PNG_put_text __PROTO((unsigned int x, unsigned int y, const char str[]));
120 TERM_PUBLIC int PNG_justify_text __PROTO((enum JUSTIFY mode));
121 TERM_PUBLIC void PNG_point __PROTO((unsigned int x, unsigned int y, int number));
122 TERM_PUBLIC int PNG_text_angle __PROTO((int ang));
123 TERM_PUBLIC void PNG_reset __PROTO((void));
124 TERM_PUBLIC int PNG_set_font __PROTO((const char *fontname));
125 TERM_PUBLIC void PNG_pointsize __PROTO((double ptsize));
126 TERM_PUBLIC void PNG_boxfill(int, unsigned int, unsigned int, unsigned int, unsigned int);
127 TERM_PUBLIC int PNG_make_palette (t_sm_palette *);
128 /* TERM_PUBLIC void PNG_previous_palette (void); */
129 TERM_PUBLIC void PNG_set_color (t_colorspec *);
130 TERM_PUBLIC void PNG_filled_polygon (int, gpiPoint *);
132 TERM_PUBLIC void PNG_image __PROTO((unsigned, unsigned, coordval *, gpiPoint *, t_imagecolor));
135 /* To support "set term png enhanced" */
136 TERM_PUBLIC void ENHGD_put_text __PROTO((unsigned int x, unsigned int y, const char str[]));
137 TERM_PUBLIC void ENHGD_OPEN __PROTO((char * fontname, double fontsize,
138 double base, TBOOLEAN widthflag, TBOOLEAN showflag,
140 TERM_PUBLIC void ENHGD_FLUSH __PROTO((void));
145 #if defined(WIN32) && !defined(NONDLL)
146 /* static font pointers are recommended when using bgd.dll */
147 # ifndef GD_NEED_LOCAL_FONT_POINTERS
148 # define GD_NEED_LOCAL_FONT_POINTERS
152 #ifdef GD_NEED_LOCAL_FONT_POINTERS
153 # include "gdfonts.h"
154 # include "gdfontl.h"
155 # include "gdfontmb.h"
156 # include "gdfontt.h"
157 # include "gdfontg.h"
160 /* This is required for the shared library version of libgd on Windows.
161 Newer versions of libgd (>=2.0.24 ?) already define it. */
162 #ifndef BGD_EXPORT_DATA_PROT
163 # define BGD_EXPORT_DATA_PROT extern
166 /* These intermediate functions are necessary on Windows since
167 the shared version of libgd uses a different calling convention
168 and there is no proper macro defined.
170 #if defined(WIN32) && !defined(NONDLL)
171 static void gp_gdImagePolygon(gdImagePtr, gdPointPtr, int, int);
172 static void gp_gdImageFilledPolygon(gdImagePtr, gdPointPtr, int, int);
174 # define gp_gdImagePolygon gdImagePolygon
175 # define gp_gdImageFilledPolygon gdImageFilledPolygon
178 static void PNG_PointX __PROTO((unsigned int, unsigned int));
179 static void PNG_PointPlus __PROTO((unsigned int, unsigned int));
180 static void PNG_Triangle(unsigned int x, unsigned int y, int direction,
181 void (*draw_func)(gdImagePtr, gdPointPtr, int, int));
182 static void PNG_Diamond(unsigned int x, unsigned int y,
183 void (*draw_func)(gdImagePtr, gdPointPtr, int, int));
185 #ifndef GD_NEED_LOCAL_FONT_POINTERS
186 BGD_EXPORT_DATA_PROT gdFontPtr gdFontSmall; /* 6x12 */
187 BGD_EXPORT_DATA_PROT gdFontPtr gdFontLarge; /* 8x16 */
188 BGD_EXPORT_DATA_PROT gdFontPtr gdFontMediumBold; /* 7x13 */
189 BGD_EXPORT_DATA_PROT gdFontPtr gdFontGiant; /* 9x15 */
190 BGD_EXPORT_DATA_PROT gdFontPtr gdFontTiny; /* 5x8 */
192 static gdFontPtr gdFontSmall; /* 6x12 */
193 static gdFontPtr gdFontLarge; /* 8x16 */
194 static gdFontPtr gdFontMediumBold; /* 7x13 */
195 static gdFontPtr gdFontGiant; /* 9x15 */
196 static gdFontPtr gdFontTiny; /* 5x8 */
199 #define GREG_XMAX 640
200 #define GREG_YMAX 480
202 /* This will be the default font */
203 # define gdfont gdFontMediumBold
204 # define PNG_VCHAR 13
207 #define PNG_TICSIZE (GREG_YMAX/100)
209 #define PNG_MAX_COLORS 256
210 #define GOT_NEXT_PROTO
213 #ifndef TERM_PROTO_ONLY
216 static TBOOLEAN PNG_initialized = FALSE; /* Set when terminal first initialized */
224 int color; /* Magic index returned by libgd */
225 int rgb; /* Our guess at the corresponding rgb */
227 int color_table[PNG_MAX_COLORS];
228 int rgb_table[PNG_MAX_COLORS];
230 enum JUSTIFY justify;
234 TBOOLEAN capbutt; /* use capbutt on lines with GD2, 20051205 MWS*/
237 gdFontPtr default_font;
238 char * default_ttffont;
241 /* Variables for animated gif support: */
242 TBOOLEAN animate; /* Only gif supports animation */
243 int loop_count; /* Number of times to repeat sequence */
244 int frame_count; /* Number of frames in animation */
245 int frame_delay; /* Time between frames in .01 seconds */
246 TBOOLEAN frame_optimization;
247 gdImagePtr previous_image; /* Needed to encode animation as a series of deltas */
250 #define PNG_USE_TRANSPARENT 1
251 #define PNG_USE_INTERLACE 2
252 #define PNG_USE_CROP 4
255 PNG_TRANSPARENT, PNG_NOTRANSPARENT,
256 PNG_INTERLACE, PNG_NOINTERLACE,
257 PNG_CROP, PNG_NOCROP,
259 PNG_TINY, PNG_SMALL, PNG_MEDIUM, PNG_LARGE, PNG_GIANT,
262 PNG_ENHANCED, PNG_NOENHANCED,
263 PNG_TRUECOLOR, PNG_NOTRUECOLOR,
264 PNG_LINEWIDTH, PNG_BUTT, PNG_ROUNDED,
265 GIF_ANIMATE, GIF_DELAY, GIF_LOOP, GIF_NOOPT, GIF_OPT,
269 /* Only needed for dubious backwards compatibility with 'set size'
270 * in pre-4.0 versions that didn't support 'set term size'
272 static TBOOLEAN PNG_explicit_size = FALSE;
278 #define Y(y) (png_state.height - (y))
280 static int PNG_XMAX = GREG_XMAX;
281 static int PNG_YMAX = GREG_YMAX;
282 static const int PNG_POINT_SCALE = 3;
283 static int PNG_ps = 3;
285 static struct gen_table PNG_opts[] =
287 { "trans$parent", PNG_TRANSPARENT },
288 { "notran$sparent", PNG_NOTRANSPARENT },
289 { "inter$lace", PNG_INTERLACE },
290 { "nointer$lace", PNG_NOINTERLACE },
291 { "crop", PNG_CROP },
292 { "nocrop", PNG_NOCROP },
293 { "ti$ny", PNG_TINY },
294 { "s$mall", PNG_SMALL },
295 { "m$edium", PNG_MEDIUM },
296 { "l$arge", PNG_LARGE },
297 { "g$iant", PNG_GIANT },
298 { "fo$nt", PNG_FONT },
299 { "si$ze", PNG_SIZE },
300 { "enh$anced", PNG_ENHANCED },
301 { "noenh$anced", PNG_NOENHANCED },
302 { "true$color", PNG_TRUECOLOR },
303 { "notrue$color", PNG_NOTRUECOLOR },
304 { "linew$idth", PNG_LINEWIDTH },
305 { "anim$ate", GIF_ANIMATE }, /* gif animation options */
306 { "delay", GIF_DELAY },
307 { "loop", GIF_LOOP },
308 { "noopt$imize", GIF_NOOPT },
309 { "opt$imize", GIF_OPT }, /* end of gif animation options */
310 { "lw", PNG_LINEWIDTH },
312 { "round$ed", PNG_ROUNDED},
317 #define MAXLINEWIDTH 12
318 static double PNG_linewidth_factor = 1.0;
320 /* EAM - gdImage structure to hold brushes for linewidth */
321 /* We only use brushes 2 through MAXLINEWIDTH */
324 unsigned int last_rgb;
329 static PNG_BRUSH PNG_brush[MAXLINEWIDTH+1];
333 unsigned int last_rgb;
337 static PNG_FILL_TILE PNG_fill_tile = { (gdImagePtr)0, 0, 0 };
339 /* To be used with libgd 2.0.34 to request Symbol encoding */
340 #ifdef gdFTEX_Adobe_Custom
341 static gdFTStringExtra PNG_FONT_INFO = {0,0,0,0,0,NULL,NULL};
344 #if defined(WIN32) && !defined(NONDLL)
346 gp_gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
348 gdImagePolygon(im, p, n, c);
352 gp_gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
354 gdImageFilledPolygon(im, p, n, c);
359 /* Common code to crop the image around its bounding box, just before writing
365 if (png_state.flags & PNG_USE_CROP) {
366 int x, y, x1, y1, x2, y2, flag;
367 int bg = png_state.color_table[0]; /* index of the background color */
369 for (flag=0, x1=0; x1 < gdImageSX(png_state.image)-1; x1++) {
370 for (y=0; y < gdImageSY(png_state.image); y++)
371 if (gdImageGetPixel(png_state.image, x1, y) != bg) { flag = 1; break; }
374 for (flag=0, x2=gdImageSX(png_state.image)-1; x2 >= x1; x2--) {
375 for (y=0; y < gdImageSY(png_state.image); y++)
376 if (gdImageGetPixel(png_state.image, x2, y) != bg) { flag = 1; break; }
379 for (flag=0, y1=0; y1 < gdImageSY(png_state.image)-1; y1++) {
380 for (x=x1; x <= x2; x++)
381 if (gdImageGetPixel(png_state.image, x, y1) != bg) { flag = 1; break; };
384 for (flag=0, y2=gdImageSY(png_state.image)-1; y2 >= y1; y2--) {
385 for (x=x1; x <= x2; x++)
386 if (gdImageGetPixel(png_state.image, x, y2) != bg) { flag = 1; break; };
389 x = x2 - x1 + 1; /* width */
390 y = y2 - y1 + 1; /* height */
392 if (png_state.TrueColor)
393 im_crop = gdImageCreateTrueColor(x,y);
395 im_crop = gdImageCreate(x,y);
397 int_warn(NO_CARET,"libgd: failed to create cropped image structure");
400 bg = gdImageColorAllocateAlpha(im_crop,255,255,255,127);
402 im_crop = gdImageCreate(x,y);
405 gdImagePaletteCopy(im_crop, png_state.image);
406 if (png_state.flags & PNG_USE_TRANSPARENT) {
407 gdImageColorTransparent(im_crop, bg);
408 /* WARNING: This is a work-around for strangeness in libgd, */
409 /* which doesn't copy transparent pixels in TrueColor images. */
410 if (png_state.TrueColor)
411 gdImageColorTransparent(png_state.image, -1);
413 gdImageColorTransparent(im_crop, -1);
415 gdImageCopy(im_crop, png_state.image, 0, 0, x1, y1, x, y);
416 gdImageDestroy(png_state.image);
417 png_state.image = im_crop;
422 static int PNG_FillSolid __PROTO((int fillpar));
423 static int PNG_FillPattern __PROTO((int fillpar));
426 PNG_FillSolid(int fillpar)
428 int red = (png_state.rgb >> 16) & 0xff;
429 int green = (png_state.rgb >> 8) & 0xff;
430 int blue = png_state.rgb & 0xff;
432 double fact = (double)(100 - fillpar) * 0.01;
436 if (fact <= 0 || fact >= 1.0)
437 return png_state.color;
439 red += (0xff - red) * fact;
440 green += (0xff - green) * fact;
441 blue += (0xff - blue) * fact;
443 color = gdImageColorExact(png_state.image, red, green, blue);
445 color = gdImageColorAllocate(png_state.image, red, green, blue);
448 color = gdImageColorClosest(png_state.image, red, green, blue);
455 PNG_FillPattern(int fillpar)
457 int rgb = png_state.rgb;
460 if (!PNG_fill_tile.im || rgb != PNG_fill_tile.last_rgb || PNG_fill_tile.fillpar != fillpar) {
462 int foreground, background;
464 if (PNG_fill_tile.im) {
465 gdImageDestroy(PNG_fill_tile.im);
466 PNG_fill_tile.im = (gdImagePtr)0;
469 /* save new values */
470 PNG_fill_tile.fillpar = fillpar;
471 PNG_fill_tile.last_rgb = rgb;
473 /* create new tile */
474 PNG_fill_tile.im = gdImageCreate(8, 8);
475 if (!PNG_fill_tile.im)
476 int_error(NO_CARET,"libgd: failed to create pattern-fill tile");
479 background = gdImageColorAllocate(PNG_fill_tile.im, 255, 255, 255);
480 /* gdImageColorTransparent(PNG_fill_tile.im, background); */
481 gdImageFilledRectangle(PNG_fill_tile.im, 0, 0, 7, 7, background);
484 foreground = gdImageColorAllocate(PNG_fill_tile.im,
485 (rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff);
488 case 0: /* no fill */
491 case 1: /* cross-hatch */
492 gdImageLine(PNG_fill_tile.im, 0, 0, 7, 7, foreground);
493 gdImageLine(PNG_fill_tile.im, 0, 6, 6, 0, foreground);
495 case 2: /* double cross-hatch */
496 gdImageLine(PNG_fill_tile.im, 0, 0, 7, 7, foreground);
497 gdImageLine(PNG_fill_tile.im, 0, 6, 6, 0, foreground);
498 gdImageLine(PNG_fill_tile.im, 0, 2, 2, 0, foreground);
499 gdImageLine(PNG_fill_tile.im, 7, 3, 3, 7, foreground);
500 gdImageLine(PNG_fill_tile.im, 4, 0, 7, 3, foreground);
501 gdImageLine(PNG_fill_tile.im, 0, 4, 3, 7, foreground);
504 gdImageFilledRectangle(PNG_fill_tile.im, 0, 0, 7, 7, foreground);
507 gdImageLine(PNG_fill_tile.im, 0, 0, 7, 7, foreground);
510 gdImageLine(PNG_fill_tile.im, 0, 7, 7, 0, foreground);
513 gdImageLine(PNG_fill_tile.im, 0, 0, 3, 7, foreground);
514 gdImageLine(PNG_fill_tile.im, 4, 0, 7, 7, foreground);
517 gdImageLine(PNG_fill_tile.im, 0, 7, 3, 0, foreground);
518 gdImageLine(PNG_fill_tile.im, 4, 7, 7, 0, foreground);
521 gdImageLine(PNG_fill_tile.im, 0, 0, 7, 3, foreground);
522 gdImageLine(PNG_fill_tile.im, 0, 4, 7, 7, foreground);
525 gdImageLine(PNG_fill_tile.im, 0, 3, 7, 0, foreground);
526 gdImageLine(PNG_fill_tile.im, 0, 7, 7, 4, foreground);
531 gdImageSetTile(png_state.image, PNG_fill_tile.im);
536 PNG_PointX(unsigned int x, unsigned int y)
538 gdImageLine(png_state.image, x - PNG_ps, y - PNG_ps,
539 x + PNG_ps, y + PNG_ps, png_state.color);
540 gdImageLine(png_state.image, x + PNG_ps, y - PNG_ps,
541 x - PNG_ps, y + PNG_ps, png_state.color);
545 PNG_PointPlus(unsigned int x, unsigned int y)
547 gdImageLine(png_state.image, x - PNG_ps, y,
548 x + PNG_ps, y, png_state.color);
549 gdImageLine(png_state.image, x, y - PNG_ps,
550 x, y + PNG_ps, png_state.color);
555 unsigned int x, unsigned int y,
557 void (*draw_func)(gdImagePtr, gdPointPtr, int, int))
559 int delta = (int)((1.33 * (double)PNG_ps) + 0.5);
560 int delta_ = (int)((0.67 * (double)PNG_ps) + 0.5);
564 points[0].y = y - direction * delta;
565 points[1].x = x - delta;
566 points[1].y = y + direction * delta_;
567 points[2].x = x + delta;
568 points[2].y = y + direction * delta_;
569 points[3].x = points[0].x;
570 points[3].y = points[0].y;
571 draw_func(png_state.image, points, 4, png_state.color);
576 unsigned int x, unsigned int y,
577 void (*draw_func)(gdImagePtr, gdPointPtr, int, int))
581 points[0].y = y - PNG_ps;
582 points[1].x = x + PNG_ps;
585 points[2].y = y + PNG_ps;
586 points[3].x = x - PNG_ps;
588 points[4].x = points[0].x;
589 points[4].y = points[0].y;
590 draw_func(png_state.image, points, 5, png_state.color);
594 * _options() Called when terminal type is selected.
595 * This procedure should parse options on the command line. A list of the
596 * currently selected options should be stored in term_options[] in a form
597 * suitable for use with the set term command. term_options[] is used by
598 * the save command. Use options_null() if no options are available.
607 TBOOLEAN new_colors = FALSE;
608 TBOOLEAN gif_anim_option = FALSE; /* set to TRUE if an animated gif option given */
610 if (!PNG_initialized) {
611 PNG_initialized = TRUE;
612 term_options[0] = '\0';
613 term->h_char = PNG_HCHAR; /* Default to medium font */
614 png_state.default_font = gdfont;
615 png_state.n_colors = 0;
617 png_state.ttffont = NULL;
618 png_state.default_ttffont = NULL;
619 png_state.default_ttfsize = 0;
620 png_state.justify = CENTRE;
621 png_state.TrueColor = FALSE;
622 PNG_linewidth_factor = 1.0;
623 png_state.capbutt = FALSE; /* to preserve previous default behavior */
624 #ifdef GD_NEED_LOCAL_FONT_POINTERS
625 gdFontSmall = gdFontGetSmall();
626 gdFontLarge = gdFontGetLarge();
627 gdFontMediumBold = gdFontGetMediumBold();
628 gdFontGiant = gdFontGetGiant();
629 gdFontTiny = gdFontGetTiny();
632 /* FIXME EAM - these should never happen! */
633 if (!png_state.default_font) {
634 fprintf(stderr,"gd.trm: caught initialization error\n");
635 png_state.default_font = gdfont;
639 /* Annoying hack to handle the case of 'set termoption' after */
640 /* we are already in animation mode. */
642 FPRINTF((stderr,"gif: Maintaining animation state\n"));
644 /* Otherwise reset animation parameters */
645 if (png_state.previous_image)
646 gdImageDestroy(png_state.previous_image);
647 png_state.animate = FALSE;
648 png_state.previous_image = NULL;
649 png_state.frame_optimization = FALSE;
650 png_state.loop_count = 0;
651 /* And default font size */
652 term->h_char = PNG_HCHAR;
653 png_state.default_ttfsize = 0;
656 while (!END_OF_COMMAND) {
657 switch(lookup_table(&PNG_opts[0],c_token)) {
658 case PNG_TRANSPARENT:
659 png_state.flags |= PNG_USE_TRANSPARENT;
662 case PNG_NOTRANSPARENT:
663 png_state.flags &= ~PNG_USE_TRANSPARENT;
667 png_state.flags |= PNG_USE_INTERLACE;
670 case PNG_NOINTERLACE:
671 png_state.flags &= ~PNG_USE_INTERLACE;
675 png_state.flags |= PNG_USE_CROP;
679 png_state.flags &= ~PNG_USE_CROP;
684 # define UNSET_TTF_FONT \
685 free(png_state.ttffont); \
686 png_state.ttffont = NULL; \
687 png_state.default_ttfsize = 2 * term->h_char - 2;
689 # define UNSET_TTF_FONT \
690 ; /* nothing to do */
692 png_state.default_font=gdFontTiny;
693 term->v_char = png_state.default_font->h;
694 term->h_char = png_state.default_font->w;
699 png_state.default_font = gdFontSmall;
700 term->v_char = png_state.default_font->h;
701 term->h_char = png_state.default_font->w;
706 png_state.default_font = gdFontMediumBold;
707 term->v_char = png_state.default_font->h;
708 term->h_char = png_state.default_font->w;
713 png_state.default_font = gdFontLarge;
714 term->v_char = png_state.default_font->h;
715 term->h_char = png_state.default_font->w;
720 png_state.default_font=gdFontGiant;
721 term->v_char = png_state.default_font->h;
722 term->h_char = png_state.default_font->w;
729 if (END_OF_COMMAND) {
730 free(png_state.ttffont);
731 png_state.ttffont = NULL;
732 png_state.default_ttfsize = 0;
737 if (isstringvalue(c_token)) {
738 char *s = try_to_get_string();
739 char *comma = strrchr(s,',');
741 if (comma && (1 == sscanf(comma+1,"%lf",&fontsize))) {
742 png_state.default_ttfsize = (int)(fontsize+0.5);
743 png_state.ttfsize = png_state.default_ttfsize;
747 free(png_state.ttffont);
748 png_state.ttffont = s;
753 free(png_state.ttffont);
754 png_state.ttffont = gp_alloc(token_len(c_token)+1,"new font");
755 copy_str(png_state.ttffont, c_token, token_len(c_token)+1);
758 free(png_state.default_ttffont);
759 png_state.default_ttffont = gp_strdup(png_state.ttffont);
760 err = gdImageStringFT(NULL, &brect[0], 0,
761 png_state.ttffont, (double)png_state.ttfsize,
765 "%s when opening font %s, trying default\n",
766 err, png_state.ttffont);
767 free(png_state.ttffont);
768 free(png_state.default_ttffont);
769 png_state.ttffont = NULL;
770 png_state.default_ttffont = NULL;
775 fprintf(stderr,"No TTF font support, using internal non-scalable font\n");
780 if (END_OF_COMMAND) {
781 PNG_XMAX = GREG_XMAX;
782 PNG_YMAX = GREG_YMAX;
783 PNG_explicit_size = FALSE;
785 PNG_XMAX = real(const_express(&s));
786 if (equals(c_token, ",")) {
788 PNG_YMAX = real(const_express(&s));
791 PNG_XMAX = GREG_XMAX;
793 PNG_YMAX = GREG_YMAX;
794 PNG_explicit_size = TRUE;
796 term->ymax = PNG_YMAX;
797 term->xmax = PNG_XMAX;
798 /* EAM Apr 2003 - same tic size on both x and y axes */
799 term->v_tic = (PNG_XMAX < PNG_YMAX) ? PNG_XMAX/100 : PNG_YMAX/100;
802 term->h_tic = term->v_tic;
805 term->flags |= TERM_ENHANCED_TEXT;
806 term->put_text = ENHGD_put_text;
810 term->flags &= ~TERM_ENHANCED_TEXT;
811 term->put_text = PNG_put_text;
815 png_state.TrueColor = TRUE;
818 case PNG_NOTRUECOLOR:
819 png_state.TrueColor = FALSE;
824 PNG_linewidth_factor = real(const_express(&s));
825 if (PNG_linewidth_factor < 0)
826 PNG_linewidth_factor = 1.0;
829 /* parse gif animation options */
831 if (strncmp("gif",term->name,3))
832 int_error(c_token,"Only the gif terminal supports animation");
834 png_state.animate = TRUE;
835 png_state.frame_count = 0;
836 png_state.frame_delay = 10;
837 png_state.frame_optimization = FALSE;
841 if (strncmp("gif",term->name,3))
842 int_error(c_token,"Only the gif terminal supports animation");
844 png_state.frame_delay = (int)real(const_express(&s));
845 if (png_state.frame_delay <= 0)
846 png_state.frame_delay = 10;
850 if (strncmp("gif",term->name,3))
851 int_error(c_token,"Only the gif terminal supports animation");
853 png_state.loop_count = (int)real(const_express(&s));
857 if (strncmp("gif",term->name,3))
858 int_error(c_token,"Only the gif terminal supports animation");
860 png_state.frame_optimization = FALSE;
864 if (strncmp("gif",term->name,3))
865 int_error(c_token,"Only the gif terminal supports animation");
867 png_state.frame_optimization = TRUE;
872 png_state.capbutt = TRUE;
877 png_state.capbutt = FALSE;
884 string = gp_input_line + token[c_token].start_index;
887 /* Check for explicit TTF font size */
888 if (sscanf(string, "%d", &i) == 1) {
889 if (i > 0 && i < 999)
890 png_state.default_ttfsize = i;
892 int_warn(c_token,"illegal font size");
898 if (sscanf(string, "x%lx", &color) != 1) {
899 int_error(c_token, "invalid color spec, must be xRRGGBB");
900 } else if (png_state.n_colors == PNG_MAX_COLORS && new_colors) {
901 int_warn(c_token, "too many colors, ignoring");
906 png_state.n_colors = 0;
908 png_state.rgb_table[png_state.n_colors++] = color;
915 #ifndef GIF_ANIMATION /* animated gifs not supported by the current GD library */
916 if (gif_anim_option) {
917 png_state.animate = FALSE;
918 int_warn(NO_CARET, "gif animation options ignored (not compiled into this binary)");
923 /* If no font has been chosen but there is a default, use it */
924 if (!png_state.ttffont) {
925 char *external_default = getenv("GNUPLOT_DEFAULT_GDFONT");
929 if (external_default)
930 png_state.ttffont = gp_strdup(external_default);
931 else /* Might as well try some plausible font; it's no worse than failing immediately */
932 png_state.ttffont = gp_strdup("arial");
934 free(png_state.default_ttffont);
935 png_state.default_ttffont = gp_strdup(png_state.ttffont);
936 png_state.default_ttfsize = 2 * term->h_char - 2;
937 err = gdImageStringFT(NULL, &brect[0], 0,
938 png_state.ttffont, (double)png_state.default_ttfsize,
941 fprintf(stderr,"%s when opening font \"%s\", using internal non-scalable font\n",
942 err, png_state.ttffont);
943 free(png_state.ttffont);
944 free(png_state.default_ttffont);
945 png_state.ttffont = NULL;
946 png_state.default_ttffont = NULL;
950 /* If no explicit TTF font size found, generate default */
951 if (png_state.default_ttfsize == 0)
952 png_state.default_ttfsize = 2 * term->h_char - 2;
953 png_state.ttfsize = png_state.default_ttfsize;
955 /* Find approximate character width of selected TTF font */
956 /* This is needed in order to set appropriate border width */
957 if (png_state.default_ttffont) {
960 err = gdImageStringFT(NULL, &brect[0], 0,
961 png_state.default_ttffont, (double)png_state.default_ttfsize,
962 0.0, 0, 0, "f00000000g");
964 term->h_char = .11 * (float)(brect[2] - brect[0]) + 0.5;
965 term->v_char = 1.1 * (float)(brect[1] - brect[7]) + 0.5;
970 /* This code is shared by png, gif, and jpeg terminal types */
971 if (!strcmp(term->name,"jpeg"))
972 png_state.flags &= ~PNG_USE_TRANSPARENT;
974 /* now generate options string */
976 if (png_state.flags & PNG_USE_TRANSPARENT) {
977 strcat(term_options, "transparent ");
979 if (png_state.flags & PNG_USE_INTERLACE) {
980 strcat(term_options, "interlace ");
982 /* JPEG files are always 24-bit color */
983 if (strcmp(term->name, "jpeg") == 0)
984 png_state.TrueColor = TRUE;
985 else if (png_state.TrueColor) {
986 strcat(term_options, "truecolor ");
988 if (!(png_state.flags & PNG_USE_CROP)) {
989 strcat(term_options, "no");
991 strcat(term_options, "crop ");
993 if (term->flags & TERM_ENHANCED_TEXT) {
994 strcat(term_options, "enhanced ");
997 if (png_state.ttffont) {
998 sprintf(term_options + strlen(term_options),
999 "font %s %d ", png_state.ttffont, png_state.ttfsize);
1000 } else switch (term->h_char) {
1002 strcat(term_options,"tiny ");
1005 strcat(term_options, "small ");
1009 strcat(term_options, "medium ");
1012 strcat(term_options, "large ");
1015 strcat(term_options,"giant ");
1019 if (PNG_linewidth_factor != 1.0)
1020 sprintf(term_options + strlen(term_options),
1021 "linewidth %3.1f ", PNG_linewidth_factor);
1023 if (png_state.capbutt) {
1024 sprintf(term_options + strlen(term_options),
1028 if (png_state.animate) {
1029 sprintf(term_options + strlen(term_options),
1030 "animate delay %d loop %d %soptimize ",
1031 png_state.frame_delay, png_state.loop_count,
1032 png_state.frame_optimization ? "" : "no");
1035 if (PNG_explicit_size)
1036 sprintf(term_options + strlen(term_options),
1037 "size %d,%d ", PNG_XMAX, PNG_YMAX);
1039 for (i = 0; strlen(term_options) + 9 < MAX_LINE_LEN &&
1040 i < png_state.n_colors; i++) {
1041 sprintf(term_options + strlen(term_options),
1042 "x%06x ", png_state.rgb_table[i]);
1048 * _init() Called once, when the device is first selected. This procedure
1049 * should set up things that only need to be set once, like handshaking and
1050 * character sets etc...
1057 png_state.linetype = 0;
1058 png_state.linewidth = 1;
1059 /* EAM - pre-define brushes to implement linewidth */
1060 for (i=2; i<=MAXLINEWIDTH; i++) {
1061 if (!((PNG_brush[i].im = gdImageCreate(i,i))))
1062 int_error(NO_CARET,"libgd: failed to create brush structure");
1063 PNG_brush[i].bgnd = gdImageColorAllocate( PNG_brush[i].im, 255, 255, 255 );
1064 gdImageFill( PNG_brush[i].im, 0, 0, PNG_brush[i].bgnd );
1065 gdImageColorTransparent( PNG_brush[i].im, PNG_brush[i].bgnd );
1066 PNG_brush[i].fgnd = gdImageColorAllocate( PNG_brush[i].im, 0, 0, 0 );
1067 PNG_brush[i].last_rgb = -99; /* invalid index will force update on first use */
1069 /* EAM - quick and dirty is to fill the entire brush (square nib). */
1070 /* might be better to approximate a circular nib by selectively */
1071 /* coloring the individual pixels of the brush image. */
1072 for (i=2; i<=MAXLINEWIDTH; i++) {
1073 gdImageFilledRectangle( PNG_brush[i].im, 0, 0, i-1, i-1, PNG_brush[i].fgnd );
1079 * _reset() Called when gnuplot is exited, the output device changed or
1080 * the terminal type changed. This procedure should reset the device,
1081 * possibly flushing a buffer somewhere or generating a form feed.
1087 /* EAM - Clean up the brushes used for linewidth */
1088 for (i=2; i<=MAXLINEWIDTH; i++) {
1089 if (PNG_brush[i].im)
1090 gdImageDestroy(PNG_brush[i].im);
1091 PNG_brush[i].im = 0;
1093 if (PNG_fill_tile.im) {
1094 gdImageDestroy(PNG_fill_tile.im);
1095 PNG_fill_tile.im = (gdImagePtr)0;
1097 #ifdef GIF_ANIMATION
1098 if (png_state.animate) {
1099 gdImageGifAnimEnd(gpoutfile);
1100 png_state.frame_count = 0;
1101 png_state.animate = FALSE;
1102 fprintf(stderr,"End of animation sequence\n");
1108 /* use #if 1 that's just for debugging */
1110 PNG_show_current_palette()
1114 fprintf(stderr, "*****\n SHOW THE PALETTE! total=%i\n",
1115 gdImageColorsTotal(png_state.image));
1116 for (i=0; i < gdImageColorsTotal(png_state.image); i++) {
1117 /* Use access macros to learn colors. */
1118 fprintf(stderr, "%i\tr=%d\t g=%d\tb=%d\n",
1120 gdImageRed(png_state.image,i),
1121 gdImageGreen(png_state.image,i),
1122 gdImageBlue(png_state.image,i));
1128 How this works: Gray interval [0;1] will be mapped to interval
1129 [0;sm_palette.colors-1] those r,g,b components are mapped by the array
1130 below palette.offset equals 0 since png_smooth_color[0..colors] are
1133 static int png_smooth_color[gdMaxColors];
1137 * This is only needed in order to maintain png_state_rgb for pattern-fill,
1138 * and only for palette-based coloring. It doesn't seem worth the space or effort.
1141 static int png_smooth_rgb[gdMaxColors];
1144 /* TODO: how to recover from a multiplot with two colour pm3d maps?
1145 They must use the same palette! Or palette size must be
1146 restricted to certain number of colours---a new user's option
1149 TERM_PUBLIC int PNG_make_palette (t_sm_palette *palette)
1152 if (palette == NULL) {
1153 /* If the output format is TrueColor there in no color limit */
1154 if (png_state.TrueColor)
1157 /* return maximal number of colours in a PNG palette */
1158 i = gdMaxColors /*256*/ - gdImageColorsTotal(png_state.image);
1159 /* the latter is the number of currently allocated colours. We want
1160 to allocate the rest */
1161 /*BACK PLEASE fprintf(stderr,"colors in PNG palette=%i\n",(int)gdMaxColors); */
1163 i = (sm_palette.colors <= 0) ? -1 : sm_palette.colors;
1164 /* (no more colorus) : (previous palette (obviously multiplot mode)) */
1166 if (i > 0) fprintf(stderr,"reusing it again\n");
1171 if (0 == gdMaxColors /*256*/ - gdImageColorsTotal(png_state.image))
1172 return 0; /* reuse previous palette (without warning) */
1173 for (i = 0; i < sm_palette.colors; i++) {
1174 png_smooth_color[i] = gdImageColorAllocate(png_state.image,
1175 (int)( palette->color[i].r * 255 + 0.5 ), /* r,g,b values for png */
1176 (int)( palette->color[i].g * 255 + 0.5 ), /* terminal are [0;255] */
1177 (int)( palette->color[i].b * 255 + 0.5 ) );
1179 png_smooth_rgb[i] = (((int)(palette->color[i].r * 255.) & 0xff) << 16)
1180 + (((int)(palette->color[i].g * 255.) & 0xff) << 8)
1181 + ((int)(palette->color[i].b * 255.) & 0xff);
1183 if (png_smooth_color[i] < 0) { /* this should never happen! take away? */
1184 FPRINTF((stderr,"png_smooth_color[i]<0 cannot happen"));
1188 fprintf(stderr,"ALLOCATED: i=%i\t=> pal_index=%i\tr=%g g=%g b=%g\n",
1189 i, png_smooth_color[i],
1190 palette->color[i].r, palette->color[i].g, palette->color[i].b );
1198 void PNG_set_color (t_colorspec *colorspec)
1200 double gray = colorspec->value;
1202 if (colorspec->type == TC_LT) {
1203 int savetype = png_state.linetype;
1204 PNG_linetype(colorspec->lt);
1205 /* Harmless now; will be needed if we ever support dot/dash */
1206 png_state.linetype = savetype;
1209 if (colorspec->type == TC_RGB) {
1210 png_state.rgb = colorspec->lt;
1211 png_state.color = gdImageColorResolve(png_state.image,
1212 colorspec->lt >> 16, (colorspec->lt >> 8) & 0xff, colorspec->lt & 0xff);
1215 if (colorspec->type != TC_FRAC)
1218 if (png_state.TrueColor) {
1220 rgb255maxcolors_from_gray(gray, &color);
1221 png_state.color = gdImageColorResolve(png_state.image,
1222 (int)color.r, (int)color.g, (int)color.b);
1223 png_state.rgb = (color.r << 16) + (color.g << 8) +color.b;
1226 int png_color = (gray <= 0) ? 0 : (int)(gray * sm_palette.colors);
1227 if (png_color >= sm_palette.colors)
1228 png_color = sm_palette.colors - 1;
1229 /* map [0;1] to interval [0;png_smooth_colors-1] */
1230 png_state.color = png_smooth_color[ png_color ];
1232 png_state.rgb = png_smooth_rgb[ png_color ];
1238 void PNG_filled_polygon(int points, gpiPoint *corners)
1241 int fillpar = corners->style >> 4;
1242 int color = png_state.color;
1244 /* since gpiPoint carries more than just x and y if
1245 * we have EXTENDED_COLOR_SPECS defined, we need to
1246 * copy it to the gdPointPtr struct; make it static
1247 * so that is faster (joze) */
1248 static gdPointPtr gd_corners = (gdPointPtr) 0;
1249 static unsigned int size = 0;
1250 if (points > size) {
1252 gd_corners = gp_realloc(gd_corners, sizeof(gdPoint) * size,
1253 "PNG_filled_polygon->gd_corners");
1255 for (i = 0; i < points; i++) {
1256 gd_corners[i].x = corners[i].x;
1257 gd_corners[i].y = Y(corners[i].y);
1260 switch (corners->style & 0xf) {
1261 case FS_EMPTY: /* fill with background color */
1262 color = png_state.color_table[0];
1264 case FS_SOLID: /* solid fill */
1265 color = PNG_FillSolid(fillpar);
1267 case FS_PATTERN: /* pattern fill */
1268 color = PNG_FillPattern(fillpar);
1271 color = png_state.color;
1275 gdImageFilledPolygon(png_state.image, gd_corners, points, color);
1277 /* easy, since gdPointPtr is the same as (gdiPoint*) */
1278 /* if someone someday needs this routine to be NON-DESTRUCTIVE, then change
1279 the following line to #if 1 */
1281 for (i = 0; i < points; i++)
1282 corners[i].y = Y(corners[i].y);
1287 * This function is used for filledboxes
1288 * style parameter is some garbled hash combining fillstyle and filldensity
1293 unsigned int x, unsigned int y,
1294 unsigned int width, unsigned int height)
1296 unsigned int x1, y1, x2, y2;
1301 * - pattern : 0 - 100
1303 int fillpar = style >> 4;
1308 case FS_EMPTY: /* fill with background color */
1309 color = png_state.color_table[0];
1311 case FS_SOLID: /* solid fill */
1312 color = PNG_FillSolid(fillpar);
1314 case FS_PATTERN: /* pattern fill */
1315 color = PNG_FillPattern(fillpar);
1318 /* should never happen */
1319 color = png_state.color;
1326 y1 = y2 - height + 1;
1327 gdImageFilledRectangle(png_state.image, x1, y1, x2, y2, color);
1331 * _graphics() Called just before a plot is going to be displayed. This
1332 * procedure should set the device into graphics mode. Devices which can't
1333 * be used as terminals (like plotters) will probably be in graphics mode
1334 * always and therefore won't need this.
1344 #ifdef BACKWARDS_COMPATIBLE
1345 /* We are deprecating the use of 'set size' to change the actual */
1346 /* canvas size, in this case the size of the output file in pixels. */
1347 if (!PNG_explicit_size) {
1354 /* TrueColor images default to a black background; load white instead */
1355 if (png_state.TrueColor) {
1356 png_state.image = gdImageCreateTrueColor(
1357 (int) (xscale * PNG_XMAX), (int) (yscale * PNG_YMAX));
1358 if (!png_state.image)
1359 int_error(NO_CARET,"libgd: failed to create output image structure");
1360 rgb = gdImageColorAllocate(png_state.image, 255, 255, 255);
1361 gdImageFill(png_state.image, 1, 1, rgb);
1364 png_state.image = gdImageCreate(
1365 (int) (xscale * PNG_XMAX), (int) (yscale * PNG_YMAX));
1366 if (!png_state.image)
1367 int_error(NO_CARET,"libgd: failed to create output image structure");
1369 png_state.height = (yscale * PNG_YMAX) - 1;
1370 png_state.charw = term->h_char; /* png_state.font->w; */
1371 png_state.charh = term->v_char; /* png_state.font->h; */
1372 png_state.font = png_state.default_font;
1373 png_state.color = 0;
1374 for (i = png_state.n_colors; i < WEB_N_COLORS; i++)
1375 png_state.rgb_table[i] =
1376 (web_color_rgbs[i].r << 16) |
1377 (web_color_rgbs[i].g << 8) |
1378 web_color_rgbs[i].b;
1379 if (png_state.n_colors < WEB_N_COLORS)
1380 png_state.n_colors = WEB_N_COLORS;
1381 for (i = 0; i < png_state.n_colors; i++) {
1382 rgb = png_state.rgb_table[i];
1383 png_state.color_table[i] =
1384 gdImageColorAllocate(png_state.image, (rgb >> 16) & 0xff,
1385 (rgb >> 8) & 0xff, rgb & 0xff);
1387 if (png_state.flags & PNG_USE_TRANSPARENT)
1388 gdImageColorTransparent(png_state.image,
1389 png_state.color_table[0]);
1391 gdImageColorTransparent(png_state.image, -1);
1396 * _text() Called immediately after a plot is displayed. This procedure
1397 * should set the device back into text mode if it is also a terminal, so
1398 * that commands can be seen as they're typed. Again, this will probably
1399 * do nothing if the device can't be used as a terminal.
1405 if (png_state.flags & PNG_USE_INTERLACE)
1406 gdImageInterlace(png_state.image, 1);
1407 gdImagePng(png_state.image, gpoutfile);
1408 gdImageDestroy(png_state.image);
1411 /* _move(x,y) Called at the start of a line. The cursor should move to the
1412 * (x,y) position without drawing.
1415 PNG_move(unsigned int x, unsigned int y)
1421 /* _vector(x,y) Called when a line is to be drawn. This should display a line
1422 * from the last (x,y) position given by _move() or _vector() to this new (x,y)
1426 PNG_vector(unsigned int x, unsigned int y)
1430 if (png_state.linetype == -1) {
1431 int png_linetype_dotted[5];
1432 png_linetype_dotted[0] = png_state.color;
1433 png_linetype_dotted[1] = png_state.color;
1434 png_linetype_dotted[2] = gdTransparent;
1435 png_linetype_dotted[3] = gdTransparent;
1436 png_linetype_dotted[4] = gdTransparent;
1438 gdImageSetStyle(png_state.image, png_linetype_dotted, 5);
1439 gdImageLine(png_state.image, png_state.x, Y(png_state.y),
1442 if (png_state.linewidth == 1) {
1443 #if (GD2_VERS >= 2) && defined(gdAntiAliased)
1444 gdImageSetThickness(png_state.image,1);
1445 gdImageSetAntiAliased(png_state.image, png_state.color);
1446 gdImageLine(png_state.image, png_state.x, Y(png_state.y),
1447 x, Y(y), gdAntiAliased);
1449 gdImageLine(png_state.image, png_state.x, Y(png_state.y),
1450 x, Y(y), png_state.color);
1453 } else if (png_state.capbutt){
1455 gdImageSetThickness(png_state.image,png_state.linewidth);
1456 gdImageLine(png_state.image, png_state.x, Y(png_state.y),
1457 x, Y(y), png_state.color);
1461 /* EAM - Implement linewidth by selecting a pre-defined brush */
1462 /* The tricky bit is re-coloring the brush to the current color */
1463 lw = png_state.linewidth;
1464 if (png_state.color != PNG_brush[lw].last_rgb) {
1465 PNG_brush[lw].fgnd = gdImageColorResolve(PNG_brush[lw].im,
1466 gdImageRed(png_state.image,png_state.color),
1467 gdImageGreen(png_state.image,png_state.color),
1468 gdImageBlue(png_state.image,png_state.color) );
1469 PNG_brush[lw].last_rgb = png_state.color;
1471 gdImageFilledRectangle( PNG_brush[lw].im, 0, 0, lw-1, lw-1, PNG_brush[lw].fgnd );
1472 gdImageSetBrush(png_state.image, PNG_brush[lw].im);
1473 gdImageLine(png_state.image, png_state.x, Y(png_state.y),
1474 x, Y(y), gdBrushed );
1481 /* _linetype(lt) Called to set the line type before text is displayed or
1483 * Negative linetypes are defined in gadgets.h
1484 * lt 0 and upwards are used for plots 0 and upwards.
1485 * If _linetype() is called with lt greater than the available line types,
1486 * it should map it to one of the available line types.
1489 PNG_linetype(int type)
1491 if (type >= (png_state.n_colors - 3))
1492 type %= (png_state.n_colors - 3);
1493 if (type <= LT_BACKGROUND) /* LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED */
1494 type = -3; /* Draw in background color */
1496 png_state.color = png_state.color_table[type + 3];
1497 png_state.rgb = png_state.rgb_table[type + 3];
1498 png_state.linetype = type;
1501 /* Use the "brush" tools in the gd library to control line width.
1502 * Pre-define brushes for linewidths 2, 3, 4, 5, 6 (1 doesn't need a brush!).
1503 * Here we just remember the state.
1506 PNG_linewidth(double linewidth)
1508 png_state.linewidth = (int)(PNG_linewidth_factor * linewidth+0.49);
1509 if (png_state.linewidth > MAXLINEWIDTH) png_state.linewidth = MAXLINEWIDTH;
1510 if (png_state.linewidth < 1) png_state.linewidth = 1;
1513 /* _put_text(x,y,str) Called to display text at the (x,y) position,
1514 * while in graphics mode. The text should be vertically (with respect
1515 * to the text) justified about (x,y). The text is rotated according
1516 * to _text_angle and then horizontally (with respect to the text)
1517 * justified according to _justify_text.
1521 PNG_put_text(unsigned int x, unsigned int y, const char *string)
1523 if (png_state.ttffont) {
1524 int brect[8]; char *err;
1525 /* Draw once with a NULL image to get the bounding rectangle */
1526 /* then draw it again, centered. */
1527 err = gdImageStringFT(NULL, brect, png_state.color,
1528 png_state.ttffont, (double)png_state.ttfsize,
1529 (double)png_state.angle * M_PI_2 / 90. ,
1530 x, Y(y), (char *)string);
1532 fprintf(stderr,"gdImageStringFT: %s while printing string %s with font %s\n",
1533 err,string,png_state.ttffont);
1535 x += sin((double)png_state.angle * M_PI_2/90.) * (double)png_state.charh/4.;
1536 y -= cos((double)png_state.angle * M_PI_2/90.) * (double)png_state.charh/4.;
1537 switch (png_state.justify) {
1539 x -= (brect[2]-brect[0]);
1540 y += (brect[3]-brect[1]);
1543 x -= (brect[2]-brect[0]) / 2.;
1544 y += (brect[3]-brect[1]) / 2.;
1549 err = gdImageStringFT(png_state.image, brect, png_state.color,
1550 png_state.ttffont, (double)png_state.ttfsize,
1551 (double)png_state.angle * M_PI_2 / 90.,
1552 x, Y(y), (char *)string);
1554 fprintf(stderr,"gdImageStringFT: %s while printing string %s with font %s\n",
1555 err,string,png_state.ttffont);
1557 } else if (png_state.angle != 0) {
1558 x -= png_state.charh / 2;
1559 switch (png_state.justify) {
1560 case RIGHT: y -= png_state.charw * strlen(string);
1562 case CENTRE:y -= png_state.charw * strlen(string) / 2;
1567 gdImageStringUp(png_state.image, png_state.font,
1569 (unsigned char *)string, png_state.color);
1571 y += png_state.charh / 2;
1572 switch (png_state.justify) {
1573 case RIGHT: x -= png_state.charw * strlen(string);
1575 case CENTRE:x -= png_state.charw * strlen(string) / 2;
1580 gdImageString(png_state.image, png_state.font,
1582 (unsigned char *)string, png_state.color);
1586 #else /* not HAVE_GD_TTF */
1589 PNG_put_text(unsigned int x, unsigned int y, const char *string)
1591 if (png_state.angle == 0) {
1592 y += png_state.charh / 2;
1593 gdImageString(png_state.image, png_state.font,
1595 (unsigned char *)string, png_state.color);
1597 x -= png_state.charh / 2;
1598 gdImageStringUp(png_state.image, png_state.font,
1600 (unsigned char *)string, png_state.color);
1604 #endif /* HAVE_GD_TTF */
1608 PNG_text_angle(int ang)
1610 while (ang < -180) ang += 360; /* Should not be needed, but reported to */
1611 while (ang > 180) ang -= 360; /* avoid a bug in some libgd versions */
1612 png_state.angle = ang;
1617 PNG_justify_text(enum JUSTIFY mode)
1620 png_state.justify = mode;
1623 return null_justify_text(mode);
1628 PNG_point(unsigned int x, unsigned int y, int number)
1630 int save_color = png_state.color;
1633 gdImageSetPixel(png_state.image, x, Y(y), png_state.color);
1636 /* Use current linewidth to draw the point symbol */
1637 if (png_state.linewidth > 1) {
1638 /* EAM - Implement linewidth by selecting a pre-defined brush */
1639 /* The tricky bit is re-coloring the brush to the current color */
1640 int lw = png_state.linewidth;
1641 if (png_state.color != PNG_brush[lw].last_rgb) {
1642 PNG_brush[lw].fgnd = gdImageColorResolve(PNG_brush[lw].im,
1643 gdImageRed(png_state.image,png_state.color),
1644 gdImageGreen(png_state.image,png_state.color),
1645 gdImageBlue(png_state.image,png_state.color) );
1646 PNG_brush[lw].last_rgb = png_state.color;
1648 gdImageFilledRectangle( PNG_brush[lw].im, 0, 0, lw-1, lw-1, PNG_brush[lw].fgnd );
1649 gdImageSetBrush(png_state.image, PNG_brush[lw].im);
1650 png_state.color = gdBrushed;
1655 switch (number % 13) {
1658 PNG_PointPlus(x, y);
1664 PNG_PointPlus(x, y);
1668 gdImageRectangle(png_state.image, x - PNG_ps, y - PNG_ps,
1669 x + PNG_ps, y + PNG_ps, png_state.color);
1671 case 4: /* box filled */
1672 gdImageFilledRectangle(png_state.image, x - PNG_ps, y - PNG_ps,
1673 x + PNG_ps, y + PNG_ps, png_state.color);
1675 case 5: /* circle */
1676 gdImageArc(png_state.image, x, y, 2 * PNG_ps, 2 * PNG_ps,
1677 0, 360, png_state.color);
1679 case 6: /* circle (disk) filled */
1681 gdImageFilledArc(png_state.image, x, y, 2 * PNG_ps, 2 * PNG_ps,
1682 0, 360, png_state.color, gdArc);
1684 gdImageArc(png_state.image, x, y, 2 * PNG_ps, 2 * PNG_ps,
1685 0, 360, png_state.color);
1686 gdImageFillToBorder(png_state.image, x, y,
1687 png_state.color, png_state.color);
1690 case 7: /* triangle */
1691 PNG_Triangle(x, y, 1, gp_gdImagePolygon);
1693 case 8: /* triangle filled */
1694 PNG_Triangle(x, y, 1, gp_gdImageFilledPolygon);
1696 case 9: /* upside down triangle */
1697 PNG_Triangle(x, y, -1, gp_gdImagePolygon);
1699 case 10: /* upside down triangle filled */
1700 PNG_Triangle(x, y, -1, gp_gdImageFilledPolygon);
1702 case 11: /* diamond */
1703 PNG_Diamond(x, y, gp_gdImagePolygon);
1705 case 12: /* diamond filled */
1706 PNG_Diamond(x, y, gp_gdImageFilledPolygon);
1710 png_state.color = save_color;
1714 PNG_set_font(const char *fontname)
1718 gdFontPtr font = png_state.default_font;
1719 char *name = gp_strdup(fontname);
1721 sep = strcspn(fontname,",");
1722 strncpy(name,fontname,sep);
1724 size = png_state.default_ttfsize;
1725 sscanf (&(fontname[sep+1]),"%d",&size);
1727 if (!strcmp(name,"small"))
1729 else if (!strcmp(name,"medium"))
1730 font = gdFontMediumBold;
1731 else if (!strcmp(name,"large"))
1733 else if (!strcmp(name,"giant"))
1735 else if (!strcmp(name,"tiny"))
1739 free(png_state.ttffont);
1740 png_state.ttffont = gp_strdup(name);
1741 png_state.ttfsize = size;
1743 /* Restore initial default font */
1744 free(png_state.ttffont);
1745 png_state.ttffont = gp_strdup(png_state.default_ttffont);
1746 png_state.ttfsize = png_state.default_ttfsize;
1750 png_state.font = font;
1751 png_state.charw = font->w;
1752 png_state.charh = font->h;
1754 /* EAM 9-Feb-2003 Make new font size visible to higher level routines like write_multiline */
1755 term->h_char = font->w;
1756 term->v_char = font->h;
1758 /* Find approximate character width and height of selected TTF font */
1759 if (png_state.ttffont) {
1762 err = gdImageStringFT(NULL, &brect[0], 0,
1763 png_state.ttffont, (double)png_state.ttfsize,
1764 0.0, 0, 0, "f00000000g");
1766 term->h_char = .11 * (float)(brect[2] - brect[0]) + 0.5;
1767 term->v_char = 1.1 * (float)(brect[1] - brect[7]) + 0.5;
1776 PNG_pointsize(double ptsize)
1780 PNG_ps = (int)(((double)PNG_POINT_SCALE * ptsize) + 0.5);
1784 * Ethan A Merritt November 2003
1785 * - Support for enhanced text mode
1787 * - placement of overprinted characters is not correct;
1788 * the overprinted text (pass 2) should be centered, not left-justified
1790 * - the Symbol font encoding didn't work in libgd until 2.0.21
1791 * - Placement of superscripts and subscripts relies on information
1792 * in the font description that is not always reliable
1793 * - the TTF character encoding for non-keyboard characters does
1794 * not always match the PostScript standard.
1795 * - Spacing of rotated text is incorrect; I believe this is a due
1796 * to a problem in the text rotation code (aspect ratio??).
1799 static TBOOLEAN ENHgd_opened_string;
1801 /* used in determining height of processed text */
1802 static float ENHgd_base;
1804 /* use these so that we don't over-write the current font settings in png_state */
1805 static double ENHgd_fontsize;
1806 static char *ENHgd_font;
1808 static TBOOLEAN ENHgd_show = TRUE;
1809 static TBOOLEAN ENHgd_sizeonly = FALSE;
1810 static int ENHgd_overprint = 0;
1811 static TBOOLEAN ENHgd_widthflag = TRUE;
1812 static unsigned int ENHgd_xsave, ENHgd_ysave;
1817 double fontsize, double base,
1822 /* If the overprint code requests a save or restore, that's all we do */
1823 if (overprint == 3) {
1824 ENHgd_xsave = png_state.x;
1825 ENHgd_ysave = png_state.y;
1827 } else if (overprint == 4) {
1828 PNG_move(ENHgd_xsave, ENHgd_ysave);
1832 if (!ENHgd_opened_string) {
1833 ENHgd_opened_string = TRUE;
1834 enhanced_cur_text = &enhanced_text[0];
1835 ENHgd_font = fontname;
1836 ENHgd_fontsize = fontsize;
1838 ENHgd_show = showflag;
1839 ENHgd_overprint = overprint;
1840 ENHgd_widthflag = widthflag;
1844 /* Write a string fragment and update the current position */
1848 int brect[8]; char *err;
1851 if (ENHgd_opened_string) {
1852 ENHgd_opened_string = FALSE;
1853 *enhanced_cur_text = '\0';
1856 x -= sin((double)png_state.angle * M_PI_2/90.) * ENHgd_base;
1857 y += cos((double)png_state.angle * M_PI_2/90.) * ENHgd_base;
1858 x += sin((double)png_state.angle * M_PI_2/90.) * (double)png_state.charh/4.;
1859 y -= cos((double)png_state.angle * M_PI_2/90.) * (double)png_state.charh/4.;
1861 #ifdef gdFTEX_Adobe_Custom
1862 /* libgd defaults to UTF-8 encodings. We have limited options for */
1863 /* over-riding this, but we can try */
1864 if (ENHgd_font && !strcmp(ENHgd_font,"Symbol")) {
1865 PNG_FONT_INFO.flags |= gdFTEX_CHARMAP;
1866 PNG_FONT_INFO.charmap = gdFTEX_Adobe_Custom;
1868 PNG_FONT_INFO.flags &= ~gdFTEX_CHARMAP;
1869 PNG_FONT_INFO.charmap = 0; /* gdFTEX_Adobe_Custom */
1871 err = gdImageStringFTEx(
1872 (ENHgd_show && !ENHgd_sizeonly) ? png_state.image : NULL,
1873 brect, png_state.color,
1874 ENHgd_font, ENHgd_fontsize,
1875 (double)png_state.angle * M_PI_2/90.,
1876 x, Y(y), enhanced_text, &PNG_FONT_INFO);
1878 err = gdImageStringFT(
1879 (ENHgd_show && !ENHgd_sizeonly) ? png_state.image : NULL,
1880 brect, png_state.color,
1881 ENHgd_font, ENHgd_fontsize,
1882 (double)png_state.angle * M_PI_2/90.,
1883 x, Y(y), enhanced_text);
1886 fprintf(stderr,"gdImageStringFT: %s while printing string %s with font %s\n",
1887 err,enhanced_text,ENHgd_font);
1889 FPRINTF((stderr,"outputstring: %s boundingbox: %d %d %d %d\n",
1890 enhanced_text, brect[6], brect[7], brect[2], brect[3]));
1891 if (ENHgd_overprint == 1) {
1892 png_state.x += ((brect[2] - brect[0]))/2;
1893 png_state.y -= (brect[3] - brect[1]);
1894 } else if (ENHgd_widthflag) {
1895 png_state.x += (brect[2] - brect[0]);
1896 png_state.y -= (brect[3] - brect[1]);
1902 ENHGD_put_text(unsigned int x, unsigned int y, const char *str)
1904 char *original_string = (char *)str;
1906 if (ignore_enhanced_text || !png_state.ttffont) {
1907 PNG_put_text(x,y,str);
1914 /* if there are no magic characters, we should just be able
1915 * punt the string to PNG_put_text()
1917 if (!strpbrk(str, "{}^_@&~")) {
1918 /* FIXME: do something to ensure default font is selected */
1919 PNG_put_text(x,y,str);
1925 /* set up the global variables needed by enhanced_recursion() */
1926 enhanced_max_height = -1000;
1927 enhanced_min_height = 1000;
1928 enhanced_fontscale = 1.0;
1929 strncpy(enhanced_escape_format,"&#x%2.2x;",sizeof(enhanced_escape_format));
1931 ENHgd_opened_string = FALSE;
1933 ENHgd_overprint = 0;
1935 /* EAM - post.trm wasn't doing this, but how else do they get initialized? */
1936 ENHgd_font = png_state.ttffont;
1937 ENHgd_fontsize = png_state.ttfsize;
1939 /* EAM - Software text justification requires two passes */
1940 if (png_state.justify == RIGHT || png_state.justify == CENTRE)
1941 ENHgd_sizeonly = TRUE;
1943 /* Set the recursion going. We say to keep going until a
1944 * closing brace, but we don't really expect to find one.
1945 * If the return value is not the nul-terminator of the
1946 * string, that can only mean that we did find an unmatched
1947 * closing brace in the string. We increment past it (else
1948 * we get stuck in an infinite loop) and try again.
1950 while (*(str = enhanced_recursion((char *)str, TRUE,
1951 ENHgd_font, ENHgd_fontsize,
1952 0.0, TRUE, TRUE, 0))) {
1953 (term->enhanced_flush)();
1955 /* I think we can only get here if *str == '}' */
1959 break; /* end of string */
1961 /* else carry on and process the rest of the string */
1964 enhanced_max_height += enhanced_min_height;
1966 /* We can do text justification by running the entire top level string */
1967 /* through 2 times, with the ENHgd_sizeonly flag set the first time. */
1968 /* After seeing where the final position is, we then offset the start */
1969 /* point accordingly and run it again without the flag set. */
1970 if (png_state.justify == RIGHT || png_state.justify == CENTRE) {
1971 int justification = png_state.justify;
1972 int x_offset = png_state.x - x;
1975 if (png_state.angle != 0)
1976 y_offset = png_state.y - y;
1977 png_state.justify = LEFT;
1978 ENHgd_sizeonly = FALSE;
1980 if (justification == RIGHT) {
1981 ENHGD_put_text(x - x_offset, y - y_offset, original_string);
1982 } else if (justification == CENTRE) {
1983 ENHGD_put_text(x - x_offset/2, y - y_offset/2, original_string);
1985 png_state.justify = justification;
1995 PNG_image (unsigned M, unsigned N, coordval * image, gpiPoint * corner, t_imagecolor color_mode)
1997 int m, n, mout, nout;
1999 int xclip1, xclip2, yclip1, yclip2;
2004 if (png_state.TrueColor) {
2005 im = gdImageCreateTrueColor(M, N);
2007 int_error(NO_CARET,"libgd: failed to create image structure");
2011 im = gdImageCreate(M, N);
2013 int_error(NO_CARET,"libgd: failed to create image structure");
2014 gdImagePaletteCopy(im, png_state.image);
2017 /* TrueColor 24-bit color mode */
2018 if (color_mode == IC_RGB) {
2019 for (n=0; n<N; n++) {
2020 for (m=0; m<M; m++) {
2022 rgb255_color rgb255;
2026 rgb255_from_rgb1( rgb1, &rgb255 );
2027 pixel = gdImageColorResolve( im,
2028 (int)rgb255.r, (int)rgb255.g, (int)rgb255.b );
2029 gdImageSetPixel( im, m, n, pixel );
2032 /* Palette color lookup from gray value */
2034 for (n=0; n<N; n++) {
2035 for (m=0; m<M; m++) {
2037 rgb255maxcolors_from_gray( *image++, &rgb );
2038 pixel = gdImageColorResolve( im,
2039 (int)rgb.r, (int)rgb.g, (int)rgb.b );
2040 gdImageSetPixel( im, m, n, pixel );
2046 /* Set clipping bound for area into which we will copy */
2047 xclip1 = GPMIN(corner[2].x, corner[3].x);
2048 xclip2 = GPMAX(corner[2].x, corner[3].x);
2049 yclip1 = GPMIN(Y(corner[2].y), Y(corner[3].y));
2050 yclip2 = GPMAX(Y(corner[2].y), Y(corner[3].y));
2051 gdImageGetClip(png_state.image, &x1, &y1, &x2, &y2);
2052 gdImageSetClip(png_state.image, xclip1, yclip1, xclip2, yclip2);
2055 /* Copy and resize onto requested region of plot */
2056 /* FIXME - WOULD gdImageCopyResampled() do a nicer job ??? */
2057 mout = abs( (int)corner[1].x - (int)corner[0].x );
2058 nout = abs( (int)corner[1].y - (int)corner[0].y );
2059 gdImageCopyResized(png_state.image, im,
2060 (corner[0].x), Y(corner[0].y), /* Destination X, Y */
2061 0, 0, /* Source X, Y */
2062 mout, nout, /* Destination Width, Height */
2063 M, N /* Source Width, Height */
2068 /* Restore previous clipping, if any */
2069 gdImageSetClip(png_state.image, x1, y1, x2, y2);
2078 #endif /* TERM_BODY */
2081 TERM_TABLE_START(png_driver)
2082 "png", "PNG images using libgd and TrueType fonts",
2083 GREG_XMAX, GREG_YMAX, PNG_VCHAR, PNG_HCHAR,
2084 PNG_TICSIZE, PNG_TICSIZE, PNG_options, PNG_init, PNG_reset,
2085 PNG_text, null_scale, PNG_graphics, PNG_move, PNG_vector,
2086 PNG_linetype, PNG_put_text, PNG_text_angle,
2087 PNG_justify_text, PNG_point, do_arrow, PNG_set_font,
2090 0 /*suspend*/, 0 /*resume*/,
2091 PNG_boxfill /*EAM - fillbox*/,
2092 PNG_linewidth /*EAM - linewidth*/
2094 , 0, 0, 0, 0, 0 /* no mouse support */
2097 0, /* previous_palette() ... no, single array of 256 colours for PNG */
2103 , ENHGD_OPEN, ENHGD_FLUSH, do_enh_writec
2104 TERM_TABLE_END(png_driver)
2107 #define LAST_TERM png_driver
2109 #endif /* TERM_TABLE */
2110 #endif /* TERM_PROTO_ONLY */
2112 #ifndef JPEG_HELP_ONLY
2116 "?commands set terminal png",
2117 "?set terminal png",
2123 " set terminal png ",
2124 " {{no}transparent} {{no}interlace}",
2125 " {{no}truecolor} {rounded|butt}",
2126 " {tiny | small | medium | large | giant}",
2127 " {font <face> {<pointsize>}}",
2128 " {size <x>,<y>} {{no}crop}",
2130 " {<color0> <color1> <color2> ...}",
2132 " PNG images are created using libgd, with optional support for TrueType",
2133 " and Adobe Type 1 fonts via libfreetype. Version 1.8 or greater of libgd",
2136 " `transparent` instructs the driver to generate transparent PNGs. The first",
2137 " color will be the transparent one. Default is `notransparent`.",
2139 " `interlace` instructs the driver to generate interlaced PNGs.",
2140 " Default is `nointerlace`.",
2142 " `butt` instructs the driver to use a line drawing method that does",
2143 " not overshoot the desired end point of a line. This setting is only",
2144 " applicable for line widths greater than 1. This setting is most useful when",
2145 " drawing horizontal or vertical lines. Default is `rounded`.",
2146 " Version 2.0 or greater of libgd is required.",
2148 " PNG plots may be conveniently viewed by piping the output to the",
2149 " 'display' program from the ImageMagick package as follows:",
2151 " set output '| display png:-'",
2153 " View the output from successive plot commands interactively by hitting",
2154 " <space> in the display window. To save a particular one to disk, left",
2155 " click in the display window and choose `save`.",
2157 " Five basic fonts are supported directly by the gd library. These are",
2158 " `tiny` (5x8 pixels), `small` (6x12 pixels), `medium`, (7x13 Bold), ",
2159 " `large` (8x16) or `giant` (9x15 pixels). These fonts cannot be scaled",
2160 " or rotated (pure horizontal or vertical text only).",
2163 " If gnuplot was built with support for TrueType (*.ttf) or Adobe Type 1 ",
2164 " (*.pfa) fonts, they may be selected using the 'font <face> {<pointsize>}' ",
2165 " option. <face> is either the full pathname to the font file, or a font ",
2166 " face name that is assumed to be the first part of a filename in one of the ",
2167 " directories listed in the GDFONTPATH environmental variable. That is, ",
2168 " 'set term png font \"Face\"' will look for a font file named either ",
2169 " <somedirectory>/Face.ttf or <somedirectory>/Face.pfa. Both TrueType and ",
2170 " Adobe Type 1 fonts are fully scalable and may be rotated through any angle.",
2171 " If no font is specified, gnuplot checks the environmental variable ",
2172 " GNUPLOT_DEFAULT_GDFONT to see if there is a preferred default font. ",
2174 " `enhanced` enables the enhanced text processing features, (subscripts, ",
2175 " superscripts and mixed fonts). See `enhanced` for more information. ",
2176 " The full enhanced mode syntax is supported by the PNG/JPEG driver itself,",
2177 " but some of these features are dependent on which version of the ",
2178 " underlying libgd library is present, and which fonts are available.",
2180 " The size <x,y> is given in pixels---it defaults to 640x480. The number of",
2181 " pixels can be also modified by scaling with the `set size` command.",
2182 " `crop` trims blank space from the edges of the completed plot, resulting",
2183 " in a smaller final image size. Default is `nocrop`.",
2185 " Each color must be of the form 'xrrggbb', where x is the literal character",
2186 " 'x' and 'rrggbb' are the red, green and blue components in hex. For example,",
2187 " 'x00ff00' is green. The background color is set first, then the border",
2188 " colors, then the X & Y axis colors, then the plotting colors. The maximum",
2189 " number of colors that can be set is 256.",
2192 " set terminal png medium size 640,480 \\",
2193 " xffffff x000000 x404040 \\",
2194 " xff0000 xffa500 x66cdaa xcdb5cd \\",
2195 " xadd8e6 x0000ff xdda0dd x9500d3 # defaults",
2197 " which uses white for the non-transparent background, black for borders, gray",
2198 " for the axes, and red, orange, medium aquamarine, thistle 3, light blue, blue,",
2199 " plum and dark violet for eight plotting colors.",
2201 " set terminal png font arial 14 size 800,600",
2203 " which searches for a TrueType font with face name 'arial' in the directory",
2204 " specified by the environment variable GDFONTPATH and 14pt font size.",
2206 " set terminal png transparent xffffff \\",
2207 " x000000 x202020 x404040 x606060 \\",
2208 " x808080 xA0A0A0 xC0C0C0 xE0E0E0",
2210 " which uses white for the transparent background, black for borders, dark",
2211 " gray for axes, and a gray-scale for the six plotting colors.",
2214 #endif /* TERM_HELP */
2215 #endif /* JPEG_HELP_ONLY */
2218 * JPEG support comes almost for free.
2219 * We just piggy-back on the PNG routines, since they both go via libgd
2223 #ifdef TERM_REGISTER
2228 TERM_PUBLIC void JPEG_text __PROTO((void));
2229 #define GOT_NEXT_PROTO
2232 #ifndef TERM_PROTO_ONLY
2238 * All functions except the final write to file
2239 * are actually performed by the PNG driver code
2247 if (png_state.flags & PNG_USE_INTERLACE)
2248 gdImageInterlace(png_state.image, 1);
2249 gdImageJpeg(png_state.image, gpoutfile, quality);
2250 gdImageDestroy(png_state.image);
2253 #endif /* TERM_BODY */
2257 TERM_TABLE_START(jpeg_driver)
2258 "jpeg", "JPEG images using libgd and TrueType fonts",
2259 GREG_XMAX, GREG_YMAX, PNG_VCHAR, PNG_HCHAR,
2260 PNG_TICSIZE, PNG_TICSIZE, PNG_options, PNG_init, PNG_reset,
2261 JPEG_text, null_scale, PNG_graphics, PNG_move, PNG_vector,
2262 PNG_linetype, PNG_put_text, PNG_text_angle,
2263 PNG_justify_text, PNG_point, do_arrow, PNG_set_font,
2265 TERM_CAN_MULTIPLOT | TERM_BINARY,
2266 0 /*suspend*/, 0 /*resume*/,
2267 PNG_boxfill /*EAM - fillbox*/,
2268 PNG_linewidth /*EAM - linewidth*/
2270 , 0, 0, 0, 0, 0 /* no mouse support */
2273 0, /* previous_palette() ... no, single array of 256 colours for PNG */
2279 , ENHGD_OPEN, ENHGD_FLUSH, do_enh_writec
2280 TERM_TABLE_END(jpeg_driver)
2283 #define LAST_TERM jpeg_driver
2285 #endif /* TERM_TABLE */
2286 #endif /* TERM_PROTO_ONLY */
2292 "?commands set terminal jpeg",
2293 "?set terminal jpeg",
2300 " set terminal jpeg ",
2302 " {tiny | small | medium | large | giant}",
2303 " {font <face> {<pointsize>}}",
2304 " {size <x>,<y>} {{no}crop}",
2306 " {<color0> <color1> <color2> ...}",
2308 " JPEG images are created using libgd, with optional support for TrueType",
2309 " fonts via libfreetype.",
2311 " The `interlace` option creates a progressive JPEG image.",
2312 " Default is `nointerlace`.",
2314 " Five basic fonts are supported directly by the gd library. These are",
2315 " `tiny` (5x8 pixels), `small` (6x12 pixels), `medium`, (7x13 Bold), ",
2316 " `large` (8x16) or `giant` (9x15 pixels). These fonts cannot be scaled",
2317 " or rotated (pure horizontal or vertical text only).",
2320 " If gnuplot was built with support for TrueType (*.ttf) or Adobe Type 1 ",
2321 " (*.pfa) fonts, they may be selected using the 'font <face> {<pointsize>}' ",
2322 " option. <face> is either the full pathname to the font file, or a font ",
2323 " face name that is assumed to be the first part of a filename in one of the ",
2324 " directories listed in the GDFONTPATH environmental variable. That is, ",
2325 " 'set term jpeg font \"Face\"' will look for a font file named either ",
2326 " <somedirectory>/Face.ttf or <somedirectory>/Face.pfa. Both TrueType and ",
2327 " Adobe Type 1 fonts are fully scalable and may be rotated through any angle.",
2328 " If no font is specified, gnuplot checks the environmental variable ",
2329 " GNUPLOT_DEFAULT_GDFONT to see if there is a preferred default font. ",
2331 " `enhanced` enables the enhanced text processing features, (subscripts, ",
2332 " superscripts and mixed fonts). See `enhanced` for more information. ",
2333 " The full enhanced mode syntax is supported by the PNG/JPEG driver itself,",
2334 " but some of these features are dependent on which version of the ",
2335 " underlying libgd library is present, and which fonts are available.",
2337 " The size <x,y> is given in pixels---it defaults to 640x480. The number of",
2338 " pixels can be also modified by scaling with the `set size` command.",
2339 " `crop` trims blank space from the edges of the completed plot, resulting",
2340 " in a smaller final image size. Default is `nocrop`.",
2342 " Each color must be of the form 'xrrggbb', where x is the literal character",
2343 " 'x' and 'rrggbb' are the red, green and blue components in hex. For example,",
2344 " 'x00ff00' is green. The background color is set first, then the border",
2345 " colors, then the X & Y axis colors, then the plotting colors. The maximum",
2346 " number of colors that can be set is 256.",
2349 " set terminal jpeg medium size 640,480 \\",
2350 " xffffff x000000 x404040 \\",
2351 " xff0000 xffa500 x66cdaa xcdb5cd \\",
2352 " xadd8e6 x0000ff xdda0dd x9500d3 # defaults",
2354 " which uses white for the non-transparent background, black for borders, gray",
2355 " for the axes, and red, orange, medium aquamarine, thistle 3, light blue, blue,",
2356 " plum and dark violet for eight plotting colors.",
2358 " set terminal jpeg large font arial size 800,600",
2360 " which searches for a TrueType font with face name 'arial' in the directory",
2361 " specified by the environment variable GDFONTPATH and large (14pt) font size.",
2364 #endif /* TERM_HELP */
2365 #endif /* HAVE_GD_JPEG */
2369 * GIF support comes almost for free.
2370 * We just piggy-back on the PNG routines, since they both go via libgd.
2371 * Required libgd version is 2.0.28 or newer.
2375 #ifdef TERM_REGISTER
2380 TERM_PUBLIC void GIF_text __PROTO((void));
2381 #define GOT_NEXT_PROTO
2384 #ifndef TERM_PROTO_ONLY
2390 * All functions except the final write to file
2391 * are actually performed by the PNG driver code
2398 #ifdef GIF_ANIMATION
2399 if (png_state.animate) {
2400 /* Note - using a global colormap saves space, but it breaks */
2401 /* if later frames add new colors to the palette. */
2402 if (png_state.frame_count == 0) {
2403 gdImageGifAnimBegin(png_state.image, gpoutfile,
2404 1, /* Load Global Colormap even if it isn't used */
2405 png_state.loop_count );
2407 gdImageGifAnimAdd(png_state.image, gpoutfile,
2408 png_state.frame_optimization ? 0 /* use global map */
2409 : 1, /* use private map */
2410 0, 0 /* No offset */,
2411 png_state.frame_delay,
2412 (png_state.flags & PNG_USE_TRANSPARENT)
2413 ? gdDisposalRestorePrevious
2415 (png_state.frame_optimization && !(png_state.flags & PNG_USE_TRANSPARENT))
2416 ? png_state.previous_image : NULL);
2417 png_state.frame_count++;
2418 if (png_state.previous_image)
2419 gdImageDestroy(png_state.previous_image);
2420 png_state.previous_image = png_state.image;
2425 gdImageGif(png_state.image, gpoutfile);
2426 gdImageDestroy(png_state.image);
2429 #endif /* TERM_BODY */
2433 TERM_TABLE_START(gif_driver)
2434 "gif", "GIF images using libgd and TrueType fonts",
2435 GREG_XMAX, GREG_YMAX, PNG_VCHAR, PNG_HCHAR,
2436 PNG_TICSIZE, PNG_TICSIZE, PNG_options, PNG_init, PNG_reset,
2437 GIF_text, null_scale, PNG_graphics, PNG_move, PNG_vector,
2438 PNG_linetype, PNG_put_text, PNG_text_angle,
2439 PNG_justify_text, PNG_point, do_arrow, PNG_set_font,
2441 TERM_CAN_MULTIPLOT | TERM_BINARY,
2442 0 /*suspend*/, 0 /*resume*/,
2443 PNG_boxfill /*EAM - fillbox*/,
2444 PNG_linewidth /*EAM - linewidth*/
2446 , 0, 0, 0, 0, 0 /* no mouse support */
2449 0, /* previous_palette() ... no, single array of 256 colours for PNG */
2455 , ENHGD_OPEN, ENHGD_FLUSH, do_enh_writec
2456 TERM_TABLE_END(gif_driver)
2459 #define LAST_TERM gif_driver
2461 #endif /* TERM_TABLE */
2462 #endif /* TERM_PROTO_ONLY */
2468 "?commands set terminal gif",
2469 "?set terminal gif",
2476 " set terminal gif ",
2477 " {tiny | small | medium | large | giant}",
2478 " {{no}transparent} {{no}enhanced}",
2479 " {font <face> {<pointsize>}}",
2480 " {animate {delay <time>} {{no}optimize}}",
2481 " {size <x>,<y>} {{no}crop}",
2482 " {<color0> <color1> <color2> ...}",
2484 " GIF images are created using libgd, with optional support for TrueType",
2485 " fonts via libfreetype.",
2487 " GIF plots may be conveniently viewed by piping the output to the",
2488 " 'display' program from the ImageMagick package as follows:",
2490 " set output '| display gif:-'",
2492 " View the output from successive plot commands interactively by hitting",
2493 " <space> in the display window. To save a particular one to disk, left",
2494 " click in the display window and choose `save`.",
2496 " Five basic fonts are supported directly by the gd library. These are",
2497 " `tiny` (5x8 pixels), `small` (6x12 pixels), `medium`, (7x13 Bold), ",
2498 " `large` (8x16) or `giant` (9x15 pixels). These fonts cannot be scaled",
2499 " or rotated (pure horizontal or vertical text only).",
2501 " `transparent` instructs the driver to generate transparent GIFs. The first",
2502 " color will be the transparent one. Default is `notransparent`.",
2504 " `enhanced` enables the enhanced text processing features, (subscripts, ",
2505 " superscripts and mixed fonts). See `enhanced` for more information. ",
2506 " The full enhanced mode syntax is supported by the PNG/GIF driver itself,",
2507 " but some of these features are dependent on which version of the ",
2508 " underlying libgd library is present, and which fonts are available.",
2511 " If your local gd library was built with support for TrueType and Adobe",
2512 " Type 1 fonts, they may be selected using the 'font <face> {<pointsize>}' ",
2513 " option. <face> is either the full pathname to the font file, or a font ",
2514 " face name that is assumed to be the first part of a filename in one of the ",
2515 " directories listed in the GDFONTPATH environmental variable. That is, ",
2516 " 'set term gif font \"Face\"' will look for a font file named either ",
2517 " <somedirectory>/Face.ttf or <somedirectory>/Face.pfa. Both TrueType and ",
2518 " Adobe Type 1 fonts are fully scalable and may be rotated through any angle.",
2519 " If no font is specified, gnuplot checks the environmental variable ",
2520 " GNUPLOT_DEFAULT_GDFONT to see if there is a preferred default font. ",
2522 " The `animate` option is available only if your local gd library supports",
2523 " the creation of animated gifs. The default delay between display of",
2524 " successive images may be specified in units of 1/100 second (default 5).",
2525 " The actual delay may vary depending on the program used as a viewer.",
2526 " An animation sequence is terminated by the next `set output` or `set term`",
2527 " command. The `optimize` option has two effects on the animation.",
2529 " 1) A single color map is used for the entire animation. This requires",
2530 " that all colors used in any frame of the animation are already",
2531 " defined in the first frame.",
2533 " 2) If possible, only the portions of a frame that differ from the",
2534 " previous frame are stored in the animation file. This space saving",
2535 " may not be possible if the animation uses transparency.",
2537 " Both of these optimizations are intended to produce a smaller output file,",
2538 " but the decrease in size is probably only significant for long animations",
2539 " or very small frame sizes.",
2540 " The `nooptimize` option turns off both of the effects just described.",
2541 " Each frame is stored in its entirety along with a private color map.",
2542 " Note that it is possible to post-process a non-optimized animation",
2543 " using external utilities, and this post-processing can yield a smaller",
2544 " file than gnuplot's internal optimization mode.",
2545 " The default is `nooptimize`.",
2547 " The size <x,y> is given in pixels---it defaults to 640x480. The number of",
2548 " pixels can be also modified by scaling with the `set size` command.",
2549 " `crop` trims blank space from the edges of the completed plot, resulting",
2550 " in a smaller final image size. Default is `nocrop`.",
2552 " Each color must be of the form 'xrrggbb', where x is the literal character",
2553 " 'x' and 'rrggbb' are the red, green and blue components in hex. For example,",
2554 " 'x00ff00' is green. The background color is set first, then the border",
2555 " colors, then the X & Y axis colors, then the plotting colors. The maximum",
2556 " number of colors that can be set is 256.",
2559 " set terminal gif medium size 640,480 \\",
2560 " xffffff x000000 x404040 \\",
2561 " xff0000 xffa500 x66cdaa xcdb5cd \\",
2562 " xadd8e6 x0000ff xdda0dd x9500d3 # defaults",
2564 " which uses white for the non-transparent background, black for borders, gray",
2565 " for the axes, and red, orange, medium aquamarine, thistle 3, light blue, blue,",
2566 " plum and dark violet for eight plotting colors.",
2568 " set terminal gif font 'arial' 14 size 800,600",
2570 " which searches for a TrueType font with face name 'arial' in the directory",
2571 " specified by the environment variable GDFONTPATH and 14pt font size.",
2574 #endif /* TERM_HELP */
2575 #endif /* HAVE_GD_GIF */