/* Hey Emacs this is -*- C -*- * $Id: emf.trm,v 1.42.2.10 2008/12/14 05:16:25 sfeam Exp $ */ /* GNUPLOT - emf.trm */ /*[ * Copyright 1998, 2004 * * Permission to use, copy, and distribute this software and its * documentation for any purpose with or without fee is hereby granted, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. * * Permission to modify the software is granted, but not the right to * distribute the complete modified source code. Modifications are to * be distributed as patches to the released version. Permission to * distribute binaries produced by compiling modified sources is granted, * provided you * 1. distribute the corresponding source modifications from the * released version in the form of a patch file along with the binaries, * 2. add special version identification to distinguish your version * in addition to the base release version number, * 3. provide your name and address as the primary contact for the * support of your modified version, and * 4. retain our contact information in regard to use of the base * software. * Permission to distribute the released version of the source code along * with corresponding source modifications in the form of a patch file is * granted with same provisions 2 through 4 for binary distributions. * * This software is provided "as is" without express or implied warranty * to the extent permitted by applicable law. ]*/ /* * This file is included by ../term.c and ../docs/termdoc.c. * * This terminal driver supports: * Enhanced Metafile Format * * TODO * * HISTORY * * 4.3.1 12-Sep-2008 Ethan A Merritt * - enhanced text mode * - Two variants are here. One uses the TA_UPDATECP mode to track character position. * This works great horizontally, but I could not find a way to introduce a vertical * offset to handle subscripts and superscripts. * - The second variant tracks both x and y by estimating the character width/height. * This causes visible imperfections in the character spacing. * - Rotated enhanced text not yet supported * * 1.0.11 06-Dec-2004 Ethan A Merritt * - implement term->set_color(), term->filled_polygon(), and term->fillbox() * RGB colors supported, but not yet PM3D palettes * 1.0.10 08-Jul-2004 Hans-Bernhard Broeker * - cleaned up to match gnuplot CodeStyle conventions (one line per statement, * even in macro bodies, no meddling with assert()). * - purged K&R definitions * 1.0.9 03-Jun-2004 Stephane Barbaray , Ethan Merritt * - fixed linewidth bug * - all is now really assumed as 1024x768@96dpi, * before it was a mix between 1600x1200@120dpi and 1024x768@96dpi, * so font may now render differently than before... * - pointsize rework (size twice also now) * - HCHAR and VCHAR are more efficiently computed * 1.0.8 06-May-2004 Stephane Barbaray * - fixed to work with MS security patch (kb835732) applied, because MS introduced bugs!!! * - EMR_EXTTEXTOUTW (84) is now EMR_EXTTEXTOUTA (83) * 1.0.7 3-Feb-2003 Ethan A Merritt * - modify text and point color handling to match other terminal types * - FIXME! alignment of rotated text is not correct. * 1.0.6 25-Jul-2002 Ethan A Merritt * - generalized text rotation and justification * 1.0.5 2000/07/20 * - Handles were not freed at all, resulting to resource leaks when viewing on Windows 9x (not on NT4/W2000!!!) * 1.0.4 2000/06/28 * - Emulated dashed vectors are now looking better * - 15 colors * 8 pointstyles = 120 pointtypes * 1.0.3 2000/03/29 * - default font is now Arial 12 * - implemented options (color/mono,dashed/solid,font) * - 15 colors * 5 dashtypes = 75 linetypes * 1.0.2 2000/03/22 * - Polygon and Polyline structures are not working for Windows 9X, I * really don't know why, replaced with lineto/moveto couples... * - Texts are now displayed in GM_Compatible mode because GM_Advanced is * displaying correctly but it does not print correctly with Word97! * - Text centering now works best according to escapement/orientation * - Now there is 8 colors * 5 dashtypes = 40 linetypes * - Successfully Working on Linux Suse 6.1 (x86) * * 1.0.1 2000/03/16 * - Unicode text have be to long aligned in EMF files (exttextoutw) * - Problems with text transparence (SetBkMode was not called) * - Null brush created for *not* filling polygon * * 1.0.0 2000/03/15 * - Only tested on x86 Win32 * * AUTHOR * Stephane Barbaray * Some code based on cgm.trm * * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net). */ #include "driver.h" #ifdef TERM_REGISTER register_term(emf) #endif #ifdef TERM_PROTO TERM_PUBLIC void EMF_options __PROTO((void)); TERM_PUBLIC void EMF_init __PROTO((void)); TERM_PUBLIC void EMF_reset __PROTO((void)); TERM_PUBLIC void EMF_text __PROTO((void)); TERM_PUBLIC void EMF_graphics __PROTO((void)); TERM_PUBLIC void EMF_move __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void EMF_dashed_vector __PROTO((unsigned int ux, unsigned int uy)); TERM_PUBLIC void EMF_solid_vector __PROTO((unsigned int ux, unsigned int uy)); TERM_PUBLIC void EMF_linetype __PROTO((int linetype)); TERM_PUBLIC void EMF_linecolor __PROTO((int color)); TERM_PUBLIC void EMF_dashtype __PROTO((int dashtype)); TERM_PUBLIC void EMF_linewidth __PROTO((double width)); TERM_PUBLIC void EMF_put_text __PROTO((unsigned int x, unsigned int y, const char *str)); TERM_PUBLIC int EMF_text_angle __PROTO((int ang)); TERM_PUBLIC int EMF_justify_text __PROTO((enum JUSTIFY mode)); TERM_PUBLIC void EMF_point __PROTO((unsigned int x, unsigned int y, int number)); TERM_PUBLIC void EMF_set_pointsize __PROTO((double size)); TERM_PUBLIC int EMF_set_font __PROTO((const char *)); TERM_PUBLIC int EMF_make_palette __PROTO((t_sm_palette *palette)); TERM_PUBLIC void EMF_previous_palette __PROTO((void)); TERM_PUBLIC void EMF_set_color __PROTO((t_colorspec *colorspec)); TERM_PUBLIC void EMF_filled_polygon __PROTO((int, gpiPoint *)); TERM_PUBLIC void EMF_fillbox __PROTO((int, unsigned int, unsigned int, unsigned int, unsigned int)); /* Enhanced text support */ TERM_PUBLIC void ENHemf_put_text __PROTO((unsigned int x, unsigned int y, const char *str)); TERM_PUBLIC void ENHemf_OPEN __PROTO((char * fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint)); TERM_PUBLIC void ENHemf_FLUSH __PROTO((void)); #undef RGB #define RGB(r,g,b) ((long) \ (((unsigned char)(r) \ | ((short) ((unsigned char) (g)) << 8)) \ | (((long) (unsigned char) (b)) << 16))) #ifndef GPMIN # define GPMIN(a,b) (a < b ? a : b) #endif #ifndef GPMAX # define GPMAX(a,b) (a > b ? a : b) #endif #define EMF_PX2HM 26.37 #define EMF_PT2HM 35.28 #define EMF_10THDEG2RAD (3.14159265359/1800) #define EMF_XMAX (1024 * EMF_PX2HM) #define EMF_YMAX (768 * EMF_PX2HM) #define EMF_HTIC (EMF_XMAX / 160) #define EMF_VTIC EMF_HTIC #define EMF_FONTNAME "Arial" #define EMF_FONTSIZE 12 #define EMF_HCHAR ((EMF_FONTSIZE * EMF_PT2HM) * 0.6) #define EMF_VCHAR ((EMF_FONTSIZE * EMF_PT2HM) * 1.3) #define EMF_LINE_TYPES 5 /* number of line types we support */ #define EMF_COLORS 15 /* number of colors we support */ #define EMF_POINTS 13 /* number of markers we support */ #define EMF_MAX_SEGMENTS 104 /* maximum # polyline coordinates */ #define EMF_HANDLE_PEN 1 #define EMF_HANDLE_FONT 2 #define EMF_HANDLE_BRUSH 3 #define EMF_HANDLE_MAX 4 #define EMF_STOCK_OBJECT_FLAG ((unsigned long)0x1 << 31) #define EMF_STOCK_OBJECT_WHITE_BRUSH (EMF_STOCK_OBJECT_FLAG + 0x00) #define EMF_STOCK_OBJECT_BLACK_PEN (EMF_STOCK_OBJECT_FLAG + 0x07) #define EMF_STOCK_OBJECT_DEFAULT_FONT (EMF_STOCK_OBJECT_FLAG + 0x0A) #define EMF_write_emr(type, size) { \ EMF_write_long(type); \ EMF_write_long(size); \ emf_record_count++; \ } #define EMF_write_sizel(width, height) { \ EMF_write_long(width); \ EMF_write_long(height); \ } #define EMF_write_points(x, y) { \ EMF_write_short(x); \ EMF_write_short(y); \ } #define EMF_write_pointl(x, y) { \ EMF_write_long(x); \ EMF_write_long(y); \ } #define EMF_write_rectl(left, top, right, bottom) { \ EMF_write_long(left); \ EMF_write_long(top); \ EMF_write_long(right); \ EMF_write_long(bottom); \ } #define EMF_EOF() { \ EMF_write_emr(14, 20); \ EMF_write_long(0); \ EMF_write_long(0x10); \ EMF_write_long(20); \ } #define EMF_SetMapMode(mode) { \ EMF_write_emr(17, 0x0C); \ EMF_write_long(mode); \ } #define EMF_SetWindowExtEx(width, height) { \ EMF_write_emr(9, 0x10); \ EMF_write_sizel(width, height); \ } #define EMF_SetWindowOrgEx(width, height) { \ EMF_write_emr(10, 0x10); \ EMF_write_sizel(width, height); \ } #define EMF_SetViewportExtEx(width, height) { \ EMF_write_emr(11, 0x10); \ EMF_write_sizel(width, height); \ } #define EMF_SetViewportOrgEx(width, height) { \ EMF_write_emr(12, 0x10); \ EMF_write_sizel(width, height); \ } #define EMF_SetTextColor(color) { \ EMF_write_emr(24, 0x0C); \ EMF_write_long(color); \ } #define EMF_MoveToEx(x,y) { \ EMF_write_emr(27, 0x10); \ EMF_write_pointl(x, y); \ } #define EMF_LineTo(x,y) { \ EMF_write_emr(54, 0x10); \ EMF_write_pointl(x, y); \ } #define EMF_CreatePen(handle, type, width, color) { \ EMF_write_emr(38, 0x1C); \ EMF_write_long(handle); \ EMF_write_long(type); \ EMF_write_long(width); \ EMF_write_long(0); \ EMF_write_long(color); \ } #define EMF_CreateBrush(handle, type, color, hatch) { \ EMF_write_emr(39, 0x18); \ EMF_write_long(handle); \ EMF_write_long(type); \ EMF_write_long(color); \ EMF_write_long(hatch); \ } #define EMF_SelectObject(handle) { \ EMF_write_emr(37, 0x0C); \ EMF_write_long(handle); \ } #define EMF_DeleteObject(handle) { \ EMF_write_emr(40, 0x0C); \ EMF_write_long(handle); \ } #define EMF_SetTextAlign(align) { \ EMF_write_emr(22, 0x0C); \ EMF_write_long(align); \ } #define EMF_SetBkMode(mode) { \ EMF_write_emr(18, 0x0C); \ EMF_write_long(mode); \ } #define EMF_SaveDC() { \ EMF_write_emr(33, 0x0C); \ EMF_write_long(0); \ } #define EMF_RestoreDC() { \ EMF_write_emr(34, 0x0C); \ EMF_write_long(1); \ } #endif /* TERM_PROTO */ #ifndef TERM_PROTO_ONLY #ifdef TERM_BODY #include /* for isspace() */ static unsigned int emf_posx; static unsigned int emf_posy; static unsigned int emf_record_count = 0; static unsigned int emf_linetype = 1; static unsigned int emf_dashtype = 0; static unsigned long emf_color = 0L; static unsigned long emf_textcolor = LT_UNDEFINED; static unsigned int emf_colors = EMF_COLORS; static unsigned int emf_polyline[EMF_MAX_SEGMENTS]; /* stored polyline coordinates */ static unsigned int emf_graphics = FALSE; static unsigned int emf_dashed = TRUE; static unsigned int emf_monochrome = FALSE; static double emf_linewidth; /* line width in plot units */ static double emf_linewidth_factor = 1.0; static double emf_dashlength = 1.0; static int emf_coords = 0; /* # polyline coordinates saved */ static char emf_fontname[255] = EMF_FONTNAME; static float emf_fontsize = EMF_FONTSIZE; static enum JUSTIFY emf_justify = LEFT; static char emf_defaultfontname[255] = EMF_FONTNAME; static float emf_defaultfontsize = EMF_FONTSIZE; static int emf_vert_text = 0; /* text orientation -- nonzero for vertical */ static int emf_step_sizes[8]; /* array of currently used dash lengths in plot units */ static int emf_step_index = 0; /* index into emf_step_sizes[] */ static int emf_step = 0; /* amount of current dash not yet drawn, in plot units */ static int emf_tic, emf_tic707, emf_tic866, emf_tic500, emf_tic1241, emf_tic1077, emf_tic621; /* marker dimensions */ static TBOOLEAN emf_tweak = TRUE; /* Empirical hack to adjust character widths */ static void EMF_flush_polyline __PROTO((void)); static void EMF_flush_polygon __PROTO((void)); static void EMF_write_byte __PROTO((int)); static void EMF_write_short __PROTO((int)); static void EMF_write_long __PROTO((unsigned long)); static void EMF_write_float __PROTO((double)); static void EMF_setfont __PROTO((void)); #define ANSI_CHARSET 0 #define DEFAULT_CHARSET 1 #define GREEK_CHARSET 161 #define TURKISH_CHARSET 162 #define BALTIC_CHARSET 186 #define RUSSIAN_CHARSET 204 #define EASTEUROPE_CHARSET 238 #define KOI8_CHARSET 242 /* Text alignment */ #define TA_NOUPDATECP 0x00 #define TA_UPDATECP 0x01 #define TA_LEFT 0x00 #define TA_RIGHT 0x02 #define TA_CENTER 0x06 #define TA_TOP 0x00 #define TA_BOTTOM 0x08 #define TA_BASELINE 0x18 /* ExtTextOut options */ #define ETO_NO_RECT 0x100 #define ETO_PDY 0x2000 static void EMF_setfont() { int i, count; int bold = 400; char italic = 0, underline = 0, strikeout = 0; char font[32]; char *sub; if (!emf_graphics) return; count = GPMIN (strlen(emf_fontname), 31); if (((sub = strstr(emf_fontname, " bold")) != NULL) || ((sub = strstr(emf_fontname, " Bold")) != NULL)) { bold = 700; count = GPMIN(sub - emf_fontname, count); } if (((sub = strstr(emf_fontname, " italic")) != NULL) || ((sub = strstr(emf_fontname, " Italic")) != NULL)) { italic = 1; count = GPMIN(sub - emf_fontname, count); } if (((sub = strstr(emf_fontname, " underline")) != NULL) || ((sub = strstr(emf_fontname, " Underline")) != NULL)) { underline = 1; count = GPMIN(sub - emf_fontname, count); } if (((sub = strstr(emf_fontname, " strikeout")) != NULL) || ((sub = strstr(emf_fontname, " Strikeout")) != NULL) || ((sub = strstr(emf_fontname, " StrikeOut")) != NULL) ) { strikeout = 1; count = GPMIN(sub - emf_fontname, count); } safe_strncpy(font, emf_fontname, count + 1); EMF_SelectObject(EMF_STOCK_OBJECT_DEFAULT_FONT); EMF_DeleteObject(EMF_HANDLE_FONT); /* SB 20040506: was not complete size was 104, now it is 332 */ EMF_write_emr(82, 332); EMF_write_long(EMF_HANDLE_FONT); EMF_write_long((long) (-emf_fontsize * EMF_PT2HM)); /* height */ EMF_write_long(0); /* width */ EMF_write_long(emf_vert_text); /* escapement */ EMF_write_long(emf_vert_text); /* orientation */ EMF_write_long(bold); /* weight */ EMF_write_byte(italic); /* italic */ EMF_write_byte(underline); /* underline */ EMF_write_byte(strikeout); /* strikeout */ /* charset: could be extended? */ switch (encoding) { case S_ENC_CP1250: case S_ENC_ISO8859_2: EMF_write_byte(EASTEUROPE_CHARSET); break; case S_ENC_KOI8_R: case S_ENC_KOI8_U: EMF_write_byte(KOI8_CHARSET); break; default: EMF_write_byte(DEFAULT_CHARSET); } EMF_write_byte(0); /* out precision */ EMF_write_byte(0); /* clip precision */ EMF_write_byte(0); /* quality */ EMF_write_byte(0); /* pitch and family */ for (i = 0; i < 32; i++) { /* face name (max 32) */ EMF_write_byte((char) (i < strlen(font) ? font[i] : 0)); EMF_write_byte(0); } /* SB 20040506: modification following */ for (i = 0; i < 64; i++) { /* FULL face name (max 64) */ EMF_write_byte((char) (i < strlen(font) ? font[i] : 0)); EMF_write_byte(0); } for (i = 0; i < 32; i++) { /* style name (max 32) */ EMF_write_byte(0); EMF_write_byte(0); } EMF_write_long(0); /* version */ EMF_write_long(0); /* Style size */ EMF_write_long(0); /* Match */ EMF_write_long(0); /* reserved */ EMF_write_long(0); /* VendorId */ EMF_write_long(0); /* Culture */ for (i = 0; i < 10; i++) EMF_write_byte(0); /* Panose (ignored) */ EMF_write_byte(0); /* pad (long aligned) */ EMF_write_byte(0); /* pad (long aligned) */ /* SB 20040506: End of modification */ EMF_SelectObject(EMF_HANDLE_FONT); } static void EMF_flush_polygon() { int i = 0; if (emf_coords == 0) return; EMF_MoveToEx(emf_polyline[i++], term->ymax - emf_polyline[i++]); while (i < emf_coords * 2) EMF_LineTo(emf_polyline[i++], term->ymax - emf_polyline[i++]); EMF_LineTo(emf_polyline[0], term->ymax - emf_polyline[1]); emf_coords = 0; } static void EMF_flush_polyline() { if (emf_coords == 0) return; if (emf_coords <= 2) { EMF_MoveToEx(emf_polyline[0], term->ymax - emf_polyline[1]); EMF_LineTo(emf_polyline[2], term->ymax - emf_polyline[3]); } else { int i = 0; #if 0 /* was commented out */ /* Polyline works for NT4 but not on W9x */ EMF_write_emr(4,(7+emf_coords*2)*4); EMF_write_rectl(0,0,0,0); EMF_write_long(emf_coords); while(i < emf_coords*2) EMF_write_pointl(emf_polyline[i++],term->ymax-emf_polyline[i++]); #endif /* 0 */ EMF_MoveToEx(emf_polyline[i++], term->ymax - emf_polyline[i++]); while (i < emf_coords * 2) EMF_LineTo(emf_polyline[i++], term->ymax - emf_polyline[i++]); } emf_coords = 0; } /* HBB 20040708: the following keep K&R argument types for now */ static void EMF_write_byte(int value) { char c = value; fwrite(&c, 1, 1, gpoutfile); } static void EMF_write_short(int value) { short actual_value = value; char c[2]; c[1] = (actual_value >> 8) & 255; /* convert to x86 order */ c[0] = actual_value & 255; fwrite(c, 1, 2, gpoutfile); } static void EMF_write_long(unsigned long value) { char c[4]; c[3] = (value >> 24) & 0xFFL; /* convert to x86 order */ c[2] = (value >> 16) & 0xFFL; c[1] = (value >> 8) & 0xFFL; c[0] = value & 0xFFL; fwrite(c, 1, 4, gpoutfile); } /* FIXME HBB 20001103: this only works as given iff 'float' is the * same format as on x86's, i.e. IEEE 4-byte floating point format */ static void EMF_write_float(double value) { char c[4]; union { long l; float f; } u; u.f = value; c[3] = (u.l >> 24) & 0xFFL; /* convert to x86 order */ c[2] = (u.l >> 16) & 0xFFL; c[1] = (u.l >> 8) & 0xFFL; c[0] = u.l & 0xFFL; fwrite(c, 1, 4, gpoutfile); } TERM_PUBLIC void EMF_options() { char *s; /* Annoying hack to handle the case of 'set termoption' after */ /* we have already initialized the terminal. */ if (c_token != 2) { term->xmax = EMF_XMAX; term->ymax = EMF_YMAX; emf_dashed = TRUE; emf_monochrome = FALSE; emf_tweak = TRUE; } while (!END_OF_COMMAND) { if (almost_equals(c_token, "de$fault")) { strcpy(emf_defaultfontname, EMF_FONTNAME); emf_defaultfontsize = EMF_FONTSIZE; emf_monochrome = FALSE; emf_dashed = TRUE; c_token++; continue; } if (almost_equals(c_token, "m$onochrome")) { emf_monochrome = TRUE; c_token++; continue; } if (almost_equals(c_token, "c$olor") || almost_equals(c_token, "c$olour")) { emf_monochrome = FALSE; c_token++; continue; } if (almost_equals(c_token, "da$shed")) { emf_dashed = TRUE; c_token++; continue; } if (equals(c_token, "dl") || almost_equals(c_token, "dashl$ength")) { struct value a; c_token++; emf_dashlength = real(const_express(&a)); if (emf_dashlength < 0.5) emf_dashlength = 1.0; continue; } if (almost_equals(c_token, "s$olid")) { emf_dashed = FALSE; c_token++; continue; } if (equals(c_token, "lw") || almost_equals(c_token, "linew$idth")) { struct value a; c_token++; emf_linewidth_factor = real(const_express(&a)); if (emf_linewidth_factor < 0.1) emf_linewidth_factor = 1.0; continue; } if (almost_equals(c_token,"enh$anced")) { c_token++; term->put_text = ENHemf_put_text; term->flags |= TERM_ENHANCED_TEXT; continue; } else if (almost_equals(c_token,"noenh$anced")) { c_token++; term->put_text = EMF_put_text; term->flags &= ~TERM_ENHANCED_TEXT; } if (almost_equals(c_token,"nopro$portional")) { c_token++; emf_tweak = FALSE; } if (almost_equals(c_token, "si$ze")) { int tempxmax = 1024; int tempymax = 768; struct value a; c_token++; if (!END_OF_COMMAND) { tempxmax = real(const_express(&a)); if (equals(c_token, ",")) { c_token++; tempymax = real(const_express(&a)); } } if (tempxmax > 0) term->xmax = tempxmax * EMF_PX2HM; if (tempymax > 0) term->ymax = tempymax * EMF_PX2HM; term->h_tic = term->xmax / 160; term->v_tic = term->h_tic; continue; } if (equals(c_token, "font")) c_token++; /* Fall through to old-style bare font name */ if ((s = try_to_get_string())) { char *comma = strrchr(s,','); if (comma && (1 == sscanf(comma+1,"%g",&emf_defaultfontsize))) { *comma = '\0'; } if (*s) strncpy(emf_defaultfontname, s, sizeof(emf_defaultfontname)); free(s); if (isanumber(c_token)) { struct value a; emf_defaultfontsize = (int) real(const_express(&a)); } continue; } break; } /* while(!end of command) */ if (!END_OF_COMMAND) { /* We have old-style bare font size specified */ struct value a; emf_defaultfontsize = (int) real(const_express(&a)); } EMF_set_font(NULL); /* set default font */ emf_colors = emf_monochrome ? 1 : EMF_COLORS; sprintf(term_options, "%s %s \"%s\" %g", emf_monochrome ? "monochrome" : "color", emf_dashed ? "dashed" : "solid", emf_defaultfontname, emf_defaultfontsize); if (term->flags & TERM_ENHANCED_TEXT) strcat(term_options, " enhanced "); if (term->xmax != (int)EMF_XMAX || term->ymax != (int)EMF_YMAX) sprintf(&(term_options[strlen(term_options)]), " size %d,%d ", (int)(0.5+term->xmax/EMF_PX2HM), (int)(0.5+term->ymax/EMF_PX2HM)); if (emf_linewidth_factor != 1.0) sprintf(&(term_options[strlen(term_options)]), " lw %.1f", emf_linewidth_factor); if (emf_dashlength != 1.0) sprintf(&(term_options[strlen(term_options)]), " dashlength %.1f", emf_dashlength); } TERM_PUBLIC void EMF_init() { emf_posx = emf_posy = 0; emf_linetype = 0; emf_vert_text = 0; emf_graphics = FALSE; } TERM_PUBLIC void EMF_graphics() { int width = 0.5 + term->xmax/EMF_PX2HM; int height = 0.5 + term->ymax/EMF_PX2HM; int mmwidth = 0.5 + (term->xmax/EMF_PX2HM) * (270./1024.); int mmheight = 0.5 + (term->ymax/EMF_PX2HM) * (200./768.); /* header start */ emf_record_count = 0; EMF_write_emr(1, 100); EMF_write_long(0); /* rclBounds */ EMF_write_long(0); EMF_write_long(term->xmax / EMF_PX2HM); EMF_write_long(term->ymax / EMF_PX2HM); EMF_write_long(0); /* rclFrame */ EMF_write_long(0); EMF_write_long(term->xmax); EMF_write_long(term->ymax); EMF_write_long(0x464D4520); /* signature */ EMF_write_long(0x00010000); /* version */ EMF_write_long(0); /* nBytes */ EMF_write_long(0); /* nRecords */ EMF_write_short(EMF_HANDLE_MAX); /* nHandles, MUST NOT BE 0 */ EMF_write_short(0); /* reserved */ EMF_write_long(0); /* descSize */ EMF_write_long(0); /* descOff */ EMF_write_long(0); /* nPalEntries */ EMF_write_long(width); /* ref dev pixwidth, default 1024 */ EMF_write_long(height); /* ref dev pixheight, default 768 */ EMF_write_long(mmwidth); /* ref dev mwidth, default 270 */ EMF_write_long(mmheight); /* ref dev mheight, default 200 */ EMF_write_long(0); /* cbPixelFormat */ EMF_write_long(0); /* offPixelFormat */ EMF_write_long(0); /* bOpenGL */ emf_graphics = TRUE; /* header end */ EMF_SetMapMode(8); /* forcing anisotropic mode */ EMF_SetWindowExtEx(term->xmax, term->ymax); /* setting logical (himetric) size */ EMF_SetViewportExtEx(term->xmax / EMF_PX2HM, term->ymax / EMF_PX2HM); /* setting device (pixel) size */ EMF_CreatePen(EMF_HANDLE_PEN, 0, 1, 0x000000); /* init default pen */ EMF_SelectObject(EMF_HANDLE_PEN); EMF_SetBkMode(1); /* transparent background for text */ EMF_CreateBrush(EMF_HANDLE_BRUSH, 1, 0, 0); /* transparent brush for polygons */ EMF_SelectObject(EMF_HANDLE_BRUSH); EMF_set_font(NULL); /* init default font */ } TERM_PUBLIC int EMF_set_font(const char *font) { static float last_fontsize = -1; static char last_fontname[256] = {'\0'}; if (font && *font) { float tempsize; int sep = strcspn(font,","); if (sep > 0) safe_strncpy(emf_fontname, font, GPMIN(sep + 1, 32)); if (sep < strlen(font) && sscanf(font+sep+1, "%f", &tempsize)) emf_fontsize = tempsize; } else { strcpy(emf_fontname, emf_defaultfontname); emf_fontsize = emf_defaultfontsize; } /* Optimization only */ if (!strcmp(last_fontname,emf_fontname) && last_fontsize == emf_fontsize) { return TRUE; } term->h_char = (emf_fontsize * EMF_PT2HM)*0.6; term->v_char = (emf_fontsize * EMF_PT2HM)*1.3; EMF_setfont(); return TRUE; } TERM_PUBLIC void EMF_text() { long pos; EMF_flush_polyline(); /* writing end of metafile */ EMF_SelectObject(EMF_STOCK_OBJECT_DEFAULT_FONT); EMF_DeleteObject(EMF_HANDLE_FONT); EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN); EMF_DeleteObject(EMF_HANDLE_PEN); EMF_SelectObject(EMF_STOCK_OBJECT_WHITE_BRUSH); EMF_DeleteObject(EMF_HANDLE_BRUSH); EMF_EOF(); /* updating header */ pos = ftell(gpoutfile); fseek(gpoutfile, 48, SEEK_SET); EMF_write_long(pos); EMF_write_long(emf_record_count); /* HBB 20010228: have to make known that we're no longer in graphics * status. */ emf_graphics = FALSE; } TERM_PUBLIC void EMF_linetype(int linetype) { /* Note : separating linetype and color would have not been futile, but anyway... */ #if (0) /* Not safe because linetype/color/pen are intermixed */ if (linetype == emf_linetype) return; #endif if (linetype == LT_NODRAW) linetype = LT_BACKGROUND; emf_linetype = linetype; EMF_linecolor(linetype); EMF_dashtype(linetype); } TERM_PUBLIC void EMF_linecolor(int linecolor) { static long GPFAR color_table_data[] = { RGB(255, 0, 0), /* red */ RGB(0, 255, 0), /* green */ RGB(0, 0, 255), /* blue */ RGB(255, 0, 255), /* magenta */ RGB(0, 0, 128), /* dark blue */ RGB(128, 0, 0), /* dark red */ RGB(0, 128, 128), /* dark cyan */ RGB(0, 0, 0), /* black */ RGB(128, 128, 128), /* grey */ RGB(0, 128, 64), /* very dark cyan */ RGB(128, 128, 0), /* dark yellow */ RGB(128, 0, 128), /* dark magenta */ RGB(192, 192, 192), /* light grey */ RGB(0, 255, 255), /* cyan */ RGB(255, 255, 0) /* yellow */ }; if (linecolor == LT_BACKGROUND) emf_color = RGB(255, 255, 255); /* white (background) */ else { linecolor = (linecolor < 0 || emf_monochrome) ? 7 : (linecolor % EMF_COLORS); emf_color = color_table_data[linecolor]; } EMF_flush_polyline(); } TERM_PUBLIC int EMF_make_palette(t_sm_palette *palette) { return 0; /* can do continous colors */ } TERM_PUBLIC void EMF_previous_palette() { /* do nothing */ } TERM_PUBLIC void EMF_set_color(t_colorspec *colorspec) { rgb255_color rgb255; if (colorspec->type == TC_LT) { EMF_linecolor(colorspec->lt); } else if (colorspec->type == TC_FRAC) { rgb255maxcolors_from_gray(colorspec->value, &rgb255); emf_color = RGB(rgb255.r, rgb255.g, rgb255.b); } else if (colorspec->type == TC_RGB) { emf_color = RGB( colorspec->lt >> 16 & 0xff, colorspec->lt >> 8 & 0xff, colorspec->lt & 0xff ); } /* else { fprintf(stderr, "unhandled colorspec type %d\n", colorspec->type); } */ /* Force reevaluation of dash type */ emf_dashtype = LT_UNDEFINED; EMF_dashtype(emf_linetype); } TERM_PUBLIC void EMF_filled_polygon(int points, gpiPoint *corners) { int i; unsigned long color = emf_color; int fillpar = corners->style >> 4; int style = corners->style & 0xf; #define EMF_POLYGON 3 switch (style) { case FS_EMPTY: /* fill with background color */ color = RGB(255,255,255); break; case FS_PATTERN: /* pattern fill implemented as partial density */ fillpar *= 12; case FS_SOLID: /* solid fill */ if (fillpar >= 0 && fillpar < 100) { double density = (double)fillpar / 100.; color = ((int)((double)((emf_color>>16)&0xff)*density) << 16) + ((int)((double)((emf_color>>8)&0xff)*density) << 8) + ((int)((double)(emf_color&0xff)*density)); color += ((int)(255.*(1.-density)) << 16) + ((int)(255.*(1.-density)) << 8) + ((int)(255.*(1.-density))); } break; default: break; } /* Sequence of operations cribbed from Windows example */ EMF_CreateBrush(EMF_HANDLE_BRUSH, 0, color, 0); EMF_SelectObject(EMF_HANDLE_BRUSH); EMF_write_emr(EMF_POLYGON, (7 + 2*points) * 4); EMF_write_rectl(0,0,0,0); /* What are these? */ EMF_write_long(points); for (i=0; iymax - corners[i].y); EMF_DeleteObject(EMF_HANDLE_BRUSH); /* Force re-evaluation of linetype next time we draw a line */ emf_linetype = LT_UNDEFINED; emf_dashtype = LT_UNDEFINED; } TERM_PUBLIC void EMF_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height) { gpiPoint corner[4]; corner[0].x = x1; corner[0].y = y1; corner[1].x = x1+width; corner[1].y = y1; corner[2].x = x1+width; corner[2].y = y1+height; corner[3].x = x1; corner[3].y = y1+height; corner->style = style; EMF_filled_polygon(4, corner); } TERM_PUBLIC void EMF_linewidth(double width) { int current_dashtype = emf_dashtype; width *= emf_linewidth_factor; if (width == emf_linewidth) return; emf_linewidth = width; emf_dashtype = LT_UNDEFINED; /* Invalidate current dash type */ EMF_dashtype(current_dashtype); /* Force re-evaluation of dash type */ } /* * Resets _both_ line color and dash type! */ TERM_PUBLIC void EMF_dashtype(int dashtype) { int i, j; /* Each group of 8 entries in dot_length[] defines a dash pattern. Entries in each group are alternately length of whitespace and length of line, in units of 2/3 of the linewidth. */ static int dot_length[EMF_LINE_TYPES * 8] = { /* 0 - solid */ 5, 8, 5, 8, 5, 8, 5, 8, /* 1 - dashes */ 4, 2, 4, 2, 4, 2, 4, 2, /* 2 - dotted */ 4, 8, 4, 2, 4, 8, 4, 2, /* 3 - dash-dot */ 4, 9, 4, 2, 4, 2, 0, 0, /* 4 - dash-dot-dot */ }; emf_dashtype = dashtype; EMF_flush_polyline(); if (dashtype >= 0) dashtype = (dashtype / emf_colors) % EMF_LINE_TYPES; if (dashtype == LT_AXIS) dashtype = 2; if (dashtype < 1 || !emf_dashed) { /* solid mode */ EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN); EMF_DeleteObject(EMF_HANDLE_PEN); EMF_CreatePen(EMF_HANDLE_PEN, 0, emf_linewidth * EMF_PX2HM, emf_color); EMF_SelectObject(EMF_HANDLE_PEN); term->vector = EMF_solid_vector; } else { /* Since win32 dashed lines works only with 1 pixel linewith we must emulate */ EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN); EMF_DeleteObject(EMF_HANDLE_PEN); EMF_CreatePen(EMF_HANDLE_PEN, 0, emf_linewidth * EMF_PX2HM, emf_color); EMF_SelectObject(EMF_HANDLE_PEN); term->vector = EMF_dashed_vector; /* set up dash dimensions */ j = (dashtype - 1) * 8; for (i = 0; i < 8; i++, j++) { emf_step_sizes[i] = dot_length[j] * emf_dashlength * EMF_PX2HM; } /* first thing drawn will be a line */ emf_step = emf_step_sizes[1]; emf_step_index = 1; } } TERM_PUBLIC void EMF_move(unsigned int x, unsigned int y) { if (x >= term->xmax || y >= term->ymax) { int_warn(NO_CARET, "emf_move: (%d,%d) out of range",x,y); x = GPMIN(x, term->xmax); y = GPMIN(y, term->ymax); } if (x == emf_posx && y == emf_posy) return; EMF_flush_polyline(); emf_posx = x; emf_posy = y; } TERM_PUBLIC void EMF_dashed_vector(unsigned int ux, unsigned int uy) { int xa, ya; int dx, dy, adx, ady; int dist; /* approximate distance in plot units from starting point to specified end point. */ long remain; /* approximate distance in plot units remaining to specified end point. */ if (ux >= term->xmax || uy >= term->ymax) int_warn(NO_CARET, "emf_dashed_vector: (%d,%d) out of range",ux,uy); dx = (ux - emf_posx); dy = (uy - emf_posy); adx = abs(dx); ady = abs(dy * 10); /* using the approximation sqrt(x**2 + y**2) ~ x + (5*x*x)/(12*y) when x > y. Note ordering of calculations to avoid overflow on 16 bit architectures */ if (10 * adx < ady) dist = (ady / 2 + 25 * adx / ady * adx / 6 * 5) / 5; else { if (adx == 0) return; dist = (adx * 10 + (ady / 24) * (ady / adx)) / 10; } remain = dist; xa = emf_posx; ya = emf_posy; while (remain > emf_step) { remain -= emf_step; if (emf_step_index & 1) EMF_solid_vector((int) (ux - (remain * dx) / dist), (int) (uy - (remain * dy) / dist)); else { xa = (int) (ux - (remain * dx) / dist); ya = (int) (uy - (remain * dy) / dist); EMF_move(xa, ya); } if (++emf_step_index >= 8) emf_step_index = 0; emf_step = emf_step_sizes[emf_step_index]; } if (emf_step_index & 1) EMF_solid_vector(ux, uy); else EMF_move(ux, uy); emf_step -= (int) remain; } TERM_PUBLIC void EMF_solid_vector(unsigned int ux, unsigned int uy) { if (ux >= term->xmax || uy >= term->ymax) int_warn(NO_CARET, "emf_solid_vector: (%d,%d) out of range",ux,uy); if (ux == emf_posx && uy == emf_posy) return; if (emf_coords * 2 > EMF_MAX_SEGMENTS - 2) EMF_flush_polyline(); if (emf_coords == 0) { emf_polyline[0] = emf_posx; emf_polyline[1] = emf_posy; emf_coords++; } emf_posx = emf_polyline[emf_coords * 2] = ux; emf_posy = emf_polyline[emf_coords * 2 + 1] = uy; emf_coords++; } TERM_PUBLIC void EMF_put_text(unsigned int x, unsigned int y, const char str[]) { int i, len = strlen(str); EMF_flush_polyline(); if (emf_textcolor != emf_color) { EMF_SetTextColor(emf_color); /* since text doesn't use pens, we must initialize with this */ emf_textcolor = emf_color; } /* SB 20040506: offset array now included since it won't work with MS Security patch (kb835732) */ /* SB 20040506: also changed function from unicode to ansi version */ if (len % 4) len += 4 - (len % 4); /* Structure must be long aligned! */ EMF_write_emr(83, 76 + len + strlen(str)*4);/* ExtTextOutA, ANSI char version! */ EMF_write_rectl(0, 0, 0, 0); /* bounding, never used */ EMF_write_long(1); /* GM_Compatible mode for advanced scaling */ EMF_write_float(EMF_PX2HM); /* x scale */ EMF_write_float(EMF_PX2HM); /* y scale */ /* positioning... y is recentered from bottom reference set in * text align */ EMF_write_pointl( x + (long) ((EMF_VCHAR / 2) * sin(emf_vert_text * EMF_10THDEG2RAD)), term->ymax - y + (long) (EMF_VCHAR / 2 * cos(emf_vert_text * EMF_10THDEG2RAD))); EMF_write_long(strlen(str)); /* real char size */ EMF_write_long(76); /* offset to text */ EMF_write_long(0); /* options, none */ EMF_write_rectl(0, 0, 0, 0); /* rectangle clipping not used */ EMF_write_long(0); /* offset to intercharacter spacing array, can't be used since really we don't know anything about the face properties used */ for (i = 0; i < len; i++) EMF_write_byte(istyle = FS_OPAQUE; EMF_flush_polyline(); old_dashtype = emf_dashtype; EMF_dashtype(0); /* if (number < 0)*/ { /* draw dot */ EMF_move(x, y); EMF_solid_vector(x + 1, y); /* goto end_points;*/ } number = number % EMF_POINTS; switch (number) { case 0: /* draw plus */ EMF_move(x - emf_tic, y); EMF_solid_vector(x + emf_tic, y); EMF_move(x, y - emf_tic); EMF_solid_vector(x, y + emf_tic); break; case 1: /* draw X */ EMF_move(x - emf_tic707, y - emf_tic707); EMF_solid_vector(x + emf_tic707, y + emf_tic707); EMF_move(x - emf_tic707, y + emf_tic707); EMF_solid_vector(x + emf_tic707, y - emf_tic707); break; case 2: /* draw star (asterisk) */ EMF_move(x, y - emf_tic); EMF_solid_vector(x, y + emf_tic); EMF_move(x + emf_tic866, y - emf_tic500); EMF_solid_vector(x - emf_tic866, y + emf_tic500); EMF_move(x + emf_tic866, y + emf_tic500); EMF_solid_vector(x - emf_tic866, y - emf_tic500); break; case 3: /* draw box */ EMF_move(x - emf_tic707, y - emf_tic707); EMF_solid_vector(x + emf_tic707, y - emf_tic707); EMF_solid_vector(x + emf_tic707, y + emf_tic707); EMF_solid_vector(x - emf_tic707, y + emf_tic707); EMF_flush_polygon(); break; case 4: /* draw filled box */ corners[0].x = x - emf_tic707; corners[0].y = y - emf_tic707; corners[1].x = x + emf_tic707; corners[1].y = y - emf_tic707; corners[2].x = x + emf_tic707; corners[2].y = y + emf_tic707; corners[3].x = x - emf_tic707; corners[3].y = y + emf_tic707; EMF_filled_polygon(4, corners); break; case 5: /* draw circle (actually, dodecagon) (WinWord 6 accepts the * CGM "circle" element, but the resulting circle is not * correctly centered!) */ EMF_move(x, y - emf_tic); EMF_solid_vector(x + emf_tic500, y - emf_tic866); EMF_solid_vector(x + emf_tic866, y - emf_tic500); EMF_solid_vector(x + emf_tic, y); EMF_solid_vector(x + emf_tic866, y + emf_tic500); EMF_solid_vector(x + emf_tic500, y + emf_tic866); EMF_solid_vector(x, y + emf_tic); EMF_solid_vector(x - emf_tic500, y + emf_tic866); EMF_solid_vector(x - emf_tic866, y + emf_tic500); EMF_solid_vector(x - emf_tic, y); EMF_solid_vector(x - emf_tic866, y - emf_tic500); EMF_solid_vector(x - emf_tic500, y - emf_tic866); EMF_flush_polygon(); break; case 6: /* filled circle */ corners [0].x = x ; corners [0].y = y - emf_tic; corners [1].x = x + emf_tic500; corners [1].y = y - emf_tic866; corners [2].x = x + emf_tic866; corners [2].y = y - emf_tic500; corners [3].x = x + emf_tic ; corners [3].y = y; corners [4].x = x + emf_tic866; corners [4].y = y + emf_tic500; corners [5].x = x + emf_tic500; corners [5].y = y + emf_tic866; corners [6].x = x ; corners [6].y = y + emf_tic; corners [7].x = x - emf_tic500; corners [7].y = y + emf_tic866; corners [8].x = x - emf_tic866; corners [8].y = y + emf_tic500; corners [9].x = x - emf_tic ; corners [9].y = y; corners[10].x = x - emf_tic866; corners[10].y = y - emf_tic500; corners[11].x = x - emf_tic500; corners[11].y = y - emf_tic866; EMF_filled_polygon(12, corners); break; case 7: /* draw triangle (point up) */ EMF_move(x, y + emf_tic1241); EMF_solid_vector(x - emf_tic1077, y - emf_tic621); EMF_solid_vector(x + emf_tic1077, y - emf_tic621); EMF_flush_polygon(); break; case 8: /* filled triangle point up */ corners[0].x = x ; corners[0].y = y + emf_tic1241; corners[1].x = x - emf_tic1077 ; corners[1].y = y - emf_tic621; corners[2].x = x + emf_tic1077 ; corners[2].y = y - emf_tic621; EMF_filled_polygon(3, corners); break; case 9: /* draw triangle (point down) */ EMF_move(x, y - emf_tic1241); EMF_solid_vector(x - emf_tic1077, y + emf_tic621); EMF_solid_vector(x + emf_tic1077, y + emf_tic621); EMF_flush_polygon(); break; case 10: /* filled triangle point down */ corners[0].x = x ; corners[0].y = y - emf_tic1241; corners[1].x = x - emf_tic1077 ; corners[1].y = y + emf_tic621; corners[2].x = x + emf_tic1077 ; corners[2].y = y + emf_tic621; EMF_filled_polygon(3, corners); break; case 11: /* draw diamond */ EMF_move(x - emf_tic, y); EMF_solid_vector(x, y - emf_tic); EMF_solid_vector(x + emf_tic, y); EMF_solid_vector(x, y + emf_tic); EMF_flush_polygon(); break; case 12: /* filled diamond */ corners[0].x = x - emf_tic ; corners[0].y = y; corners[1].x = x ; corners[1].y = y - emf_tic; corners[2].x = x + emf_tic ; corners[2].y = y; corners[3].x = x ; corners[3].y = y + emf_tic; EMF_filled_polygon(4, corners); break; } /* end_points: */ EMF_dashtype(old_dashtype); } TERM_PUBLIC void EMF_set_pointsize(double size) { if (size < 0) size = 1; emf_tic = (size * term->h_tic); emf_tic707 = emf_tic * 12 / 17; emf_tic866 = emf_tic * 13 / 15; emf_tic500 = emf_tic / 2; emf_tic1241 = emf_tic * 36 / 29; emf_tic1077 = emf_tic * 14 / 13; emf_tic621 = emf_tic * 18 / 29; } /* * Ethan A Merritt September 2008 * - Support for enhanced text mode * PROBLEMS: * - Rotated enhanced text is not handled * - The proportional spacing hack is really ugly * ETO_PDY is supposed to handle this, but pre-Vista Windows * doesn't support the flag so it's of no real use. */ static TBOOLEAN ENHemf_opened_string; /* used in determining height of processed text */ static float ENHemf_base; /* use these so that we don't over-write the current font settings */ static float ENHemf_fontsize; static char *ENHemf_font; static TBOOLEAN ENHemf_show = TRUE; static int ENHemf_overprint = 0; TERM_PUBLIC void ENHemf_OPEN( char *fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint) { /* If the overprint code requests a save or restore, that's all we do */ #define EMF_AVG_WID 0.8 #undef TA_UPDATECP_MODE #ifdef TA_UPDATECP_MODE if (overprint == 3) { EMF_SaveDC(); return; } else if (overprint == 4) { EMF_RestoreDC(); return; } #else static int save_x, save_y; if (overprint == 3) { save_x = emf_posx; save_y = emf_posy; return; } else if (overprint == 4) { emf_posx = save_x; emf_posy = save_y; return; } #endif if (!ENHemf_opened_string) { ENHemf_opened_string = TRUE; enhanced_cur_text = &enhanced_text[0]; ENHemf_font = fontname; ENHemf_fontsize = fontsize; ENHemf_base = base; ENHemf_show = showflag; ENHemf_overprint = overprint; } } /* Write a string fragment and update the current position */ TERM_PUBLIC void ENHemf_FLUSH() { unsigned int x, y; char *str; int i; int incr_x; double strl; if (ENHemf_opened_string) { *enhanced_cur_text = '\0'; ENHemf_opened_string = FALSE; x = emf_posx; y = emf_posy; FPRINTF((stderr,"ENHemf_FLUSH: Write string \"%s\" len %d at %g with font %s,%g\n", enhanced_text,strlen(enhanced_text), (double)x/EMF_PX2HM,ENHemf_font,ENHemf_fontsize)); if (1) { char save_font[256]; float save_fontsize = emf_fontsize; strcpy(save_font,emf_fontname); emf_fontsize = ENHemf_fontsize; EMF_set_font(ENHemf_font); emf_fontsize = save_fontsize; strcpy(emf_fontname,save_font); } /* Don't know how to do a pure move; instead write in white */ if (!ENHemf_show) { EMF_SetTextColor(0xffffff); emf_textcolor = 0xffffff; } else if (ENHemf_show && emf_textcolor != emf_color) { EMF_SetTextColor(emf_color); emf_textcolor = emf_color; } str = enhanced_text; #ifndef TA_UPDATEPC_MODE /* We are especially bad at guessing the width of whitespace. */ /* Best is to pile up all our errors on top of leading space. */ i = strspn(enhanced_text," "); if (i > 0) { x += i * term->h_char * EMF_AVG_WID * ENHemf_fontsize/emf_defaultfontsize; emf_posx = x; str += i; } #endif /* Copied from put_text(). Is all this really necessary? */ { int record_length; int len = strlen(str); if (len % 4) len += 4 - (len % 4); /* Structure must be long aligned! */ record_length = 76 + len + strlen(str)*4; EMF_write_emr(83, record_length);/* ExtTextOutA, ANSI char version! */ EMF_write_rectl(0, 0, 0, 0); /* bounding, never used */ EMF_write_long(1); /* GM_Compatible mode for advanced scaling */ EMF_write_float(EMF_PX2HM); /* x scale */ EMF_write_float(EMF_PX2HM); /* y scale */ if (emf_vert_text == 0) { /* x,y position (ignored if TA_UPDATECP) */ float yo = 1.3 * EMF_PX2HM * ENHemf_base; EMF_write_pointl( x, term->ymax - (y + yo)); } else { float a = emf_vert_text * EMF_10THDEG2RAD; float yo = 1.3 * EMF_PX2HM * ENHemf_base; EMF_write_pointl( x - (long) (yo * sin(a)), term->ymax - (long) (y + (yo * cos(a))) ); } EMF_write_long(strlen(str)); /* true number of characters */ EMF_write_long(76); /* offset to text */ EMF_write_long(ETO_NO_RECT); /* ExtTextOut options */ EMF_write_rectl(0, 0, 0, 0); /* bounding, never used */ EMF_write_long(0); /* offset to intercharacter spacing array */ for (i = 0; i < len; i++) EMF_write_byte(i",str[i])) wide++; if('i' == str[i]) thin++; } incr_x = (strl * EMF_AVG_WID + (double)(wide-thin) * 0.2) * term->h_char; } } else { incr_x = strl * EMF_AVG_WID * term->h_char; } /* Attempt to handle slanted text. Not entirely successful */ emf_posx += incr_x * cos(emf_vert_text * EMF_10THDEG2RAD); emf_posy += incr_x * sin(emf_vert_text * EMF_10THDEG2RAD); if (ENHemf_overprint == 1) emf_posx -= strlen(str) * term->h_char * (0.5) * EMF_AVG_WID * ENHemf_fontsize/emf_defaultfontsize; } } TERM_PUBLIC void ENHemf_put_text(unsigned int x, unsigned int y, const char *str) { int tmp_justify = emf_justify; int len; if (ignore_enhanced_text) { EMF_put_text(x,y,str); return; } if (!strlen(str)) return; len = estimate_strlen((char *)str); /* if there are no magic characters, we should just be able * punt the string to EMF_put_text() */ if (!strpbrk(str, "{}^_@&~")) { /* FIXME: do something to ensure default font is selected */ EMF_put_text(x,y,str); return; } if (emf_textcolor != emf_color) { EMF_SetTextColor(emf_color); emf_textcolor = emf_color; } /* set up the global variables needed by enhanced_recursion() */ enhanced_fontscale = 1.0; strncpy(enhanced_escape_format,"&#x%2.2x;",sizeof(enhanced_escape_format)); ENHemf_opened_string = FALSE; ENHemf_show = TRUE; ENHemf_overprint = 0; /* EAM - post.trm wasn't doing this, but how else do they get initialized? */ ENHemf_font = emf_fontname; ENHemf_fontsize = emf_fontsize; if (emf_justify == RIGHT) { EMF_MoveToEx(x - term->h_char * len, term->ymax-y); EMF_move(x - EMF_AVG_WID * term->h_char * len, y); } else if (emf_justify == CENTRE) { EMF_MoveToEx(x - term->h_char * len/2, term->ymax-y); EMF_move(x - EMF_AVG_WID * term->h_char * len/2, y); } else { EMF_MoveToEx(x, term->ymax-y); EMF_move(x, y); } emf_justify = LEFT; #ifdef UPDATECP_MODE EMF_SetTextAlign(TA_BASELINE|TA_LEFT|TA_UPDATECP); #else EMF_SetTextAlign(TA_BASELINE|TA_LEFT|TA_NOUPDATECP); #endif /* Set the recursion going. We say to keep going until a * closing brace, but we don't really expect to find one. * If the return value is not the nul-terminator of the * string, that can only mean that we did find an unmatched * closing brace in the string. We increment past it (else * we get stuck in an infinite loop) and try again. */ while (*(str = enhanced_recursion((char *)str, TRUE, ENHemf_font, ENHemf_fontsize, 0.0, TRUE, TRUE, 0))) { (term->enhanced_flush)(); /* I think we can only get here if *str == '}' */ enh_err_check(str); if (!*++str) break; /* end of string */ /* else carry on and process the rest of the string */ } /* Restore everything we messed with */ emf_justify = tmp_justify; EMF_setfont(); /* Necessary? */ } #endif /* TERM_BODY */ #ifdef TERM_TABLE TERM_TABLE_START(emf_driver) "emf", "Enhanced Metafile format", EMF_XMAX, EMF_YMAX, EMF_VCHAR, EMF_HCHAR, EMF_VTIC, EMF_HTIC, EMF_options, EMF_init, EMF_reset, EMF_text, null_scale, EMF_graphics, EMF_move, EMF_solid_vector, EMF_linetype, EMF_put_text, EMF_text_angle, EMF_justify_text, EMF_point, do_arrow, EMF_set_font, EMF_set_pointsize, TERM_BINARY, /* various flags */ NULL, /* suspend */ NULL, /* resume */ EMF_fillbox, EMF_linewidth #ifdef USE_MOUSE , 0, 0, 0, 0, 0 /* no mouse support for emf */ #endif , EMF_make_palette, EMF_previous_palette, EMF_set_color, EMF_filled_polygon #ifdef WITH_IMAGE , NULL #endif , ENHemf_OPEN, ENHemf_FLUSH, do_enh_writec TERM_TABLE_END(emf_driver) #undef LAST_TERM #define LAST_TERM emf_driver #endif /* TERM_TABLE */ #endif /* TERM_PROTO_ONLY */ #ifdef TERM_HELP START_HELP(emf) "1 emf", "?commands set terminal emf", "?set terminal emf", "?set term emf", "?terminal emf", "?term emf", "?emf", " The `emf` terminal generates an Enhanced Metafile Format file.", " This file format is recognized by many Windows applications.", "", " Syntax:", " set terminal emf {color | monochrome} {solid | dashed}", " {enhanced {noproportional}}", " {linewidth } {dashlength
} {size XX,YY}", " {\"\"} {} #old syntax", " {font \",\"} #new syntax", "", " In `monochrome` mode successive line types cycle through dash patterns.", " In `color` mode successive line types use successive colors, and only after", " all 8 default colors are exhausted is the dash pattern incremented.", " `solid` draws all curves with solid lines, overriding any dashed patterns;", " `linewidth ` multiplies all line widths by this factor.", " `dashlength ` is useful for thick lines.", " is the name of a font; and ", " `` is the size of the font in points.", "", " The nominal size of the output image defaults to 1024x768 in arbitrary", " units. You may specify a different nominal size using the `size` option.", "", " Enhanced text mode tries to approximate proportional character spacing.", " If you are using a monospaced font, or don't like the approximation, you", " can turn off this correction using the `noproportional` option.", "", " The default settings are `color dashed font \"Arial,12\" size 1024,768`", " Selecting `default` sets all options to their default values.", "", " Examples:", " set terminal emf 'Times Roman Italic' 12", " set terminal emf color solid # no pesky dashes!" END_HELP(emf) #endif /* TERM_HELP */