Annotation of OpenXM_contrib/gnuplot/term/emf.trm, Revision 1.1.1.1
1.1 ohara 1: /*
2: * $Id: emf.trm,v 1.1.6.4 2002/01/26 19:05:34 lhecking Exp $
3: */
4:
5: /* GNUPLOT - emf.trm */
6:
7: /*[
8: * Copyright 1998
9: *
10: * Permission to use, copy, and distribute this software and its
11: * documentation for any purpose with or without fee is hereby granted,
12: * provided that the above copyright notice appear in all copies and
13: * that both that copyright notice and this permission notice appear
14: * in supporting documentation.
15: *
16: * Permission to modify the software is granted, but not the right to
17: * distribute the complete modified source code. Modifications are to
18: * be distributed as patches to the released version. Permission to
19: * distribute binaries produced by compiling modified sources is granted,
20: * provided you
21: * 1. distribute the corresponding source modifications from the
22: * released version in the form of a patch file along with the binaries,
23: * 2. add special version identification to distinguish your version
24: * in addition to the base release version number,
25: * 3. provide your name and address as the primary contact for the
26: * support of your modified version, and
27: * 4. retain our contact information in regard to use of the base
28: * software.
29: * Permission to distribute the released version of the source code along
30: * with corresponding source modifications in the form of a patch file is
31: * granted with same provisions 2 through 4 for binary distributions.
32: *
33: * This software is provided "as is" without express or implied warranty
34: * to the extent permitted by applicable law.
35: ]*/
36:
37: /*
38: * This file is included by ../term.c and ../docs/termdoc.c.
39: *
40: * This terminal driver supports:
41: * Enhanced Metafile Format
42: *
43: * TODO
44: *
45: * HISTORY
46: *
47: * 1.0.5 2000/07/20
48: * - Handles were not freed at all, resulting to resource leaks when viewing on Windows 9x (not on NT4/W2000!!!)
49: * 1.0.4 2000/06/28
50: * - Emulated dashed vectors are now looking better
51: * - 15 colors * 8 pointstyles = 120 pointtypes
52: * 1.0.3 2000/03/29
53: * - default font is now Arial 12
54: * - implemented options (color/mono,dashed/solid,font)
55: * - 15 colors * 5 dashtypes = 75 linetypes
56: * 1.0.2 2000/03/22
57: * - Polygon and Polyline structures are not working for Windows 9X, I
58: * really don't know why, replaced with lineto/moveto couples...
59: * - Texts are now displayed in GM_Compatible mode because GM_Advanced is
60: * displaying correctly but it does not print correctly with Word97!
61: * - Text centering now works best according to escapement/orientation
62: * - Now there is 8 colors * 5 dashtypes = 40 linetypes
63: * - Successfully Working on Linux Suse 6.1 (x86)
64: *
65: * 1.0.1 2000/03/16
66: * - Unicode text have be to long aligned in EMF files (exttextoutw)
67: * - Problems with text transparence (SetBkMode was not called)
68: * - Null brush created for *not* filling polygon
69: *
70: * 1.0.0 2000/03/15
71: * - Only tested on x86 Win32
72: *
73: * AUTHOR
74: * Stephane Barbaray <stephane.barbaray@compodata.com>
75: * Some code based on cgm.trm
76: *
77: * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
78: */
79:
80: #include "driver.h"
81:
82: #ifdef TERM_REGISTER
83: register_term(emf)
84: #endif
85:
86: #ifdef TERM_PROTO
87: TERM_PUBLIC void EMF_options __PROTO((void));
88: TERM_PUBLIC void EMF_init __PROTO((void));
89: TERM_PUBLIC void EMF_reset __PROTO((void));
90: TERM_PUBLIC void EMF_text __PROTO((void));
91: TERM_PUBLIC void EMF_graphics __PROTO((void));
92: TERM_PUBLIC void EMF_move __PROTO((unsigned int x, unsigned int y));
93: TERM_PUBLIC void EMF_dashed_vector __PROTO((unsigned int ux, unsigned int uy));
94: TERM_PUBLIC void EMF_solid_vector __PROTO((unsigned int ux, unsigned int uy));
95: TERM_PUBLIC void EMF_linetype __PROTO((int linetype));
96: TERM_PUBLIC void EMF_linecolor __PROTO((int color));
97: TERM_PUBLIC void EMF_dashtype __PROTO((int dashtype));
98: TERM_PUBLIC void EMF_linewidth __PROTO((double width));
99: TERM_PUBLIC void EMF_put_text __PROTO((unsigned int x, unsigned int y, char *str));
100: TERM_PUBLIC int EMF_text_angle __PROTO((int ang));
101: TERM_PUBLIC int EMF_justify_text __PROTO((enum JUSTIFY mode));
102: TERM_PUBLIC void EMF_point __PROTO((unsigned int x, unsigned int y, int number));
103: TERM_PUBLIC void EMF_set_pointsize __PROTO((double size));
104: TERM_PUBLIC int EMF_set_font __PROTO((char *));
105:
106: #ifdef RGB
107: #undef RGB
108: #endif
109: #define RGB(r,g,b) ((long)(((unsigned char)(r)|((short)((unsigned char)(g))<<8))|(((long)(unsigned char)(b))<<16)))
110:
111: #ifndef min
112: #define min(a,b) (a<b?a:b)
113: #endif
114:
115: #ifndef max
116: #define max(a,b) (a>b?a:b)
117: #endif
118:
119: #define EMF_PX2HM 20
120: #define EMF_PT2HM 35.28
121: #define EMF_10THDEG2RAD (3.14159265359/1800)
122: #define EMF_XMAX (1024*EMF_PX2HM)
123: #define EMF_YMAX (768*EMF_PX2HM)
124: #define EMF_HTIC (EMF_XMAX/160)
125: #define EMF_VTIC EMF_HTIC
126: #define EMF_FONTNAME "Arial"
127: #define EMF_FONTSIZE 12
128: #define EMF_HCHAR (EMF_FONTSIZE*EMF_PT2HM)
129: #define EMF_VCHAR (EMF_FONTSIZE*EMF_PT2HM)
130: #define EMF_LINE_TYPES 5 /* number of line types we support */
131: #define EMF_COLORS 15 /* number of colors we support */
132: #define EMF_POINTS 8 /* number of markers we support */
133: #define EMF_MAX_SEGMENTS 104 /* maximum # polyline coordinates */
134:
135: #define EMF_HANDLE_PEN 1
136: #define EMF_HANDLE_FONT 2
137: #define EMF_HANDLE_BRUSH 3
138: #define EMF_HANDLE_MAX 4
139:
140: #define EMF_STOCK_OBJECT_FLAG ((unsigned long)0x1 << 31)
141: #define EMF_STOCK_OBJECT_WHITE_BRUSH (EMF_STOCK_OBJECT_FLAG + 0x00)
142: #define EMF_STOCK_OBJECT_BLACK_PEN (EMF_STOCK_OBJECT_FLAG + 0x07)
143: #define EMF_STOCK_OBJECT_DEFAULT_FONT (EMF_STOCK_OBJECT_FLAG + 0x0A)
144:
145: #define EMF_write_emr(type,size) {EMF_write_long(type);EMF_write_long(size);emf_record_count++;}
146: #define EMF_write_sizel(width,height) {EMF_write_long(width);EMF_write_long(height);}
147: #define EMF_write_points(x,y) {EMF_write_short(x);EMF_write_short(y);}
148: #define EMF_write_pointl(x,y) {EMF_write_long(x);EMF_write_long(y);}
149: #define EMF_write_rectl(left,top,right,bottom) {EMF_write_long(left);EMF_write_long(top);EMF_write_long(right);EMF_write_long(bottom);}
150:
151: #define EMF_EOF() {EMF_write_emr(14,20);EMF_write_long(0);EMF_write_long(0x10);EMF_write_long(20);}
152: #define EMF_SetMapMode(mode) {EMF_write_emr(17,0xc);EMF_write_long(mode);}
153: #define EMF_SetWindowExtEx(width,height) {EMF_write_emr(9,0x10);EMF_write_sizel(width,height);}
154: #define EMF_SetWindowOrgEx(width,height) {EMF_write_emr(10,0x10);EMF_write_sizel(width,height);}
155: #define EMF_SetViewportExtEx(width,height) {EMF_write_emr(11,0x10);EMF_write_sizel(width,height);}
156: #define EMF_SetViewportOrgEx(width,height) {EMF_write_emr(12,0x10);EMF_write_sizel(width,height);}
157: #define EMF_SetTextColor(color) {EMF_write_emr(24,0xc);EMF_write_long(color);}
158: #define EMF_MoveToEx(x,y) {EMF_write_emr(27,0x10);EMF_write_pointl(x,y);}
159: #define EMF_LineTo(x,y) {EMF_write_emr(54,0x10);EMF_write_pointl(x,y);}
160: #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);}
161: #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);}
162: #define EMF_SelectObject(handle) {EMF_write_emr(37,0x0C);EMF_write_long(handle);}
163: #define EMF_DeleteObject(handle) {EMF_write_emr(40,0x0C);EMF_write_long(handle);}
164: #define EMF_SetTextAlign(align) {EMF_write_emr(22,0x0C);EMF_write_long(align);}
165: #define EMF_SetBkMode(mode) {EMF_write_emr(18,0x0C);EMF_write_long(mode);}
166:
167: #endif /* TERM_PROTO */
168:
169: #ifndef TERM_PROTO_ONLY
170: #ifdef TERM_BODY
171:
172: /*
173: * on NeXTstep, id is an identifier (in ObjC) and causes a parse error
174: * since some asserts below are mistaken as casts. datum is a type
175: * defined in ndbm.h which also causes a parse error (ndbm.h is
176: * included as part of appkit.h, I think). Strangely enough, both
177: * errors only happen with cpp-precomp -smart, not with the regular
178: * cpp. (AL)
179: */
180:
181: #ifdef NEXT
182: #define id id_
183: #define datum datum_
184: #endif
185:
186: #include <ctype.h> /* for isspace() */
187:
188: #ifndef assert
189: #define assert(x) 0 /* defeat assertions */
190: #endif
191:
192: /* uncomment the following to enable assertions for this module only,
193: regardless of compiler switches */
194: #ifdef NDEBUG
195: #define DEFEAT_ASSERTIONS
196: #endif
197: #undef NDEBUG
198: #include <assert.h>
199:
200: static unsigned int emf_posx;
201: static unsigned int emf_posy;
202: static unsigned int emf_record_count = 0;
203: static unsigned int emf_linetype = 1;
204: static unsigned int emf_linewidth; /* line width in plot units */
205: static unsigned int emf_dashtype = 0;
206: static unsigned long emf_color = 0L;
207: static unsigned int emf_polyline[EMF_MAX_SEGMENTS]; /* stored polyline coordinates */
208: static unsigned int emf_graphics = FALSE;
209: static unsigned int emf_dashed = TRUE;
210: static unsigned int emf_monochrome = FALSE;
211: static int emf_coords = 0; /* # polyline coordinates saved */
212: static char emf_fontname[255] = EMF_FONTNAME;
213: static int emf_fontsize = EMF_FONTSIZE;
214: static char emf_defaultfontname[255] = EMF_FONTNAME;
215: static int emf_defaultfontsize = EMF_FONTSIZE;
216: enum JUSTIFY emf_justify = LEFT;
217: static int emf_vert_text = 0; /* text orientation -- nonzero for vertical */
218: static int emf_step_sizes[8]; /* array of currently used dash lengths in plot units */
219: static int emf_step_index = 0; /* index into emf_step_sizes[] */
220: static int emf_step = 0; /* amount of current dash not yet drawn, in plot units */
221: static int emf_tic, emf_tic707, emf_tic866, emf_tic500, emf_tic1241, emf_tic1077, emf_tic621; /* marker dimensions */
222:
223: static void EMF_flush_polyline __PROTO((void));
224: static void EMF_flush_polygon __PROTO((void));
225: static void EMF_write_byte __PROTO((int)); /* HBB 20001102: was 'char'... */
226: static void EMF_write_short __PROTO((int)); /* HBB 20001102: was 'short' */
227: static void EMF_write_long __PROTO((unsigned long));
228: static void EMF_write_float __PROTO((double)); /* HBB 20001102: was 'float' */
229: static void EMF_setfont __PROTO((void));
230:
231: static void
232: EMF_setfont()
233: {
234: int i, count;
235: int bold = 400;
236: char italic = 0, underline = 0, strikeout = 0;
237: char font[32];
238: char *sub;
239:
240: if (!emf_graphics)
241: return;
242:
243: count = min (strlen(emf_fontname), 31);
244: if (((sub = strstr(emf_fontname, " bold")) != NULL)
245: || ((sub = strstr(emf_fontname, " Bold")) != NULL)) {
246: bold = 700;
247: count = min(sub - emf_fontname, count);
248: }
249: if (((sub = strstr(emf_fontname, " italic")) != NULL)
250: || ((sub = strstr(emf_fontname, " Italic")) != NULL)) {
251: italic = 1;
252: count = min(sub - emf_fontname, count);
253: }
254: if (((sub = strstr(emf_fontname, " underline")) != NULL)
255: || ((sub = strstr(emf_fontname, " Underline")) != NULL)) {
256: underline = 1;
257: count = min(sub - emf_fontname, count);
258: }
259: if (((sub = strstr(emf_fontname, " strikeout")) != NULL)
260: || ((sub = strstr(emf_fontname, " Strikeout")) != NULL)
261: || ((sub = strstr(emf_fontname, " StrikeOut")) != NULL)
262: ) {
263: strikeout = 1;
264: count = min(sub - emf_fontname, count);
265: }
266:
267: safe_strncpy(font, emf_fontname, count + 1);
268:
269: EMF_SelectObject(EMF_STOCK_OBJECT_DEFAULT_FONT);
270: EMF_DeleteObject(EMF_HANDLE_FONT);
271:
272: EMF_write_emr(82, 104);
273: EMF_write_long(EMF_HANDLE_FONT);
274: EMF_write_long((long) (emf_fontsize * EMF_PT2HM)); /* height */
275: EMF_write_long(0); /* width */
276: EMF_write_long(emf_vert_text); /* escapement */
277: EMF_write_long(emf_vert_text); /* orientation */
278: EMF_write_long(bold); /* weight */
279: EMF_write_byte(italic); /* italic */
280: EMF_write_byte(underline); /* underline */
281: EMF_write_byte(strikeout); /* strikeout */
282: EMF_write_byte(1); /* charset */
283: EMF_write_byte(0); /* out precision */
284: EMF_write_byte(0); /* clip precision */
285: EMF_write_byte(0); /* quality */
286: EMF_write_byte(0); /* pitch and family */
287: for (i = 0; i < 32; i++) { /* face name (max 32) */
288: EMF_write_byte((char) (i < strlen(font) ? font[i] : 0));
289: EMF_write_byte(0);
290: }
291: EMF_SelectObject(EMF_HANDLE_FONT);
292: }
293:
294: static void
295: EMF_flush_polygon()
296: {
297: if (emf_coords == 0)
298: return;
299: else {
300: int i = 0;
301: /* Polygon works for NT4 but not on W9x */
302: /* EMF_write_emr(3,(7+emf_coords*2)*4);
303: EMF_write_rectl(0,0,0,0);
304: EMF_write_long(emf_coords);
305: while(i < emf_coords*2)
306: EMF_write_pointl(emf_polyline[i++],term->ymax-emf_polyline[i++]);
307: */
308: EMF_MoveToEx(emf_polyline[i++], term->ymax - emf_polyline[i++]);
309: while (i < emf_coords * 2)
310: EMF_LineTo(emf_polyline[i++], term->ymax - emf_polyline[i++]);
311: EMF_LineTo(emf_polyline[0], term->ymax - emf_polyline[1]);
312: }
313: emf_coords = 0;
314: }
315:
316: static void
317: EMF_flush_polyline()
318: {
319: if (emf_coords == 0)
320: return;
321: else if (emf_coords <= 2) {
322: EMF_MoveToEx(emf_polyline[0], term->ymax - emf_polyline[1]);
323: EMF_LineTo(emf_polyline[2], term->ymax - emf_polyline[3]);
324: } else {
325: int i = 0;
326: /* Polyline works for NT4 but not on W9x */
327: /* EMF_write_emr(4,(7+emf_coords*2)*4);
328: EMF_write_rectl(0,0,0,0);
329: EMF_write_long(emf_coords);
330: while(i < emf_coords*2)
331: EMF_write_pointl(emf_polyline[i++],term->ymax-emf_polyline[i++]);
332: */
333: EMF_MoveToEx(emf_polyline[i++], term->ymax - emf_polyline[i++]);
334: while (i < emf_coords * 2)
335: EMF_LineTo(emf_polyline[i++], term->ymax - emf_polyline[i++]);
336: }
337: emf_coords = 0;
338: }
339:
340: /* HBB 20001103: K&R'ized these 4 functions a bit better. */
341: static void
342: EMF_write_byte(value)
343: int value;
344: {
345: char c = value;
346: fwrite(&c, 1, 1, gpoutfile);
347: }
348:
349: static void
350: EMF_write_short(value)
351: int value;
352: {
353: short int actual_value = value;
354: char c[2];
355:
356: c[1] = (actual_value >> 8) & 255; /* convert to x86 order */
357: c[0] = actual_value & 255;
358:
359: fwrite(c, 1, 2, gpoutfile);
360: }
361:
362: static void
363: EMF_write_long(value)
364: unsigned long value;
365: {
366: char c[4];
367:
368: c[3] = (value >> 24) & 0xFFL; /* convert to x86 order */
369: c[2] = (value >> 16) & 0xFFL;
370: c[1] = (value >> 8) & 0xFFL;
371: c[0] = value & 0xFFL;
372:
373: fwrite(c, 1, 4, gpoutfile);
374: }
375:
376: /* FIXME HBB 20001103: this only works as given iff 'float' is the
377: * same format as on x86's, i.e. IEEE 4-byte floating point format */
378: static void
379: EMF_write_float(value)
380: double value;
381: {
382: char c[4];
383:
384: union {
385: long l;
386: float f;
387: } u;
388:
389: u.f = value;
390:
391: c[3] = (u.l >> 24) & 0xFFL; /* convert to x86 order */
392: c[2] = (u.l >> 16) & 0xFFL;
393: c[1] = (u.l >> 8) & 0xFFL;
394: c[0] = u.l & 0xFFL;
395:
396: fwrite(c, 1, 4, gpoutfile);
397: }
398:
399: TERM_PUBLIC void
400: EMF_options()
401: {
402: term->xmax = EMF_XMAX;
403: term->ymax = EMF_YMAX;
404: emf_dashed = TRUE;
405: emf_monochrome = FALSE;
406: while (!END_OF_COMMAND) {
407: if (almost_equals(c_token, "de$fault")) {
408: strcpy(emf_defaultfontname, EMF_FONTNAME);
409: emf_defaultfontsize = EMF_FONTSIZE;
410: emf_monochrome = FALSE;
411: emf_dashed = TRUE;
412: c_token++;
413: continue;
414: }
415: if (almost_equals(c_token, "m$onochrome")) {
416: emf_monochrome = TRUE;
417: c_token++;
418: continue;
419: }
420: if (almost_equals(c_token, "c$olor") || almost_equals(c_token, "c$olour")) {
421: emf_monochrome = FALSE;
422: c_token++;
423: continue;
424: }
425: if (almost_equals(c_token, "da$shed")) {
426: emf_dashed = TRUE;
427: c_token++;
428: continue;
429: }
430: if (almost_equals(c_token, "s$olid")) {
431: emf_dashed = FALSE;
432: c_token++;
433: continue;
434: }
435: break;
436: }
437: if (!END_OF_COMMAND && isstring(c_token)) {
438: quote_str(emf_defaultfontname, c_token, MAX_ID_LEN);
439: c_token++;
440: }
441: if (!END_OF_COMMAND) {
442: /* We have font size specified */
443: struct value a;
444: emf_defaultfontsize = (int) real(const_express(&a));
445: }
446: EMF_set_font(NULL); /* set default font */
447:
448: sprintf(term_options, "%s %s \"%s\" %d",
449: emf_monochrome ? "monochrome" : "color",
450: emf_dashed ? "dashed" : "solid",
451: emf_defaultfontname, emf_defaultfontsize);
452: }
453:
454: TERM_PUBLIC void
455: EMF_init()
456: {
457: emf_posx = emf_posy = 0;
458: emf_linetype = 0;
459: emf_vert_text = 0;
460: emf_graphics = FALSE;
461: }
462:
463: TERM_PUBLIC void
464: EMF_graphics()
465: {
466: /* header start */
467: emf_record_count = 0;
468: EMF_write_emr(1, 100);
469: EMF_write_long(0); /* rclBounds */
470: EMF_write_long(0);
471: EMF_write_long(term->xmax / 20);
472: EMF_write_long(term->ymax / 20);
473: EMF_write_long(0); /* rclFrame */
474: EMF_write_long(0);
475: EMF_write_long(term->xmax);
476: EMF_write_long(term->ymax);
477: EMF_write_long(0x464D4520); /* signature */
478: EMF_write_long(0x00010000); /* version */
479: EMF_write_long(0); /* nBytes */
480: EMF_write_long(0); /* nRecords */
481: EMF_write_short(EMF_HANDLE_MAX); /* nHandles */
482: EMF_write_short(0); /* reserved */
483: EMF_write_long(0); /* descSize */
484: EMF_write_long(0); /* descOff */
485: EMF_write_long(0); /* nPalEntries */
486: EMF_write_long(1600); /* ref dev pixwidth */
487: EMF_write_long(1200); /* ref dev pixheight */
488: EMF_write_long(320); /* ref dev mwidth */
489: EMF_write_long(240); /* ref dev mheight */
490: EMF_write_long(0); /* cbPixelFormat */
491: EMF_write_long(0); /* offPixelFormat */
492: EMF_write_long(0); /* bOpenGL */
493: emf_graphics = TRUE;
494: /* header end */
495:
496: EMF_SetMapMode(8); /* forcing anisotropic mode */
497: EMF_SetWindowExtEx(term->xmax, term->ymax); /* setting logical (himetric) size */
498: EMF_SetViewportExtEx(term->xmax / 20, term->ymax / 20); /* setting device (pixel) size */
499: EMF_CreatePen(EMF_HANDLE_PEN, 0, 1, 0x000000); /* init default pen */
500: EMF_SelectObject(EMF_HANDLE_PEN);
501: EMF_SetBkMode(1); /* transparent background for text */
502: EMF_CreateBrush(EMF_HANDLE_BRUSH, 1, 0, 0); /* transparent brush for polygons */
503: EMF_SelectObject(EMF_HANDLE_BRUSH);
504: EMF_set_font(NULL); /* init default font */
505: }
506:
507: TERM_PUBLIC int
508: EMF_set_font(char *font)
509: {
510: int sep; /* hope this function exist everywhere... */
511:
512: if (font && *font) {
513: char *comma = strchr(font, ',');
514: if (comma == NULL)
515: return FALSE; /* bad format */
516: sep = comma - font;
517: safe_strncpy(emf_fontname, font, min(sep + 1, 32));
518: emf_fontsize = atoi(&font[sep + 1]);
519: } else {
520: strcpy(emf_fontname, emf_defaultfontname);
521: emf_fontsize = emf_defaultfontsize;
522: }
523: term->h_char = (emf_fontsize * EMF_PT2HM);
524: term->v_char = (emf_fontsize * EMF_PT2HM);
525: EMF_setfont();
526: return TRUE;
527: }
528:
529: TERM_PUBLIC void
530: EMF_text()
531: {
532: long pos;
533: EMF_flush_polyline();
534:
535: /* writing end of metafile */
536: EMF_SelectObject(EMF_STOCK_OBJECT_DEFAULT_FONT);
537: EMF_DeleteObject(EMF_HANDLE_FONT);
538: EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
539: EMF_DeleteObject(EMF_HANDLE_PEN);
540: EMF_SelectObject(EMF_STOCK_OBJECT_WHITE_BRUSH);
541: EMF_DeleteObject(EMF_HANDLE_BRUSH);
542: EMF_EOF();
543:
544: /* updating header */
545: pos = ftell(gpoutfile);
546: fseek(gpoutfile, 48, SEEK_SET);
547: EMF_write_long(pos);
548: EMF_write_long(emf_record_count);
549: /* HBB 20010228: have to make known that we're no longer in graphics
550: * status. */
551: emf_graphics = FALSE;
552: }
553:
554: TERM_PUBLIC void
555: EMF_linetype(linetype)
556: int linetype;
557: {
558: /* Note : separating linetype and color would have not been futile, but anyway... */
559:
560: assert(linetype >= -2);
561: if (linetype == emf_linetype)
562: return;
563: emf_linetype = linetype;
564:
565: EMF_linecolor(linetype);
566: EMF_dashtype(linetype);
567: }
568:
569: TERM_PUBLIC void
570: EMF_linecolor(linecolor)
571: int linecolor;
572: {
573: static long GPFAR color_table_data[] =
574: {
575: RGB(255, 0, 0), /* red */
576: RGB(0, 255, 0), /* green */
577: RGB(0, 0, 255), /* blue */
578: RGB(255, 0, 255), /* magenta */
579: RGB(0, 0, 128), /* dark blue */
580: RGB(128, 0, 0), /* dark red */
581: RGB(0, 128, 128), /* dark cyan */
582: RGB(0, 0, 0), /* black */
583: RGB(128, 128, 128), /* grey */
584: RGB(0, 128, 64), /* very dark cyan */
585: RGB(128, 128, 0), /* dark yellow */
586: RGB(128, 0, 128), /* dark magenta */
587: RGB(192, 192, 192), /* light grey */
588: RGB(0, 255, 255), /* cyan */
589: RGB(255, 255, 0), /* yellow */
590: };
591:
592: assert(linecolor >= -2);
593: linecolor = (linecolor < 0 || emf_monochrome) ? 7 : (linecolor % EMF_COLORS);
594: if (color_table_data[linecolor] == emf_color)
595: return;
596: emf_color = color_table_data[linecolor];
597:
598: EMF_flush_polyline();
599: }
600:
601: TERM_PUBLIC void
602: EMF_linewidth(width)
603: double width;
604: {
605: assert(width >= 0);
606: if (width == emf_linewidth)
607: return;
608: emf_linewidth = width;
609:
610: EMF_dashtype(emf_dashtype); /* have dash lengths recalculated */
611: }
612:
613: TERM_PUBLIC void
614: EMF_dashtype(dashtype)
615: int dashtype;
616: {
617: int i, j;
618: /* Each group of 8 entries in dot_length[] defines a dash
619: pattern. Entries in each group are alternately length of
620: whitespace and length of line, in units of 2/3 of the
621: linewidth. */
622: static int dot_length[EMF_LINE_TYPES * 8] =
623: { /* 0 - solid */
624: 5, 8, 5, 8, 5, 8, 5, 8, /* 1 - dashes */
625: 4, 2, 4, 2, 4, 2, 4, 2, /* 2 - dotted */
626: 4, 8, 4, 2, 4, 8, 4, 2, /* 3 - dash-dot */
627: 4, 9, 4, 2, 4, 2, 0, 0, /* 4 - dash-dot-dot */
628: };
629:
630:
631: assert(dashtype >= -2);
632: if (dashtype == emf_dashtype)
633: return;
634:
635: emf_dashtype = dashtype;
636:
637: EMF_flush_polyline();
638:
639: if (dashtype >= 0)
640: dashtype = (dashtype / EMF_COLORS) % EMF_LINE_TYPES;
641:
642: if (dashtype < 1 || !emf_dashed) { /* solid mode */
643: EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
644: EMF_DeleteObject(EMF_HANDLE_PEN);
645: EMF_CreatePen(EMF_HANDLE_PEN, 0, emf_linewidth * EMF_PX2HM, emf_color);
646: EMF_SelectObject(EMF_HANDLE_PEN);
647:
648: term->vector = EMF_solid_vector;
649: } else { /* Since win32 dashed lines works only with 1 pixel linewith we must emulate */
650: EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
651: EMF_DeleteObject(EMF_HANDLE_PEN);
652: EMF_CreatePen(EMF_HANDLE_PEN, 0, emf_linewidth * EMF_PX2HM, emf_color);
653: EMF_SelectObject(EMF_HANDLE_PEN);
654:
655: term->vector = EMF_dashed_vector;
656:
657: /* set up dash dimensions */
658: j = (dashtype - 1) * 8;
659: for (i = 0; i < 8; i++, j++) {
660: if (dot_length[j])
661: emf_step_sizes[i] = (dot_length[j] * emf_linewidth * EMF_PX2HM) * 3 / 3;
662: else
663: emf_step_sizes[i] = 0;
664: }
665: /* first thing drawn will be a line */
666: emf_step = emf_step_sizes[1];
667: emf_step_index = 1;
668: }
669: }
670:
671: TERM_PUBLIC void
672: EMF_move(x, y)
673: unsigned int x, y;
674: {
675: assert(x < term->xmax && y < term->ymax);
676: if (x == emf_posx && y == emf_posy)
677: return;
678: EMF_flush_polyline();
679: emf_posx = x;
680: emf_posy = y;
681: }
682:
683: TERM_PUBLIC void
684: EMF_dashed_vector(ux, uy)
685: unsigned int ux, uy;
686: {
687: int xa, ya;
688: int dx, dy, adx, ady;
689: int dist; /* approximate distance in plot units from starting point to specified end point. */
690: long remain; /* approximate distance in plot units remaining to specified end point. */
691:
692: assert(ux < term->xmax && uy < term->ymax);
693:
694: dx = (ux - emf_posx);
695: dy = (uy - emf_posy);
696: adx = abs(dx);
697: ady = abs(dy * 10);
698:
699: /* using the approximation sqrt(x**2 + y**2) ~ x + (5*x*x)/(12*y) when x > y.
700: Note ordering of calculations to avoid overflow on 16 bit architectures */
701: if (10 * adx < ady)
702: dist = (ady / 2 + 25 * adx / ady * adx / 6 * 5) / 5;
703: else {
704: if (adx == 0)
705: return;
706: dist = (adx * 10 + (ady / 24) * (ady / adx)) / 10;
707: }
708: remain = dist;
709: xa = emf_posx;
710: ya = emf_posy;
711: while (remain > emf_step) {
712: remain -= emf_step;
713: if (emf_step_index & 1)
714: EMF_solid_vector((int) (ux - (remain * dx) / dist), (int) (uy - (remain * dy) / dist));
715: else {
716: xa = (int) (ux - (remain * dx) / dist);
717: ya = (int) (uy - (remain * dy) / dist);
718: EMF_move(xa, ya);
719: }
720: if (++emf_step_index >= 8)
721: emf_step_index = 0;
722: emf_step = emf_step_sizes[emf_step_index];
723: }
724: if (emf_step_index & 1)
725: EMF_solid_vector(ux, uy);
726: else
727: EMF_move(ux, uy);
728: emf_step -= (int) remain;
729: }
730:
731: TERM_PUBLIC void
732: EMF_solid_vector(ux, uy)
733: unsigned int ux, uy;
734: {
735: assert(ux < term->xmax && uy < term->ymax);
736: if (ux == emf_posx && uy == emf_posy)
737: return;
738: if (emf_coords * 2 > EMF_MAX_SEGMENTS - 2)
739: EMF_flush_polyline();
740: if (emf_coords == 0) {
741: emf_polyline[0] = emf_posx;
742: emf_polyline[1] = emf_posy;
743: emf_coords++;
744: }
745: emf_posx = emf_polyline[emf_coords * 2] = ux;
746: emf_posy = emf_polyline[emf_coords * 2 + 1] = uy;
747: emf_coords++;
748: }
749:
750: TERM_PUBLIC void
751: EMF_put_text(x, y, str)
752: unsigned int x, y;
753: char str[];
754: {
755: int i, len = strlen(str);
756: if (len % 2) /* Must be long aligned! */
757: len++;
758: EMF_flush_polyline();
759: EMF_SetTextColor(emf_color); /* since text doesn't use pens, we must initialize with this */
760: EMF_write_emr(84, 76 + len * 2); /* exttextoutw, yes it's the 16bits char version! */
761: EMF_write_rectl(0, 0, 0, 0); /* bounding, never used */
762: EMF_write_long(1); /* GM_Compatible mode for advanced scaling */
763: EMF_write_float(EMF_PX2HM); /* x scale */
764: EMF_write_float(EMF_PX2HM); /* y scale */
765: 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))); /* positioning... y is recentered from bottom reference set in text align */
766: EMF_write_long(strlen(str)); /* real char size */
767: EMF_write_long(76); /* offset to text */
768: EMF_write_long(0); /* options, none */
769: EMF_write_rectl(0, 0, 0, 0); /* rectangle clipping not used */
770: EMF_write_long(0); /* offset to dx, can't be used since really we don't know anything about the face properties used */
771:
772: for (i = 0; i < len; i++) { /* it is safe to go up to strlen+1 for aligning to long */
773: char pad = 0;
774: fwrite(&str[i], 1, 1, gpoutfile);
775: fwrite(&pad, 1, 1, gpoutfile);
776: }
777: emf_posx = emf_posy = -2000;
778: }
779:
780: TERM_PUBLIC int
781: EMF_text_angle(ang)
782: int ang;
783: {
784: /* Note : why did they use choose only 0 and 1? That's stupid! */
785: /* Win GDI rotation is scaled in tenth of degrees, so... */
786: switch (ang) {
787: case 0: /* left right */
788: if (emf_vert_text != 0) {
789: emf_vert_text = 0;
790: EMF_setfont();
791: }
792: break;
793: case 1: /* bottom up */
794: if (emf_vert_text != 900) {
795: emf_vert_text = 900;
796: EMF_setfont();
797: }
798: break;
799: }
800: return TRUE;
801: }
802:
803: TERM_PUBLIC int
804: EMF_justify_text(mode)
805: enum JUSTIFY mode;
806: {
807: int align = 8; /* y referenced to bottom */
808: switch (mode) {
809: case LEFT:
810: align |= 0;
811: break;
812: case RIGHT:
813: align |= 2;
814: break;
815: case CENTRE:
816: align |= 6;
817: break;
818: }
819: EMF_SetTextAlign(align);
820: return (TRUE);
821: }
822:
823: TERM_PUBLIC void
824: EMF_reset()
825: {
826: emf_posx = emf_posy = 0;
827: emf_graphics = FALSE;
828: }
829:
830: TERM_PUBLIC void
831: EMF_point(x, y, number)
832: unsigned int x, y;
833: int number;
834: {
835: int old_dashtype;
836: unsigned long old_linecolor;
837:
838: EMF_flush_polyline();
839: old_dashtype = emf_dashtype;
840: old_linecolor = emf_color;
841: EMF_linecolor(number);
842: EMF_dashtype(number % EMF_COLORS);
843:
844: if (number < 0) { /* draw dot */
845: EMF_move(x, y);
846: EMF_solid_vector(x + 1, y);
847: goto end_points;
848: }
849: number = (number / EMF_COLORS) % EMF_POINTS;
850:
851: switch (number) {
852: case 0: /* draw diamond */
853: EMF_move(x - emf_tic, y);
854: EMF_solid_vector(x, y - emf_tic);
855: EMF_solid_vector(x + emf_tic, y);
856: EMF_solid_vector(x, y + emf_tic);
857: EMF_flush_polygon();
858: break;
859: case 1: /* draw plus */
860: EMF_move(x - emf_tic, y);
861: EMF_solid_vector(x + emf_tic, y);
862: EMF_move(x, y - emf_tic);
863: EMF_solid_vector(x, y + emf_tic);
864: break;
865: case 2: /* draw box */
866: EMF_move(x - emf_tic707, y - emf_tic707);
867: EMF_solid_vector(x + emf_tic707, y - emf_tic707);
868: EMF_solid_vector(x + emf_tic707, y + emf_tic707);
869: EMF_solid_vector(x - emf_tic707, y + emf_tic707);
870: EMF_flush_polygon();
871: break;
872: case 3: /* draw X */
873: EMF_move(x - emf_tic707, y - emf_tic707);
874: EMF_solid_vector(x + emf_tic707, y + emf_tic707);
875: EMF_move(x - emf_tic707, y + emf_tic707);
876: EMF_solid_vector(x + emf_tic707, y - emf_tic707);
877: break;
878: case 4: /* draw triangle (point up) */
879: EMF_move(x, y + emf_tic1241);
880: EMF_solid_vector(x - emf_tic1077, y - emf_tic621);
881: EMF_solid_vector(x + emf_tic1077, y - emf_tic621);
882: EMF_flush_polygon();
883: break;
884: case 5: /* draw star (asterisk) */
885: EMF_move(x, y - emf_tic);
886: EMF_solid_vector(x, y + emf_tic);
887: EMF_move(x + emf_tic866, y - emf_tic500);
888: EMF_solid_vector(x - emf_tic866, y + emf_tic500);
889: EMF_move(x + emf_tic866, y + emf_tic500);
890: EMF_solid_vector(x - emf_tic866, y - emf_tic500);
891: break;
892: case 6: /* draw triangle (point down) */
893: EMF_move(x, y - emf_tic1241);
894: EMF_solid_vector(x - emf_tic1077, y + emf_tic621);
895: EMF_solid_vector(x + emf_tic1077, y + emf_tic621);
896: EMF_flush_polygon();
897: break;
898: case 7: /* draw circle (actually, dodecagon)
899: (WinWord 6 accepts the CGM "circle"
900: element, but the resulting circle
901: is not correctly centered!) */
902: EMF_move(x, y - emf_tic);
903: EMF_solid_vector(x + emf_tic500, y - emf_tic866);
904: EMF_solid_vector(x + emf_tic866, y - emf_tic500);
905: EMF_solid_vector(x + emf_tic, y);
906: EMF_solid_vector(x + emf_tic866, y + emf_tic500);
907: EMF_solid_vector(x + emf_tic500, y + emf_tic866);
908: EMF_solid_vector(x, y + emf_tic);
909: EMF_solid_vector(x - emf_tic500, y + emf_tic866);
910: EMF_solid_vector(x - emf_tic866, y + emf_tic500);
911: EMF_solid_vector(x - emf_tic, y);
912: EMF_solid_vector(x - emf_tic866, y - emf_tic500);
913: EMF_solid_vector(x - emf_tic500, y - emf_tic866);
914: EMF_flush_polygon();
915: break;
916: }
917: end_points:
918: emf_color = old_linecolor;
919: EMF_dashtype(old_dashtype);
920: }
921:
922:
923: TERM_PUBLIC void
924: EMF_set_pointsize(size)
925: double size;
926: {
927: emf_tic = (size * term->h_tic / 2);
928: emf_tic707 = emf_tic * 12 / 17;
929: emf_tic866 = emf_tic * 13 / 15;
930: emf_tic500 = emf_tic / 2;
931: emf_tic1241 = emf_tic * 36 / 29;
932: emf_tic1077 = emf_tic * 14 / 13;
933: emf_tic621 = emf_tic * 18 / 29;
934: }
935:
936: #ifdef DEFEAT_ASSERTIONS
937: #define NDEBUG
938: #include <assert.h>
939: #undef DEFEAT_ASSERTIONS
940: #endif /* DEFEAT_ASSERTIONS */
941:
942: #ifdef NEXT
943: #undef id
944: #undef datum
945: #endif
946:
947: #endif /* TERM_BODY */
948:
949: #ifdef TERM_TABLE
950: TERM_TABLE_START(emf_driver)
951: "emf", "Enhanced Metafile format",
952: EMF_XMAX, EMF_YMAX, EMF_VCHAR, EMF_HCHAR,
953: EMF_VTIC, EMF_HTIC, EMF_options, EMF_init, EMF_reset,
954: EMF_text, null_scale, EMF_graphics, EMF_move, EMF_solid_vector,
955: EMF_linetype, EMF_put_text, EMF_text_angle,
956: EMF_justify_text, EMF_point, do_arrow, EMF_set_font,
957: EMF_set_pointsize,
958: TERM_BINARY, /* various flags */
959: NULL, /* after one plot of multiplot */
960: NULL, /* before subsequent plot of multiplot */
961: NULL, /* clear part of multiplot */
962: EMF_linewidth
963: TERM_TABLE_END(emf_driver)
964: #undef LAST_TERM
965: #define LAST_TERM emf_driver
966:
967: #endif /* TERM_TABLE */
968: #endif /* TERM_PROTO_ONLY */
969:
970: #ifdef TERM_HELP
971: START_HELP(emf)
972: "1 emf",
973: "?commands set terminal emf",
974: "?set terminal emf",
975: "?set term emf",
976: "?terminal emf",
977: "?term emf",
978: "?emf",
979: " The `emf` terminal generates an Enhanced Metafile Format file. This file format",
980: " is the metafile standard on MS Win32 Systems"
981: "",
982: " Syntax:",
983: " set terminal emf {<color>} {solid | dashed}",
984: " {\"<font>\"} {<fontsize>}",
985: "",
986: " <color> is either `color` or `monochrome`; ",
987: " `solid` draws all curves with solid lines, overriding any dashed patterns;",
988: " <font> is the name of a font; and ",
989: " `<fontsize>` is the size of the font in points.",
990: "",
991: " The first two options can be in any order. Selecting `default` sets all",
992: " options to their default values.",
993: "",
994: " Examples:",
995: " set terminal emf 'Times Roman Italic' 12",
996: " set terminal emf color solid # no pesky dashes!"
997: END_HELP(emf)
998: #endif /* TERM_HELP */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>