/* * $Id: png.trm,v 1.11.2.12 2002/12/12 12:56:44 lhecking Exp $ * */ /* GNUPLOT - png.trm */ /*[ * Copyright 1995, 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: * png * * AUTHORS * Alexander Lehmann * derived from pbm.trm by Russell Lang * * Eric S. Raymond update for pnglib-1.0.3; transparency. * H.-B. Broeker fixes to Eric's changes * * send your comments or suggestions to (info-gnuplot@dartmouth.edu). * */ /* To compile this terminal driver, you need libpng and zlib, both are available at ftp://ftp.uu.net/graphics/png. Remember to add the include dirs and libraries to TERMFLAGS and TERMLIBS. */ /* The following png drivers use the generic bit mapped graphics routines from bitmap.c to build up a bit map in memory. The driver interchanges colomns and lines in order to access entire lines easily and returns the lines to get bits in the right order : (x,y) -> (y,XMAX-1-x). */ /* This interchange is done by calling b_makebitmap() with reversed xmax and ymax, and then setting b_rastermode to TRUE. b_setpixel() will then perform the interchange before each pixel is plotted */ #include "driver.h" #ifdef TERM_REGISTER register_term(png_driver) #endif #ifdef TERM_PROTO TERM_PUBLIC void PNG_options __PROTO((void)); TERM_PUBLIC void PNG_init __PROTO((void)); TERM_PUBLIC void PNG_reset __PROTO((void)); TERM_PUBLIC void PNG_setfont __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_point __PROTO((unsigned int x, unsigned int y, int point)); #endif /* TERM_PROTO */ /* make XMAX and YMAX a multiple of 8 */ #define PNG_XMAX (640) #define PNG_YMAX (480) #define PNG_VCHAR (FNT5X9_VCHAR) #define PNG_HCHAR (FNT5X9_VCHAR) #define PNG_VTIC FNT5X9_HBITS #define PNG_HTIC FNT5X9_HBITS #ifdef TERM_BODY #include "png.h" /* I'm not sure exactly which is the first version we work with, * but I know that some older ones don't define all the symbols * we use */ /* png version test now in configure */ static int png_font = 1; /* small font */ static int png_mode = 0; /* 0:monochrome 1:gray 2:color */ static int png_transparent = 0; /* generate transparent first color */ /* 7=black, 0=white */ static int png_gray[] = { 7, 1, 6, 5, 4, 3, 2, 1, 7 }; /* grays */ static png_color png_palette[WEB_N_COLORS]; TERM_PUBLIC void PNG_options() { unsigned short rgb_color[3]; int n_colors = 0; char *string; int i; rgb_color[0] = 0; rgb_color[1] = 0; rgb_color[2] = 0; png_font = 1; /* small */ png_mode = 2; /* color */ png_transparent = 0; /* use opaque image background */ term_options[0] = NUL; while (!END_OF_COMMAND) { if (almost_equals(c_token, "s$mall")) png_font = 1; else if (almost_equals(c_token, "me$dium")) png_font = 2; else if (almost_equals(c_token, "l$arge")) png_font = 3; else if (almost_equals(c_token, "mo$nochrome")) png_mode = 0; else if (almost_equals(c_token, "g$ray")) png_mode = 1; else if (almost_equals(c_token, "c$olor") || almost_equals(c_token, "c$olour")) png_mode = 2; else if (almost_equals(c_token, "t$ransparent")) png_transparent = 1; else if (almost_equals(c_token, "not$ransparent")) png_transparent = 0; else { /* set color */ string = input_line + token[c_token].start_index; if (string[0] == 'x') { /* HBB 991123: read in as *shorts*, not ints! */ if (sscanf(string, "x%2hx%2hx%2hx", &rgb_color[0], &rgb_color[1], &rgb_color[2] ) != 3) { int_error("invalid color spec, must be xRRGGBB", c_token); } } else int_error("expecting: {small, medium, large},[no]transparent, or {monochrome, gray, color, [xRRGGBB] }", c_token); if (n_colors >= WEB_N_COLORS) { int_warn("too many colors, ignoring", c_token); /* Magic number abuse guards against * "> WEB_N_COLORS warning" scroll fests. */ if (!END_OF_COMMAND) { while (!END_OF_COMMAND) ++c_token; --c_token; } } else { web_color_rgbs[n_colors].r = rgb_color[0]; web_color_rgbs[n_colors].g = rgb_color[1]; web_color_rgbs[n_colors].b = rgb_color[2]; n_colors++; } } c_token++; } /* setup options string */ /* HBB 991008: moved this block to here, so 'transparent' gets * printed out first. Don't print 'notransparent', for now, to * protect older gnuplots. Scripts with 'transparent' in them * won't work as wanted, with older versions, so put it here. */ if (png_transparent) strcat(term_options, " transparent"); switch (png_font) { case 3: strcat(term_options, " large"); break; case 2: strcat(term_options, " medium"); break; case 1: default: strcat(term_options, " small"); break; } switch (png_mode) { case 2: strcat(term_options, " color"); break; case 1: strcat(term_options, " gray"); break; case 0: default: strcat(term_options, " monochrome"); break; } for (i = 0; strlen(term_options) + 9 < MAX_LINE_LEN && i < n_colors ; i++ ) { sprintf(term_options,"%s x%02x%02x%02x", term_options, web_color_rgbs[i].r, web_color_rgbs[i].g, web_color_rgbs[i].b); } } TERM_PUBLIC void PNG_init() { PNG_setfont(); /* HBB 980226: do this here! */ } TERM_PUBLIC void PNG_reset() { #ifdef VMS fflush_binary(); #endif /* VMS */ } TERM_PUBLIC void PNG_setfont() { switch (png_font) { case 3: b_charsize(FNT13X25); term->v_char = FNT13X25_VCHAR; term->h_char = FNT13X25_HCHAR; term->v_tic = FNT13X25_HBITS; term->h_tic = FNT13X25_HBITS; break; case 2: b_charsize(FNT9X17); term->v_char = FNT9X17_VCHAR; term->h_char = FNT9X17_HCHAR; term->v_tic = FNT9X17_HBITS; term->h_tic = FNT9X17_HBITS; break; case 1: default: b_charsize(FNT5X9); term->v_char = FNT5X9_VCHAR; term->h_char = FNT5X9_HCHAR; term->v_tic = FNT5X9_HBITS; term->h_tic = FNT5X9_HBITS; break; } } TERM_PUBLIC void PNG_graphics() { int numplanes = 1; switch (png_mode) { case 2: numplanes = 8; break; case 1: numplanes = 3; break; case 0: default: numplanes = 1; break; } /* PNGsetfont(); *//* HBB 980226: do this in init() ! */ /* rotate plot -90 degrees by reversing XMAX and YMAX and by setting b_rastermode to TRUE */ b_makebitmap((unsigned int) (PNG_YMAX * ysize), (unsigned int) (PNG_XMAX * xsize), numplanes); b_rastermode = TRUE; if (png_mode != 0) b_setlinetype(0); /* solid lines */ } TERM_PUBLIC void PNG_text() { png_structp png_ptr; png_infop info_ptr; png_bytep prow; png_text pngtext, *pngtext_copy; png_byte pal_trans[1]; char text[100]; register int x, i, j; /* register int row, value; */ /* int mask, plane1, plane2, plane3, plane4; */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { b_freebitmap(); return; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp) NULL); b_freebitmap(); return; } prow = malloc(b_ysize); if (!prow) { png_destroy_write_struct(&png_ptr, &info_ptr); b_freebitmap(); return; } memset(prow,0,sizeof(prow)); if (setjmp(png_ptr->jmpbuf)) { png_destroy_write_struct(&png_ptr, &info_ptr); free(prow); b_freebitmap(); return; } #ifdef __OLD_PNGLIB__ /* deprecated and no longer necessary */ png_info_init(info_ptr); png_write_init(png_ptr); */ #endif /* __OLD_PNGLIB__ */ png_init_io(png_ptr, gpoutfile); info_ptr->width = b_ysize; info_ptr->height = b_xsize; info_ptr->bit_depth = png_mode == 0 ? 1 : 8; info_ptr->color_type = png_mode == 2 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY; if (png_mode == 2) { info_ptr->valid |= PNG_INFO_PLTE; info_ptr->palette = png_palette; info_ptr->num_palette = sizeof(png_palette)/sizeof(png_palette[0]); } if (png_mode != 0) { info_ptr->valid |= PNG_INFO_sBIT; if (png_mode == 1) { info_ptr->sig_bit.gray = 3; png_set_shift(png_ptr, &(info_ptr->sig_bit)); } else { /* HBB 991123: we're now using the full 8 bits per color * component... */ info_ptr->sig_bit.red = 8; info_ptr->sig_bit.green = 8; info_ptr->sig_bit.blue = 8; } } info_ptr->interlace_type = 0; if (png_mode == 0) png_set_invert_mono(png_ptr); if (png_mode == 2) { if (png_transparent) { info_ptr->valid |= PNG_INFO_tRNS; info_ptr->num_trans = 1; pal_trans[0] = 0; info_ptr->trans=pal_trans; } for (i = 0; i < WEB_N_COLORS; i++) { png_palette[i].red = web_color_rgbs[i].r; png_palette[i].green = web_color_rgbs[i].g; png_palette[i].blue = web_color_rgbs[i].b; } } sprintf(text, "gnuplot version %s patchlevel %s on %s %s", gnuplot_version, gnuplot_patchlevel, os_name, os_rel); pngtext.compression = -1; pngtext.key = "Software"; pngtext.text = text; pngtext.text_length = strlen(text); pngtext_copy = malloc(sizeof(*pngtext_copy)); if (!pngtext_copy) { png_destroy_write_struct(&png_ptr, &info_ptr); free(prow); b_freebitmap(); return; } memset(pngtext_copy,0,sizeof(pngtext_copy)); *pngtext_copy = pngtext; info_ptr->num_text = 1; info_ptr->text = pngtext_copy; png_write_info(png_ptr, info_ptr); info_ptr->num_text = 0; if (info_ptr->text) free(info_ptr->text); info_ptr->text = NULL; png_set_packing(png_ptr); /* dump bitmap in raster mode */ for (x = b_xsize - 1; x >= 0; x--) { #if 0 row = (b_ysize / 8) - 1; for (j = row; j >= 0; j--) { mask = 0x80; plane1 = (*((*b_p)[j] + x)); if (png_mode != 0) { plane2 = (*((*b_p)[j + b_psize] + x)); plane3 = (*((*b_p)[j + b_psize + b_psize] + x)); } else { plane2 = 0; plane3 = 0; } if (png_mode == 2) plane4 = (*((*b_p)[j + b_psize + b_psize + b_psize] + x)); else plane4 = 0; for (i = 0; i < 8; i++) { value = 0; if (plane1 & mask) value += 1; if (plane2 & mask) value += 2; if (plane3 & mask) value += 4; if (plane4 & mask) value += 8; if (png_mode == 1) value = 7 - value; prow[(row - j) * 8 + i] = (png_byte) (value & 0xFF) ; mask >>= 1; } } #else for (j=b_ysize - 1; j>= 0; j--) prow[j] = (png_byte)b_getpixel(j, x); #endif png_write_rows(png_ptr, &prow, 1); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); free(prow); b_freebitmap(); } /* _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 PNG_linetype(linetype) int linetype; { switch (png_mode) { /* HBB 991008: this once made the grid lines and axes (-1) look the * same as the borders (-2). That's ugly, IMHO. GIF uses a * dashed line, for this, but libpng doesn't seem able to do * that. But a look into the palette turns up that color 2 * is grey, and is currently unused... Let's see: */ case 2: if (linetype == -2) linetype = 1; else if (linetype == -1) linetype = 2; else { /* HBB 991008: moved the += 3 down, so colors 0, 1, 2 are * _not_ used by the regular plots, as it should be */ if (linetype >= (WEB_N_COLORS - 3)) linetype %= (WEB_N_COLORS - 3); linetype += 3; } b_setvalue(linetype); break; case 1: if (linetype >= 7) linetype %= 7; b_setvalue(png_gray[linetype + 2]); break; case 0: default: b_setlinetype(linetype); break; } } TERM_PUBLIC void PNG_point(x, y, point) unsigned int x, y; int point; { if (png_mode == 0) line_and_point(x, y, point); else do_point(x, y, point); } #endif /* TERM_BODY */ #ifdef TERM_TABLE TERM_TABLE_START(png_driver) "png", "Portable Network Graphics [small medium large] [monochrome gray color]", PNG_XMAX, PNG_YMAX, PNG_VCHAR, PNG_HCHAR, PNG_VTIC, PNG_HTIC, PNG_options, PNG_init, PNG_reset, PNG_text, null_scale, PNG_graphics, b_move, b_vector, PNG_linetype, b_put_text, b_text_angle, null_justify_text, PNG_point, do_arrow, set_font_null, 0, /* pointsize */ TERM_CAN_MULTIPLOT | TERM_BINARY TERM_TABLE_END(png_driver) #undef LAST_TERM #define LAST_TERM png_driver #endif /* TERM_TABLE */ #ifdef TERM_HELP START_HELP(png) "1 png", "?commands set terminal png", "?set terminal png", "?set term png", "?terminal png", "?term png", "?png", " The `png` terminal driver supports Portable Network Graphics. To compile it,", " you will need the third-party libraries \"libpng\" and \"zlib\"; both are", " available at http://www.cdrom.com/pub/png/. `png` has four options.", "", " By default, the `png` terminal driver uses a shared Web-friendy palette.", "", " Syntax:", " set terminal png {small | medium | large}", " {transparent | notransparent}", " {monochrome | gray | color}", " { ...}", "", " `transparent` instructs the driver to generate transparent PNGs. The first", " color will be the transparent one.", "", " The defaults are small (fontsize) and color. Default size of the output", " is 640*480 pixel. ", "", " 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 currently 99." END_HELP(png) #endif /* TERM_HELP */