/*-------------------------------------------------------------------- * $Id: pstext.c,v 1.2.4.3 2002/01/17 17:42:51 pwessel Exp $ * * Copyright (c) 1991-2002 by P. Wessel and W. H. F. Smith * See COPYING file for copying and redistribution conditions. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Contact info: gmt.soest.hawaii.edu *--------------------------------------------------------------------*/ /* * pstext will read (x, y, angle, size, fontno, justify, text) from GMT_stdin * or file and plot the textstrings at (x,y) on a map using the size, font, * and justification selected by the user. Alternatively (with -H), read * one or more text paragraphs to be typeset. * * Author: Paul Wessel * Date: 21-JAN-1991-2000 * Version: 2.0 based on old v1.x * Version: 3.1 based on old 3.0 * Version: 3.3: PW: Introducing paragraph mode -M * Version: 3.3.4: PW: Input x,y can be in dd:mm[:ss] format * Version: 3.4.1 * */ #include "gmt.h" struct GMT_TEXT { double x_offset, y_offset; /* Offset from reference point */ double line_spacing; double paragraph_width; int text_justify; int paragraph_font; int font_size; double paragraph_angle; int block_justify; int boxflag; double x_space, y_space; /* Extra spacing between box and text */ struct GMT_PEN boxpen; struct GMT_PEN vecpen; struct GMT_PEN txtpen; struct GMT_FILL txtfill; struct GMT_FILL boxfill; }; int GMT_just_decode(char *key); void GMT_putwords (double x, double y, char **text, int n_words, struct GMT_TEXT *info); main(int argc, char **argv) { int i, j, k, last_font, fno, n_files = 0, n_args, n_words = 0, nscan; int ix, iy, use_font[N_FONTS], n_processed = 0, n_read = 0, n_paragraphs = 0; size_t n_alloc; double xy[2], west = 0., east = 0.0, south = 0.0, north = 0.0, plot_x, plot_y; double new_z_level = 0.0, z_level = 0.0; BOOLEAN error = FALSE, nofile = TRUE, outline = FALSE, set_z = FALSE, master_record = FALSE, offset_outward = FALSE; BOOLEAN solid = TRUE, do_paragraphs = FALSE, list = FALSE, done = FALSE, clip = TRUE, old_GMT_world_map, add; BOOLEAN skip_text_records = FALSE; char text[BUFSIZ], line[BUFSIZ], this_font[80], just_key[5], txt_a[32], txt_b[32], txt_x[32], txt_y[32]; char *p, **word, pjust; FILE *fp = NULL; struct GMT_TEXT T; memset ((void *)&T, 0, sizeof (struct GMT_TEXT)); GMT_init_pen (&T.txtpen, GMT_PENWIDTH); GMT_init_pen (&T.boxpen, GMT_PENWIDTH); GMT_init_pen (&T.vecpen, GMT_PENWIDTH); GMT_init_fill (&T.boxfill, -1, -1, -1); /* No fill */ GMT_init_fill (&T.txtfill, 0, 0, 0); argc = GMT_begin (argc, argv); T.x_space = T.y_space = 0.05; if (gmtdefs.measure_unit == GMT_CM) T.x_space = T.y_space = 0.15 / 2.54; /* Check and interpret the command line arguments */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch(argv[i][1]) { /* Common parameters */ case 'B': case 'H': case 'J': case 'K': case 'O': case 'P': case 'R': case 'U': case 'V': case 'X': case 'x': case 'Y': case 'y': case 'c': case ':': case '\0': error += GMT_get_common_args (argv[i], &west, &east, &south, &north); break; /* Supplemental parameters */ case 'C': sscanf (&argv[i][2], "%[^/]/%s", txt_a, txt_b); T.x_space = GMT_convert_units (txt_a, GMT_INCH); T.y_space = GMT_convert_units (txt_b, GMT_INCH); break; case 'D': k = 2; if (argv[i][k] == 'j') offset_outward = TRUE, k++; for (j = k; argv[i][j] && argv[i][j] != 'v'; j++); if (argv[i][j] == 'v') { T.boxflag |= 32; if (argv[i][j+1] && GMT_getpen (&argv[i][j+1], &T.vecpen)) { fprintf (stderr, "%s: GMT SYNTAX ERROR -D option: Give pen after c\n", GMT_program); error++; } argv[i][j] = 0; } sscanf (&argv[i][k], "%[^/]/%s", txt_a, txt_b); T.x_offset = GMT_convert_units (txt_a, GMT_INCH); T.y_offset = GMT_convert_units (txt_b, GMT_INCH); break; case 'E': sscanf (&argv[i][2], "%lf/%lf", &z_project.view_azimuth, &z_project.view_elevation); break; case 'G': if (GMT_getfill (&argv[i][2], &T.txtfill)) { GMT_fill_syntax ('G'); error++; } solid = TRUE; break; case 'L': list = GMT_quick = TRUE; break; case 'M': /* Multiple line segments input: Text blocks */ GMT_multisegment (&argv[i][2]); do_paragraphs = TRUE; break; case 'N': /* Do not clip at border */ clip = FALSE; break; case 'S': outline = TRUE; if (GMT_getpen (&argv[i][2], &T.txtpen)) { GMT_pen_syntax ('S'); error++; } break; case 'W': for (j = 0; argv[i][j] && !(strchr ("cCoO", argv[i][j])); j++); if (argv[i][j]) { T.boxflag |= 1; /* Want box outline */ if (argv[i][j] == 'O') T.boxflag |= 4; /* Want rounded box outline */ if (argv[i][j] == 'c') T.boxflag |= 8; /* Want concave box outline */ if (argv[i][j] == 'C') T.boxflag |= 16; /* Want convex box outline */ if (argv[i][j+1] && GMT_getpen (&argv[i][j+1], &T.boxpen)) { fprintf (stderr, "%s: GMT SYNTAX ERROR -W option: Give pen after o\n", GMT_program); error++; } argv[i][j] = 0; } if (argv[i][2] && isdigit ((int)argv[i][2])) { /* Also gave fill */ if (GMT_getfill (&argv[i][2], &T.boxfill)) { GMT_fill_syntax ('W'); error++; } T.boxflag |= 2; } if (!(T.boxflag | 31)) { fprintf (stderr, "%s: GMT SYNTAX ERROR -W option: Must give arguments\n", GMT_program); error++; } break; case 'Z': if (argv[i][2]) { new_z_level = atof (&argv[i][2]); set_z = TRUE; } break; /* Options not recognized */ default: error = TRUE; GMT_default_error (argv[i][1]); break; } } else n_files++; } if (argc == 1 || GMT_quick) { fprintf (stderr, "pstext %s - To plot text on maps\n\n", GMT_VERSION); fprintf (stderr, "usage: pstext -J -R///\n"); fprintf (stderr, "\t[-B] [-C/] [-D[j]/[v[]] [-Eaz/el] [-G]\n"); fprintf (stderr, "\t[-H[]] [-K] [-L] [-M[]] [-N] [-O] [-P] [-S] [-U] [-V] [-W[][o|O|c[]]]\n"); fprintf (stderr, "\t[-X] [-Y] [-Z] [-c] [-:]\n\n"); fprintf (stderr, "\tReads (x,y,size,angle,fontno,justify,text) from [or stdin]\n"); fprintf (stderr, "\tOR (with -M) one or more text paragraphs with formatting info in the segment header.\n"); fprintf (stderr, "\tjustify is of the form [T|M|B][L|C|R] (top/middle/bottom/left/center/right)\n"); fprintf (stderr, "\tBuilt-in escape sequences:\n"); fprintf (stderr, "\t @~ toggles between current font and Symbol font\n"); fprintf (stderr, "\t @%%%% switches to font number ; @%%%% resets font\n"); fprintf (stderr, "\t @+ toggles between normal and superscript mode\n"); fprintf (stderr, "\t @- toggles between normal and subscript mode\n"); fprintf (stderr, "\t @# toggles between normal and Small Caps mode\n"); fprintf (stderr, "\t @! makes one composite character\n"); fprintf (stderr, "\t @@ prints the @ sign itself\n"); fprintf (stderr, "\t @e, @o, @a, @E, @O, @A give the accented Scandinavian characters\n"); fprintf (stderr, "\t In addition, paragraph text (-M) also understands these sequences:\n"); fprintf (stderr, "\t @:: switches font size; @:: resets font size\n"); fprintf (stderr, "\t @;; switches font color; @;; resets font color\n"); fprintf (stderr, "\t @_ toggles between normal and underlined text\n"); fprintf (stderr, "\t(See manual page for more information)\n"); if (list) { /* List fonts */ fprintf (stderr, "\n\tFont # Font Name\n"); fprintf (stderr, "\t------------------------------------\n"); for (i = 0; i < N_FONTS; i++) fprintf (stderr, "\t%3d\t%s\n", i, GMT_font_name[i]); } if (GMT_quick) exit (EXIT_FAILURE); GMT_explain_option ('j'); GMT_explain_option ('R'); fprintf (stderr, "\n\tOPTIONS:\n"); GMT_explain_option ('b'); fprintf (stderr, "\t-C sets the clearance between characters and surrounding box [0.05i/0.05i]\n"); fprintf (stderr, "\t Only used if -W has been set\n"); fprintf (stderr, "\t-D adds , to the text origin AFTER projecting with -J. [0/0]\n"); fprintf (stderr, "\t Use -Dj to move text origin away from point (direction determined by text's justification)\n"); fprintf (stderr, "\t Append v[] to draw line from text to original point (-M only)\n"); fprintf (stderr, "\t-E set azimuth and elevation of viewpoint for 3-D perspective [180/90]\n"); fprintf (stderr, "\t-G set the color (red/green/blue (0-255)) for solid text [0/0/0]\n"); GMT_explain_option ('H'); GMT_explain_option ('K'); GMT_explain_option ('M'); fprintf (stderr, "\t Expects (x y size angle fontno justify linespace parwidth parjust) in segment header\n"); fprintf (stderr, "\t followed by lines with one or more paragraphs of text.\n"); fprintf (stderr, "\t parjust is one of (l)eft, (c)enter, (r)ight, or (j)ustified.\n"); fprintf (stderr, "\t-N Do Not clip text that exceeds the map boundaries [Default will clip]\n"); GMT_explain_option ('O'); GMT_explain_option ('P'); fprintf (stderr, "\t-S draw outline of characters. Append pen attributes\n"); GMT_explain_option ('U'); GMT_explain_option ('V'); fprintf (stderr, "\t-W paints and outlines a rectangle underneath the text. [Default is no rectangle]\n"); fprintf (stderr, "\t Append fill color [none]. To draw outline, append o, O, or c, and optionally a pen [No outline]\n"); fprintf (stderr, "\t Lower case o will draw rectangular outline\n"); fprintf (stderr, "\t Upper case O will draw rectangle with rounded corners (-M only)\n"); fprintf (stderr, "\t Lower case c will draw concave rectangle (-M only)\n"); fprintf (stderr, "\t Upper case C will draw convex rectangle (-M only)\n"); GMT_explain_option ('X'); fprintf (stderr, "\t-Z For 3-D plots: Set the z-level of map [0]\n"); GMT_explain_option ('c'); GMT_explain_option (':'); GMT_explain_option ('.'); exit (EXIT_FAILURE); } /* Check that the options selected are mutually consistant */ if (T.x_space < 0.0 || T.y_space < 0.0) { fprintf (stderr, "%s: GMT SYNTAX ERROR -C option: clearances cannot be negative!\n", GMT_program); error++; } if (T.x_space == 0.0 && T.y_space == 0.0 && (T.boxflag & 4)) { fprintf (stderr, "%s: Warning: -WO requires a nonzero -C\n", GMT_program); error++; } if (T.x_space == 0.0 && T.y_space == 0.0 && (T.boxflag & 8 || T.boxflag & 16)) { fprintf (stderr, "%s: Warning: -Wc|C requires a nonzero -C\n", GMT_program); error++; } if ((T.boxflag & 32) && !do_paragraphs) { fprintf (stderr, "%s: Warning: -Dv only applies to -M\n", GMT_program); error++; } if (!(z_project.view_azimuth == 180.0 && z_project.view_elevation == 90.0) && do_paragraphs) { fprintf (stderr, "%s: -E not implemented with -M yet\n", GMT_program); error++; } if (T.x_offset == 0.0 && T.y_offset == 0.0 && (T.boxflag & 32)) { fprintf (stderr, "%s: Warning: -Dv requires one nonzero \n", GMT_program); error++; } if (z_project.view_azimuth > 360.0 || z_project.view_elevation <= 0.0 || z_project.view_elevation > 90.0) { fprintf (stderr, "%s: GMT SYNTAX ERROR -E option: Enter azimuth in 0-360 range, elevation in 0-90 range\n", GMT_program); error++; } if (!project_info.region_supplied) { fprintf (stderr, "%s: GMT SYNTAX ERROR: Must specify -R option\n", GMT_program); error++; } if (error) exit (EXIT_FAILURE); GMT_put_history (argc, argv); /* Update .gmtcommands */ add = !(T.x_offset == 0.0 && T.y_offset == 0.0); if (add && offset_outward) T.boxflag |= 64; if (n_files > 0) nofile = FALSE; else n_files = 1; n_args = (argc > 1) ? argc : 2; GMT_map_setup (west, east, south, north); ps_plotinit (CNULL, gmtdefs.overlay, gmtdefs.page_orientation, gmtdefs.x_origin, gmtdefs.y_origin, gmtdefs.global_x_scale, gmtdefs.global_y_scale, gmtdefs.n_copies, gmtdefs.dpi, GMT_INCH, gmtdefs.paper_width, gmtdefs.page_rgb, GMT_epsinfo (argv[0])); GMT_echo_command (argc, argv); if (gmtdefs.unix_time) GMT_timestamp (argc, argv); if (project_info.three_D) ps_transrotate (-z_project.xmin, -z_project.ymin, 0.0); if (set_z) { project_info.z_level = new_z_level; GMT_z_to_zz (new_z_level, &z_level); } GMT_setpen (&T.txtpen); if (clip) GMT_map_clip_on (GMT_no_rgb, 3); last_font = 0; ix = (gmtdefs.xy_toggle); iy = 1 - ix; /* if (draw_box && project_info.three_D) draw_box = FALSE; */ /* Not implemented yet */ /* Mark used fonts */ if (gmtdefs.want_euro_font) { memset ((void *)use_font, 0, (size_t)(N_FONTS * sizeof (int))); if (gmtdefs.unix_time) use_font[0] = use_font[1] = TRUE; use_font[gmtdefs.anot_font] = TRUE; if (frame_info.header[0]) use_font[gmtdefs.header_font] = TRUE; if (frame_info.label[0][0] || frame_info.label[1][0] || frame_info.label[2][0]) use_font[gmtdefs.label_font] = TRUE; } if (do_paragraphs) { n_alloc = GMT_CHUNK; word = (char **) GMT_memory (VNULL, n_alloc, sizeof (char), GMT_program); } old_GMT_world_map = GMT_world_map; GMT_world_map = TRUE; for (fno = 1; !done && fno < n_args; fno++) { /* Loop over all input files */ if (!nofile && argv[fno][0] == '-') continue; if (nofile) { fp = GMT_stdin; done = TRUE; } else if ((fp = fopen (argv[fno], "r")) == NULL) { fprintf (stderr, "psxy: Cannot open file %s\n", argv[fno]); continue; } if (!nofile && gmtdefs.verbose) fprintf (stderr, "pstext: Working on file %s\n", argv[fno]); if (gmtdefs.io_header) for (i = 0; i < gmtdefs.n_header_recs; i++) fgets (line, BUFSIZ, fp); while (fgets (line, BUFSIZ, fp)) { if (line[0] == '\0' || (line[0] == '#' && GMT_io.EOF_flag != '#')) continue; /* Skip blank lines or # comments */ if (do_paragraphs) { /* Paragraph mode */ if (line[0] == GMT_io.EOF_flag) { skip_text_records = FALSE; if (n_processed) { /* Must output what we got */ GMT_putwords (plot_x, plot_y, word, n_words, &T); n_processed = n_words = 0; n_paragraphs++; } nscan = sscanf (&line[2], "%s %s %d %lf %s %s %s %s %c\n", txt_x, txt_y, &T.font_size, &T.paragraph_angle, this_font, just_key, txt_a, txt_b, &pjust); if (!(GMT_scanf (txt_x, &xy[ix]) && GMT_scanf (txt_y, &xy[iy]))) { fprintf (stderr, "%s: Record %d had bad x and/or y coordinates, must exit)\n", GMT_program, n_read); exit (EXIT_FAILURE); } if (nscan != 9) { fprintf (stderr, "%s: Record %d had incomplete paragraph information, must exit)\n", GMT_program, n_read); exit (EXIT_FAILURE); } GMT_geo_to_xy (xy[0], xy[1], &plot_x, &plot_y); if (clip) { skip_text_records = TRUE; /* If this record should be skipped we must skip the whole paragraph */ GMT_map_outside (xy[0], xy[1]); if ( abs (GMT_x_status_new) > 1 || abs (GMT_y_status_new) > 1) continue; skip_text_records = FALSE; /* Since we got here we do not want to skip */ } T.text_justify = (int)pjust; T.block_justify = (isdigit ((int)just_key[0])) ? atoi (just_key) : GMT_just_decode (just_key); if (T.block_justify == -99) { fprintf (stderr, "%s: Record %d had bad justification info (set to LB)\n", GMT_program, n_read); T.block_justify = 1; } if (this_font[0] >= '0' && this_font[0] <= '9') /* Gave a font # */ T.paragraph_font = atoi (this_font); else { /* Gave a font name */ T.paragraph_font = GMT_key_lookup (this_font, GMT_font_name, N_FONTS); if (T.paragraph_font == N_FONTS) { fprintf (stderr, "%s: Record %d had bad font (set to %s (0))\n", GMT_program, n_read, GMT_font_name[0]); T.paragraph_font = 0; } } if (!use_font[T.paragraph_font] && gmtdefs.want_euro_font) { /* Must reencode this font */ ps_def_euro_font (T.paragraph_font); use_font[T.paragraph_font] = TRUE; } T.line_spacing = GMT_convert_units (txt_a, GMT_INCH); T.paragraph_width = GMT_convert_units (txt_b, GMT_INCH); master_record = TRUE; } else { /* Text block record */ if (!master_record) { fprintf (stderr, "%s: Text record line %d not preceeded by paragraph information, must exit)\n", GMT_program, n_read); exit (EXIT_FAILURE); } line[strlen(line)-1] = 0; if (line[0] == 0) { /* Blank line */ word[n_words] = (char *) GMT_memory (VNULL, (size_t)(1), sizeof (char), GMT_program); n_words++; if ((size_t)n_words == n_alloc) { n_alloc += GMT_CHUNK; word = (char **) GMT_memory (VNULL, n_alloc, sizeof (char *), GMT_program); } } p = strtok (line, " "); while (p) { word[n_words] = (char *) GMT_memory (VNULL, (size_t)(strlen(p)+1), sizeof (char), GMT_program); strcpy (word[n_words], p); n_words++; if ((size_t)n_words == n_alloc) { n_alloc += GMT_CHUNK; word = (char **) GMT_memory (VNULL, n_alloc, sizeof (char *), GMT_program); } p = strtok (NULL, " "); } n_processed++; } n_read++; } else { /* Old-style pstext input */ if (skip_text_records) continue; /* Skip all records for this paragraph */ nscan = sscanf (line, "%s %s %d %lf %s %s %[^\n]\n", txt_x, txt_y, &T.font_size, &T.paragraph_angle, this_font, just_key, text); if (!(GMT_scanf (txt_x, &xy[ix]) && GMT_scanf (txt_y, &xy[iy]))) { fprintf (stderr, "%s: Record %d had bad x and/or y coordinates, must exit)\n", GMT_program, n_read); exit (EXIT_FAILURE); } if (nscan != 7) { fprintf (stderr, "%s: Record %d is incomplete (skipped)\n", GMT_program, n_read); continue; } n_read++; GMT_geo_to_xy (xy[0], xy[1], &plot_x, &plot_y); if (clip) { GMT_map_outside (xy[0], xy[1]); if ( abs (GMT_x_status_new) > 1 || abs (GMT_y_status_new) > 1) continue; } T.block_justify = (isdigit ((int)just_key[0])) ? atoi (just_key) : GMT_just_decode (just_key); if (T.block_justify == -99) { fprintf (stderr, "%s: Record %d had bad justification info (skipped)\n", GMT_program, n_read); continue; } if (add) { if (offset_outward) { /* Smart offset according to justification (from Dave Huang) */ switch (T.block_justify & 3) { case 1: plot_x += T.x_offset; break; case 3: plot_x -= T.x_offset; break; } switch (T.block_justify >> 2) { case 0: plot_y += T.y_offset; break; case 2: plot_y -= T.y_offset; break; } } else { /* Default hard offset */ plot_x += T.x_offset; plot_y += T.y_offset; } } if (this_font[0] >= '0' && this_font[0] <= '9') /* Gave a font # */ T.paragraph_font = atoi (this_font); else { /* Gave a font name */ T.paragraph_font = GMT_key_lookup (this_font, GMT_font_name, N_FONTS); if (T.paragraph_font == N_FONTS) { fprintf (stderr, "%s: Record %d had bad font (set to %s (0))\n", GMT_program, n_read, GMT_font_name[0]); T.paragraph_font = 0; } } n_paragraphs++; if (T.paragraph_font != last_font) { ps_setfont (T.paragraph_font); last_font = T.paragraph_font; } if (!use_font[T.paragraph_font] && gmtdefs.want_euro_font) { /* Must reencode this font */ ps_def_euro_font (T.paragraph_font); use_font[T.paragraph_font] = TRUE; } if (T.boxflag) { GMT_setpen (&T.boxpen); GMT_textbox3d (plot_x, plot_y, z_level, T.font_size, T.paragraph_font, text, T.paragraph_angle, T.block_justify, (T.boxflag & 1), T.x_space, T.y_space, T.boxfill.rgb); GMT_setpen (&T.txtpen); } if (outline) { GMT_setpen (&T.txtpen); GMT_text3d (plot_x, plot_y, z_level, T.font_size, T.paragraph_font, text, T.paragraph_angle, T.block_justify, TRUE); } if (solid) { ps_setpaint (T.txtfill.rgb); GMT_text3d (plot_x, plot_y, z_level, T.font_size, T.paragraph_font, text, T.paragraph_angle, T.block_justify, FALSE); } } } /* Go read next line */ if (do_paragraphs && n_processed) { /* Must output what we got */ GMT_putwords (plot_x, plot_y, word, n_words, &T); n_processed = n_words = 0; n_paragraphs++; } if (fp != GMT_stdin) fclose (fp); } if (do_paragraphs) GMT_free ((void *)word); if (clip) GMT_map_clip_off (); GMT_world_map = old_GMT_world_map; if (frame_info.plot) GMT_map_basemap (); if (project_info.three_D) ps_rotatetrans (z_project.xmin, z_project.ymin, 0.0); ps_plotend (gmtdefs.last_page); if (gmtdefs.verbose) { if (do_paragraphs) fprintf (stderr, "pswords: Plotted %d textblocks\n", n_paragraphs); else fprintf (stderr, "pstext: Plotted %d text-strings\n", n_paragraphs); } GMT_end (argc, argv); } int GMT_just_decode (char *key) { int i, j, k; /* Converts justification info like LL (lower left) to justification indeces */ for (k = 0; k < (int)strlen (key); k++) { switch (key[k]) { case 'b': /* Bottom baseline */ case 'B': j = 0; break; case 'm': /* Middle baseline */ case 'M': j = 4; break; case 't': /* Top baseline */ case 'T': j = 8; break; case 'l': /* Left Justified */ case 'L': i = 1; break; case 'c': /* Center Justified */ case 'C': i = 2; break; case 'r': /* Right Justified */ case 'R': i = 3; break; default: return (-99); } } return (j + i); } void GMT_putwords (double x, double y, char **text, int n_words, struct GMT_TEXT *T) { char *boxpen_texture = CNULL, *vecpen_texture = CNULL; int boxpen_width, boxpen_offset, boxpen_rgb[3]; int vecpen_width, vecpen_offset, vecpen_rgb[3]; int i; boxpen_texture = GMT_convertpen (&T->boxpen, &boxpen_width, &boxpen_offset, boxpen_rgb); vecpen_texture = GMT_convertpen (&T->vecpen, &vecpen_width, &vecpen_offset, vecpen_rgb); ps_words (x, y, text, n_words, T->line_spacing, T->paragraph_width, T->text_justify, T->paragraph_font, T->font_size, T->paragraph_angle, T->txtfill.rgb, T->block_justify, T->boxflag, T->x_offset, T->y_offset, T->x_space, T->y_space, boxpen_width, boxpen_texture, boxpen_offset, boxpen_rgb, vecpen_width, vecpen_texture, vecpen_offset, vecpen_rgb, T->boxfill.rgb); if (boxpen_texture) GMT_free ((void *)boxpen_texture); if (vecpen_texture) GMT_free ((void *)vecpen_texture); for (i = 0; i < n_words; i++) GMT_free ((void *)text[i]); }