1 /*
2 * TransFig: Facility for Translating Fig code
3 * Copyright (c) 1999 by Philippe Bekaert
4 * Parts Copyright (c) 1989-2002 by Brian V. Smith
5 *
6 * Any party obtaining a copy of these files is granted, free of charge, a
7 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
8 * nonexclusive right and license to deal in this software and
9 * documentation files (the "Software"), including without limitation the
10 * rights to use, copy, modify, merge, publish and/or distribute copies of
11 * the Software, and to permit persons who receive copies from any such
12 * party to do so, with the only requirement being that this copyright
13 * notice remain intact.
14 *
15 */
16
17 /*
18 * genemf.c -- convert fig to Enhanced MetaFile
19 *
20 * Written by Michael Schrick (2001-03-04)
21 *
22 * Revision History:
23 *
24 * 2004/02/10 - Added support for locale text (if iconv() is available),
25 * arc box, open arc, rotated ellipse, picture,
26 * dash-triple-dotted line style, and all fill patterns.
27 * (ITOH Yasufumi)
28 *
29 * 2003/01/14 - Added text orientation, text alignment. Corrected color
30 * table and added text color. Added transparency, fill
31 * colors and patterns. (M. Schrick)
32 *
33 * 2001/10/03 - Added htof functions for big endian machines (M. Schrick)
34 *
35 * 2001/09/24 - Added filled polygons, circles and ellipses (M. Schrick)
36 *
37 * 2001/03/04 - Created from gencgm.c (M. Schrick)
38 *
39 * Limitations:
40 *
41 * - old style splines are not supported by this driver. New style
42 * (X) splines are automatically converted to polylines and thus
43 * are supported.
44 *
45 * - Windows 95 supports linestyles only for the thin line. Lines with
46 * styles will converted to the thin width. Dash-triple-dotted linestyle
47 * is not supported.
48 * Windows 98/Me don't seem to support linestyles well.
49 *
50 * - Windows 95/98/Me supports only 12 patterns out of FIG's 22 fill pattern.
51 * Unsupported patterns will be shown differently.
52 *
53 * - Windows 95/98/Me doesn't support line cap and join styles. The correct
54 * appearance of arrows depends on the cap style the viewer uses (not
55 * known at conversion time, but can be set using the -r driver option).
56 *
57 * - an EMF file may look quite different when viewed with different
58 * EMF capable drawing programs. This is especially so for text:
59 * the text font e.g. needs to be recognized and supported by the
60 * viewer. Same is True for special characters in text strings, etc.
61 *
62 */
63
64 #include <stdio.h>
65 #include <stdlib.h>
66 #if defined(I18N) && defined(USE_ICONV)
67 #include <iconv.h>
68 #endif
69 #include "fig2dev.h"
70 #include "object.h"
71 #include "genemf.h"
72
73 #define UNDEFVALUE -100 /* UNDEFined attribute value */
74 #define EPSILON 1e-4 /* small floating point value */
75
76 typedef enum {EMH_RECORD, EMH_DATA} emh_flag;
77 static ENHMETAHEADER emh; /* The Enhanced MetaFile header, which is the
78 * first record in the file must be updated
79 * to reflect the total number of records and
80 * the total number of bytes. This record
81 * contains little endian data and should not
82 * be used internally without a conversion. */
83 /* Internal variables in host format */
84 static unsigned emh_nBytes; /* Size of the metafile in bytes */
85 static unsigned emh_nRecords; /* Number of records in the metafile */
86 static unsigned emh_nHandles; /* Number of handles in the handle table */
87
88 /*
89 * Limit maximum number of handles.
90 * XXX limit to which number?
91 */
92 static unsigned maxHandles = 50;
93
94 /* Data types for keeping track of the device context handles */
95 enum emfhandletype { EMFH_PEN, EMFH_BRUSH, EMFH_FONT, EMFH_MAX } type;
96
97 static unsigned lasthandle[EMFH_MAX]; /* Last device handle */
98
99 struct emfhandle {
100 struct emfhandle *next; /* This field must be first */
101 struct emfhandle **prev;
102 enum emfhandletype type;
103 Boolean is_current; /* True: currently selected */
104 unsigned handle;
105 union {
106 struct pen {
107 int pstyle, pwidth, prgb;
108 } p;
109 struct brush {
110 int bstyle;
111 int brgb, bpattern, bhatchbkrgb;
112 } b;
113 struct font {
114 int ffont;
115 int fsize;
116 int fangle;
117 } f;
118 } eh_un;
119 };
120
121 static struct emfhandle *handles;
122 static struct emfhandle *latesthandle;
123
124
125 static int rounded_arrows; /* If rounded_arrows is False, the position
126 * of arrows will be corrected for
127 * compensating line width effects. This
128 * correction is not needed if arrows appear
129 * rounded with the used EMF viewer.
130 * See -r driver command line option. */
131
132 /* EMF compatibility level */
133 static enum emfcompatlevel {
134 EMF_LEVEL_WIN95, /* Windows 95 */
135 EMF_LEVEL_WIN98, /* Windows 98/Me */
136 EMF_LEVEL_WINNT /* Windows NT/2000/XP (Windows NT 3.1 and later) */
137 } emflevel = EMF_LEVEL_WINNT;
138 const char *const emflevelname[] = { "win95", "win98", "winnt" };
139
140 typedef struct Dir {double x, y;} Dir;
141 #define ARROW_INDENT_DIST 0.8
142 #define ARROW_POINT_DIST 1.2
143 /* Arrows appear this much longer with projected line caps. */
144 #define ARROW_EXTRA_LEN(a) ((double)a->ht / (double)a->wid * a->thickness)
145
146 /* update bounding box */
147 #define UPDATE_BBX_X(x) \
148 do { \
149 if (bbx_left>(x)) bbx_left=(x); else if (bbx_right<(x)) bbx_right=(x);\
150 } while (0)
151 #define UPDATE_BBX_Y(y) \
152 do { \
153 if (bbx_top>(y)) bbx_top=(y); else if (bbx_bottom<(y)) bbx_bottom=(y);\
154 } while (0)
155
156
157 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
158
159 /*
160 * fill pattern bitmaps
161 */
162
163 /* pat0.xbm */
164 #define pat0_width 8
165 #define pat0_height 4
166 static unsigned char pat0_bits[] = {
167 0x03, 0x0c, 0x30, 0xc0};
168
169 /* pat1.xbm */
170 #define pat1_width 8
171 #define pat1_height 4
172 static unsigned char pat1_bits[] = {
173 0xc0, 0x30, 0x0c, 0x03};
174
175 /* pat2.xbm */
176 #define pat2_width 8
177 #define pat2_height 4
178 static unsigned char pat2_bits[] = {
179 0x81, 0x66, 0x18, 0x66};
180
181 #if 0 /* mapped to EMF pattern */
182 /* pat3.xbm */
183 #define pat3_width 8
184 #define pat3_height 8
185 static unsigned char pat3_bits[] = {
186 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
187
188 /* pat4.xbm */
189 #define pat4_width 8
190 #define pat4_height 8
191 static unsigned char pat4_bits[] = {
192 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
193
194 /* pat5.xbm */
195 #define pat5_width 8
196 #define pat5_height 8
197 static unsigned char pat5_bits[] = {
198 0x11, 0x0a, 0x04, 0x0a, 0x11, 0xa0, 0x40, 0xa0};
199 #endif
200
201 /* pat6.xbm */
202 #define pat6_width 16
203 #define pat6_height 16
204 static unsigned char pat6_bits[] = {
205 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
206 0x00, 0x80, 0xff, 0xff, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
207 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xff, 0xff};
208
209 /* pat7.xbm */
210 #define pat7_width 16
211 #define pat7_height 16
212 static unsigned char pat7_bits[] = {
213 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
214 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
215 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
216
217 #if 0 /* mapped to EMF pattern */
218 /* pat8.xbm */
219 #define pat8_width 8
220 #define pat8_height 4
221 static unsigned char pat8_bits[] = {
222 0xff, 0x00, 0x00, 0x00};
223
224 /* pat9.xbm */
225 #define pat9_width 8
226 #define pat9_height 4
227 static unsigned char pat9_bits[] = {
228 0x88, 0x88, 0x88, 0x88};
229
230 /* pat10.xbm */
231 #define pat10_width 8
232 #define pat10_height 4
233 static unsigned char pat10_bits[] = {
234 0xff, 0x88, 0x88, 0x88};
235 #endif
236
237 /* pat11.xbm */
238 #define pat11_width 24
239 #define pat11_height 24
240 static unsigned char pat11_bits[] = {
241 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
242 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff,
243 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00,
244 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff,
245 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
246 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff};
247
248 /* pat12.xbm */
249 #define pat12_width 24
250 #define pat12_height 24
251 static unsigned char pat12_bits[] = {
252 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20,
253 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
254 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00,
255 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff,
256 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00,
257 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff};
258
259 /* pat13.xbm */
260 #define pat13_width 24
261 #define pat13_height 24
262 static unsigned char pat13_bits[] = {
263 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
264 0x80, 0x80, 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0,
265 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
266 0x80, 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0, 0x80,
267 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
268 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0, 0x80, 0x80};
269
270 /* pat14.xbm */
271 #define pat14_width 24
272 #define pat14_height 24
273 static unsigned char pat14_bits[] = {
274 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
275 0x80, 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83, 0x80,
276 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
277 0x80, 0x80, 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83,
278 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
279 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83, 0x80, 0x80};
280
281 /* pat15.xbm */
282 #define pat15_width 16
283 #define pat15_height 8
284 static unsigned char pat15_bits[] = {
285 0x40, 0x02, 0x30, 0x0c, 0x0e, 0x70, 0x01, 0x80, 0x02, 0x40, 0x0c, 0x30,
286 0x70, 0x0e, 0x80, 0x01};
287
288 /* pat16.xbm */
289 #define pat16_width 8
290 #define pat16_height 8
291 static unsigned char pat16_bits[] = {
292 0x01, 0x01, 0x82, 0x6c, 0x10, 0x10, 0x28, 0xc6};
293
294 /* pat17.xbm */
295 #define pat17_width 16
296 #define pat17_height 16
297 static unsigned char pat17_bits[] = {
298 0xe0, 0x0f, 0x18, 0x30, 0x04, 0x40, 0x02, 0x80, 0x02, 0x80, 0x01, 0x00,
299 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
300 0x02, 0x80, 0x02, 0x80, 0x04, 0x40, 0x18, 0x30};
301
302 /* pat18.xbm */
303 #define pat18_width 30
304 #define pat18_height 18
305 static unsigned char pat18_bits[] = {
306 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00,
307 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
308 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x3f,
309 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00,
310 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
311 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00};
312
313 /* pat19.xbm */
314 #define pat19_width 16
315 #define pat19_height 16
316 static unsigned char pat19_bits[] = {
317 0xe0, 0x0f, 0x10, 0x10, 0x08, 0x20, 0x04, 0x40, 0x02, 0x80, 0x01, 0x00,
318 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
319 0x02, 0x80, 0x04, 0x40, 0x08, 0x20, 0x10, 0x10};
320
321 /* pat20.xbm */
322 #define pat20_width 8
323 #define pat20_height 8
324 static unsigned char pat20_bits[] = {
325 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x80};
326
327 /* pat21.xbm */
328 #define pat21_width 8
329 #define pat21_height 8
330 static unsigned char pat21_bits[] = {
331 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x01};
332
333 const struct emf_bmpat {
334 unsigned width, height;
335 unsigned char *bits;
336 } emf_bm_pattern[22] = {
337 { pat0_width, pat0_height, pat0_bits },
338 { pat1_width, pat1_height, pat1_bits },
339 { pat2_width, pat2_height, pat2_bits },
340 { 0, 0, 0 }, /* mapped to EMF pattern */
341 { 0, 0, 0 }, /* mapped to EMF pattern */
342 { 0, 0, 0 }, /* mapped to EMF pattern */
343 { pat6_width, pat6_height, pat6_bits },
344 { pat7_width, pat7_height, pat7_bits },
345 { 0, 0, 0 }, /* mapped to EMF pattern */
346 { 0, 0, 0 }, /* mapped to EMF pattern */
347 { 0, 0, 0 }, /* mapped to EMF pattern */
348 { pat11_width, pat11_height, pat11_bits },
349 { pat12_width, pat12_height, pat12_bits },
350 { pat13_width, pat13_height, pat13_bits },
351 { pat14_width, pat14_height, pat14_bits },
352 { pat15_width, pat15_height, pat15_bits },
353 { pat16_width, pat16_height, pat16_bits },
354 { pat17_width, pat17_height, pat17_bits },
355 { pat18_width, pat18_height, pat18_bits },
356 { pat19_width, pat19_height, pat19_bits },
357 { pat20_width, pat20_height, pat20_bits },
358 { pat21_width, pat21_height, pat21_bits }
359 };
360
361 /* EMF patterns are numbered 0-5 (I use -1 for bitmap patterns) */
362 int emf_map_pattern[22] = { -1, -1, -1, HS_FDIAGONAL,
363 HS_BDIAGONAL, HS_DIAGCROSS, -1, -1,
364 HS_HORIZONTAL, HS_VERTICAL, HS_CROSS, -1,
365 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
366
367
368 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
369
370 static int ltFonts[] = { /* Convert from LaTeX fonts to PostScript */
371 0, /* default */
372 0, /* Roman */
373 2, /* Bold */
374 1, /* Italic */
375 4, /* Modern */
376 12, /* Typewriter */
377 };
378
379 static char *lfFaceName[] = {
380 "Times", /* Times-Roman */
381 "Times", /* Times-Italic */
382 "Times", /* Times-Bold */
383 "Times", /* Times-BoldItalic */
384 "AvantGarde", /* AvantGarde */
385 "AvantGarde", /* AvantGarde-BookOblique */
386 "AvantGarde", /* AvantGarde-Demi */
387 "AvantGarde", /* AvantGarde-DemiOblique */
388 "Bookman", /* Bookman-Light */
389 "Bookman", /* Bookman-LightItalic */
390 "Bookman", /* Bookman-Demi */
391 "Bookman", /* Bookman-DemiItalic */
392 "Courier", /* Courier */
393 "Courier", /* Courier-Oblique */
394 "Courier", /* Courier-Bold */
395 "Courier", /* Courier-BoldItalic */
396 "Helvetica", /* Helvetica */
397 "Helvetica", /* Helvetica-Oblique */
398 "Helvetica", /* Helvetica-Bold */
399 "Helvetica", /* Helvetica-BoldOblique */
400 "Helvetica-Narrow", /* Helvetica-Narrow */
401 "Helvetica-Narrow", /* Helvetica-Narrow-Oblique */
402 "Helvetica-Narrow", /* Helvetica-Narrow-Bold */
403 "Helvetica-Narrow", /* Helvetica-Narrow-BoldOblique */
404 "NewCenturySchlbk", /* NewCenturySchlbk-Roman */
405 "NewCenturySchlbk", /* NewCenturySchlbk-Italic */
406 "NewCenturySchlbk", /* NewCenturySchlbk-Bold */
407 "NewCenturySchlbk", /* NewCenturySchlbk-BoldItalic */
408 "Palatino", /* Palatino-Roman */
409 "Palatino", /* Palatino-Italic */
410 "Palatino", /* Palatino-Bold */
411 "Palatino", /* Palatino-BoldItalic */
412 "Symbol", /* Symbol */
413 "ZapfChancery", /* ZapfChancery-MediumItalic */
414 "ZapfDingbats" /* ZapfDingbats */
415 };
416
417 static int lfWeight[] = {
418 FW_NORMAL, /* Times-Roman */
419 FW_NORMAL, /* Times-Italic */
420 FW_BOLD, /* Times-Bold */
421 FW_BOLD, /* Times-BoldItalic */
422 FW_NORMAL, /* AvantGarde */
423 FW_NORMAL, /* AvantGarde-BookOblique */
424 FW_DEMIBOLD, /* AvantGarde-Demi */
425 FW_DEMIBOLD, /* AvantGarde-DemiOblique */
426 FW_LIGHT, /* Bookman-Light */
427 FW_LIGHT, /* Bookman-LightItalic */
428 FW_DEMIBOLD, /* Bookman-Demi */
429 FW_DEMIBOLD, /* Bookman-DemiItalic */
430 FW_NORMAL, /* Courier */
431 FW_NORMAL, /* Courier-Oblique */
432 FW_BOLD, /* Courier-Bold */
433 FW_BOLD, /* Courier-BoldItalic */
434 FW_NORMAL, /* Helvetica */
435 FW_NORMAL, /* Helvetica-Oblique */
436 FW_BOLD, /* Helvetica-Bold */
437 FW_BOLD, /* Helvetica-BoldOblique */
438 FW_NORMAL, /* Helvetica-Narrow */
439 FW_NORMAL, /* Helvetica-Narrow-Oblique */
440 FW_BOLD, /* Helvetica-Narrow-Bold */
441 FW_BOLD, /* Helvetica-Narrow-BoldOblique */
442 FW_NORMAL, /* NewCenturySchlbk-Roman */
443 FW_NORMAL, /* NewCenturySchlbk-Italic */
444 FW_BOLD, /* NewCenturySchlbk-Bold */
445 FW_BOLD, /* NewCenturySchlbk-BoldItalic */
446 FW_NORMAL, /* Palatino-Roman */
447 FW_NORMAL, /* Palatino-Italic */
448 FW_BOLD, /* Palatino-Bold */
449 FW_BOLD, /* Palatino-BoldItalic */
450 FW_NORMAL, /* Symbol */
451 FW_NORMAL, /* ZapfChancery-MediumItalic */
452 FW_NORMAL /* ZapfDingbats */
453 };
454
455 static uchar lfItalic[] = {
456 False, /* Times-Roman */
457 True, /* Times-Italic */
458 False, /* Times-Bold */
459 True, /* Times-BoldItalic */
460 False, /* AvantGarde */
461 True, /* AvantGarde-BookOblique */
462 False, /* AvantGarde-Demi */
463 True, /* AvantGarde-DemiOblique */
464 False, /* Bookman-Light */
465 True, /* Bookman-LightItalic */
466 False, /* Bookman-Demi */
467 True, /* Bookman-DemiItalic */
468 False, /* Courier */
469 True, /* Courier-Oblique */
470 False, /* Courier-Bold */
471 True, /* Courier-BoldItalic */
472 False, /* Helvetica */
473 True, /* Helvetica-Oblique */
474 False, /* Helvetica-Bold */
475 True, /* Helvetica-BoldOblique */
476 False, /* Helvetica-Narrow */
477 True, /* Helvetica-Narrow-Oblique */
478 False, /* Helvetica-Narrow-Bold */
479 True, /* Helvetica-Narrow-BoldOblique */
480 False, /* NewCenturySchlbk-Roman */
481 True, /* NewCenturySchlbk-Italic */
482 False, /* NewCenturySchlbk-Bold */
483 True, /* NewCenturySchlbk-BoldItalic */
484 False, /* Palatino-Roman */
485 True, /* Palatino-Italic */
486 False, /* Palatino-Bold */
487 True, /* Palatino-BoldItalic */
488 False, /* Symbol */
489 False, /* ZapfChancery-MediumItalic */
490 False /* ZapfDingbats */
491 };
492
493 static uchar lfCharSet[] = {
494 ANSI_CHARSET, /* Times-Roman */
495 ANSI_CHARSET, /* Times-Italic */
496 ANSI_CHARSET, /* Times-Bold */
497 ANSI_CHARSET, /* Times-BoldItalic */
498 ANSI_CHARSET, /* AvantGarde */
499 ANSI_CHARSET, /* AvantGarde-BookOblique */
500 ANSI_CHARSET, /* AvantGarde-Demi */
501 ANSI_CHARSET, /* AvantGarde-DemiOblique */
502 ANSI_CHARSET, /* Bookman-Light */
503 ANSI_CHARSET, /* Bookman-LightItalic */
504 ANSI_CHARSET, /* Bookman-Demi */
505 ANSI_CHARSET, /* Bookman-DemiItalic */
506 ANSI_CHARSET, /* Courier */
507 ANSI_CHARSET, /* Courier-Oblique */
508 ANSI_CHARSET, /* Courier-Bold */
509 ANSI_CHARSET, /* Courier-BoldItalic */
510 ANSI_CHARSET, /* Helvetica */
511 ANSI_CHARSET, /* Helvetica-Oblique */
512 ANSI_CHARSET, /* Helvetica-Bold */
513 ANSI_CHARSET, /* Helvetica-BoldOblique */
514 ANSI_CHARSET, /* Helvetica-Narrow */
515 ANSI_CHARSET, /* Helvetica-Narrow-Oblique */
516 ANSI_CHARSET, /* Helvetica-Narrow-Bold */
517 ANSI_CHARSET, /* Helvetica-Narrow-BoldOblique */
518 ANSI_CHARSET, /* NewCenturySchlbk-Roman */
519 ANSI_CHARSET, /* NewCenturySchlbk-Italic */
520 ANSI_CHARSET, /* NewCenturySchlbk-Bold */
521 ANSI_CHARSET, /* NewCenturySchlbk-BoldItalic */
522 ANSI_CHARSET, /* Palatino-Roman */
523 ANSI_CHARSET, /* Palatino-Italic */
524 ANSI_CHARSET, /* Palatino-Bold */
525 ANSI_CHARSET, /* Palatino-BoldItalic */
526 SYMBOL_CHARSET, /* Symbol */
527 SYMBOL_CHARSET, /* ZapfChancery-MediumItalic */
528 SYMBOL_CHARSET /* ZapfDingbats */
529 };
530
531 static uchar lfPitchAndFamily[] = {
532 VARIABLE_PITCH | FF_ROMAN, /* Times-Roman */
533 VARIABLE_PITCH | FF_ROMAN, /* Times-Italic */
534 VARIABLE_PITCH | FF_ROMAN, /* Times-Bold */
535 VARIABLE_PITCH | FF_ROMAN, /* Times-BoldItalic */
536 VARIABLE_PITCH | FF_ROMAN, /* AvantGarde */
537 VARIABLE_PITCH | FF_ROMAN, /* AvantGarde-BookOblique */
538 VARIABLE_PITCH | FF_ROMAN, /* AvantGarde-Demi */
539 VARIABLE_PITCH | FF_ROMAN, /* AvantGarde-DemiOblique */
540 VARIABLE_PITCH | FF_ROMAN, /* Bookman-Light */
541 VARIABLE_PITCH | FF_ROMAN, /* Bookman-LightItalic */
542 VARIABLE_PITCH | FF_ROMAN, /* Bookman-Demi */
543 VARIABLE_PITCH | FF_ROMAN, /* Bookman-DemiItalic */
544 FIXED_PITCH | FF_MODERN, /* Courier */
545 FIXED_PITCH | FF_MODERN, /* Courier-Oblique */
546 FIXED_PITCH | FF_MODERN, /* Courier-Bold */
547 FIXED_PITCH | FF_MODERN, /* Courier-BoldItalic */
548 VARIABLE_PITCH | FF_ROMAN, /* Helvetica */
549 VARIABLE_PITCH | FF_ROMAN, /* Helvetica-Oblique */
550 VARIABLE_PITCH | FF_ROMAN, /* Helvetica-Bold */
551 VARIABLE_PITCH | FF_ROMAN, /* Helvetica-BoldOblique */
552 VARIABLE_PITCH | FF_ROMAN, /* Helvetica-Narrow */
553 VARIABLE_PITCH | FF_ROMAN, /* Helvetica-Narrow-Oblique */
554 VARIABLE_PITCH | FF_ROMAN, /* Helvetica-Narrow-Bold */
555 VARIABLE_PITCH | FF_ROMAN, /* Helvetica-Narrow-BoldOblique */
556 VARIABLE_PITCH | FF_ROMAN, /* NewCenturySchlbk-Roman */
557 VARIABLE_PITCH | FF_ROMAN, /* NewCenturySchlbk-Italic */
558 VARIABLE_PITCH | FF_ROMAN, /* NewCenturySchlbk-Bold */
559 VARIABLE_PITCH | FF_ROMAN, /* NewCenturySchlbk-BoldItalic */
560 VARIABLE_PITCH | FF_ROMAN, /* Palatino-Roman */
561 VARIABLE_PITCH | FF_ROMAN, /* Palatino-Italic */
562 VARIABLE_PITCH | FF_ROMAN, /* Palatino-Bold */
563 VARIABLE_PITCH | FF_ROMAN, /* Palatino-BoldItalic */
564 VARIABLE_PITCH | FF_ROMAN, /* Symbol */
565 VARIABLE_PITCH | FF_ROMAN, /* ZapfChancery-MediumItalic */
566 VARIABLE_PITCH | FF_ROMAN, /* ZapfDingbats */
567 };
568
569 #if defined(I18N) && defined(USE_ICONV)
570 extern Boolean support_i18n; /* enable i18n support? */
571
572 #define FONT_TIMES_ROMAN 0
573 #define FONT_TIMES_BOLD 2
574 #define IS_LOCALE_FONT(f) ((f) == FONT_TIMES_ROMAN || (f) == FONT_TIMES_BOLD)
575
576 #define FONT_LOCALE_ROMAN -1
577 #define FONT_LOCALE_BOLD -2
578
579 enum genemf_lang {
580 LANG_DEFAULT,
581 LANG_ZH_CN,
582 LANG_ZH_TW,
583 LANG_JA,
584 LANG_KO
585 } figLanguage;
586
587 /* EUC codeset name for iconv(3) */
588 static const char *const iconvCharset[] = {
589 "ASCII", /* placeholder */
590 "eucCN",
591 "eucTW",
592 "eucJP",
593 "eucKR"
594 };
595
596 /* EMF codeset name for iconv(3) */
597 #ifdef __hpux
598 # define EMF_ICONV_CODESET "ucs2" /* convert to big endian Unicode */
599 # define EMF_ICONV_NEED_SWAP 1 /* and swap the byte order */
600 #else
601 # define EMF_ICONV_CODESET "UTF-16LE"
602 #endif
603
604 /* localized fonts */
605 static const struct localefnt {
606 const char *FaceName; /* font name in EUC of the language */
607 int Weight;
608 uchar Italic, Charset, PitchAndFamily;
609 } localeFonts[2][5] = { {
610 { "Times", FW_NORMAL, False, DEFAULT_CHARSET, FIXED_PITCH|FF_DONTCARE },
611 { "SimSun",
612 FW_NORMAL, False, GB2312_CHARSET, FIXED_PITCH|FF_DONTCARE },
613 { "MingLiU",
614 FW_NORMAL, False, CHINESEBIG5_CHARSET, FIXED_PITCH|FF_DONTCARE },
615 { "\243\315\243\323 \314\300\304\253", /* MS Mincho */
616 FW_NORMAL, False, SHIFTJIS_CHARSET, FIXED_PITCH|FF_DONTCARE },
617 { "Batang",
618 FW_NORMAL, False, HANGUL_CHARSET, FIXED_PITCH|FF_DONTCARE }
619 }, {
620 { "Times", FW_BOLD, False, DEFAULT_CHARSET, FIXED_PITCH|FF_DONTCARE },
621 { "SimHei",
622 FW_MEDIUM, False, GB2312_CHARSET, FIXED_PITCH|FF_DONTCARE },
623 { "MingLiU",
624 FW_BOLD, False, CHINESEBIG5_CHARSET, FIXED_PITCH|FF_DONTCARE },
625 { "\243\315\243\323 \245\264\245\267\245\303\245\257", /* MS Gothic */
626 FW_MEDIUM, False, SHIFTJIS_CHARSET, FIXED_PITCH|FF_DONTCARE },
627 { "Gungsuh",
628 FW_MEDIUM, False, HANGUL_CHARSET, FIXED_PITCH|FF_DONTCARE }
629 } };
630 #endif /* defined(I18N) && defined(USE_ICONV) */
631
632
633 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
634
635
636 static void delete_handle();
637 static void clear_current_handle();
638 static void select_object();
639 static void use_handle();
640 static struct emfhandle *get_handle();
641 static int conv_color();
642 static int conv_fill_color();
643 static int conv_fontindex();
644 static int conv_capstyle();
645 static int conv_joinstyle();
646 static int conv_linetype();
647 static void edgeattr();
648 static void edgevis();
649 static void bkmode();
650 static void bkcolor();
651 static void create_brush_pattern();
652 static void fillstyle();
653 static void textfont();
654 static void warn_32bit_pos();
655 static void pos2point();
656 static double arrow_length();
657 static void arrow();
658 static void arc_arrow();
659 static void arc_arrow_adjust();
660 static double arc_radius();
661 static void translate();
662 static void rotate();
663 static void arc_rotate();
664 static void arcoutline();
665 static void arcinterior();
666 static void arc_reverse();
667 static void circle();
668 static void ellipse();
669 static void rotated_ellipse();
670 static int icprod();
671 static int cwarc();
672 static int direction();
673 static double distance();
674 static size_t emh_write();
675 static int is_flip();
676 static void encode_bitmap();
677 static void picbox();
678 static void polygon();
679 static int polyline_adjust();
680 static void polyline();
681 static void rect();
682 static void roundrect();
683 static void shape();
684 static void shape_interior();
685 static void textunicode();
686 static void text();
687 static void textcolr();
688 static void textalign();
689 #if defined(I18N) && defined(USE_ICONV)
690 static void moveto();
691 #endif
692
693 extern FILE *open_picfile();
694 extern void close_picfile();
695 #ifdef USE_PNG
696 extern int read_png();
697 #endif
698
699 /* Piece of code to avoid unnecessary attribute changes */
700 #define chkcache(val, cachedval) \
701 if (val == cachedval) \
702 return; \
703 else \
704 cachedval = val;
705
706
707 /* Delete an object by handle structure. */
delete_handle(h)708 static void delete_handle(h)
709 struct emfhandle *h;
710 {
711 EMRSELECTOBJECT em_so; /* EMRDELETEOBJECT */
712
713 /* If this is selected, select a stock object before deleting it. */
714 if (h->is_current) {
715 em_so.emr.iType = htofl(EMR_SELECTOBJECT);
716 em_so.emr.nSize = htofl(sizeof(EMRSELECTOBJECT));
717 switch (h->type) {
718 case EMFH_PEN:
719 em_so.ihObject = htofl(ENHMETA_STOCK_OBJECT | BLACK_PEN);
720 lasthandle[EMFH_PEN] = ENHMETA_STOCK_OBJECT | BLACK_PEN;
721 break;
722 case EMFH_BRUSH:
723 em_so.ihObject = htofl(ENHMETA_STOCK_OBJECT | WHITE_BRUSH);
724 lasthandle[EMFH_BRUSH] = ENHMETA_STOCK_OBJECT | WHITE_BRUSH;
725 break;
726 case EMFH_FONT:
727 em_so.ihObject = htofl(ENHMETA_STOCK_OBJECT | SYSTEM_FONT);
728 lasthandle[EMFH_FONT] = ENHMETA_STOCK_OBJECT | SYSTEM_FONT;
729 break;
730 default:
731 fprintf(stderr, "genemf: unknown handle type %d.\n", h->type);
732 exit(1);
733 }
734
735 # ifdef __EMF_DEBUG__
736 fprintf(stderr, "SelectObject: %u\n", ftohl(em_so.ihObject));
737 # endif
738
739 emh_write(&em_so, sizeof(EMRSELECTOBJECT), (size_t) 1, EMH_RECORD);
740 h->is_current = False;
741 }
742
743 em_so.emr.iType = htofl(EMR_DELETEOBJECT);
744 em_so.emr.nSize = htofl(sizeof(EMRDELETEOBJECT));
745
746 em_so.ihObject = htofl(h->handle);
747
748 # ifdef __EMF_DEBUG__
749 fprintf(stderr, "DeleteObject: %u\n", ftohl(em_so.ihObject));
750 # endif
751
752 emh_write(&em_so, sizeof(EMRDELETEOBJECT), (size_t) 1, EMH_RECORD);
753 }
754
755
756 /* Clear current mark from objects of the specified type. */
clear_current_handle(type)757 static void clear_current_handle(type)
758 enum emfhandletype type;
759 {
760 struct emfhandle *h;
761
762 for (h = handles; h; h = h->next)
763 if (h->is_current && h->type == type) {
764 h->is_current = False;
765 break;
766 }
767 }
768
769
770 /* Select object by handle number. */
select_object(handle)771 static void select_object(handle)
772 unsigned handle;
773 {
774 EMRSELECTOBJECT em_so;
775
776 em_so.emr.iType = htofl(EMR_SELECTOBJECT);
777 em_so.emr.nSize = htofl(sizeof(EMRSELECTOBJECT));
778 em_so.ihObject = htofl(handle);
779
780 # ifdef __EMF_DEBUG__
781 fprintf(stderr, "SelectObject: %u\n", ftohl(em_so.ihObject));
782 # endif
783
784 emh_write(&em_so, sizeof(EMRSELECTOBJECT), (size_t) 1, EMH_RECORD);
785 }
786
787
788 /* Add a handle structure to the newest position of handle list. */
use_handle(h)789 static void use_handle(h)
790 struct emfhandle *h;
791 {
792
793 if (h != latesthandle) {
794 if (h->prev) {
795 /* unlink from list */
796 if (h->next)
797 h->next->prev = h->prev;
798 *h->prev = h->next;
799 }
800 if (handles == NULL) {
801 handles = h;
802 h->prev = &handles;
803 } else
804 h->prev = &latesthandle->next;
805 *h->prev = h;
806 h->next = NULL;
807 latesthandle = h;
808 }
809 }
810
811
812 /*
813 * Allocate handle structure. If the number of currently allocated handle
814 * exceeds maximum limit, reuse the least recently used handle.
815 */
get_handle(type)816 static struct emfhandle *get_handle(type)
817 enum emfhandletype type;
818 {
819 struct emfhandle *h;
820
821 if (emh_nHandles >= maxHandles) {
822 /* reuse handle (LRU) */
823 for (h = handles; h; h = h->next) {
824 if (!h->is_current) {
825 /* use it */
826 delete_handle(h);
827 goto use;
828 }
829 }
830 /*
831 * All handles are currently in use.
832 * Although exceeds maxHandles, create new one
833 */
834 /* FALLTHROUGH */
835 }
836
837 /* allocate new handle */
838 if ((h = malloc(sizeof(struct emfhandle))) == NULL) {
839 perror("fig2dev: malloc");
840 exit(1);
841 }
842 emh_nHandles++;
843 h->handle = emh_nHandles;
844 h->prev = NULL;
845 h->next = NULL;
846 h->is_current = False;
847 use:
848 h->type = type;
849
850 return h;
851 }
852
853
854 /* Given an index into either the standard color list or into the
855 * user defined color list, return the hex RGB value of the color. */
conv_color(colorIndex)856 static int conv_color(colorIndex)
857 int colorIndex;
858 {
859 int rgb;
860 static const int rgbColors[NUM_STD_COLS] = {
861 /* Black Blue Green Cyan Red Magenta */
862 0x000000, 0x0000FF, 0x00FF00, 0x00FFFF, 0xFF0000, 0xFF00FF,
863 /* Yellow White Blue4 Blue3 Blue2 LtBlue */
864 0xFFFF00, 0xFFFFFF, 0x000090, 0x0000B0, 0x0000D0, 0x87CEFF,
865 /* Green4 Green3 Green2 Cyan4 Cyan3 Cyan2 */
866 0x009000, 0x00B000, 0x00D000, 0x009090, 0x00B0B0, 0x00D0D0,
867 /* Red4 Red3 Red2 Magenta4 Magenta3 Magenta2 */
868 0x900000, 0xB00000, 0xD00000, 0x900090, 0xB000B0, 0xD000D0,
869 /* Brown4 Brown3 Brown2 Pink4 Pink3 Pink2 */
870 0x803000, 0xA04000, 0xC06000, 0xFF8080, 0xFFA0A0, 0xFFC0C0,
871 /* Pink Gold */
872 0xFFE0E0, 0xFFD700
873 };
874
875 if (colorIndex == DEFAULT)
876 colorIndex = 0;
877
878 if (colorIndex < NUM_STD_COLS)
879 rgb = RGB(rgbColors[colorIndex] >> 16,
880 (rgbColors[colorIndex] >> 8) & 0xff,
881 rgbColors[colorIndex] & 0xff);
882 else
883 rgb = RGB(user_colors[colorIndex-NUM_STD_COLS].r,
884 user_colors[colorIndex-NUM_STD_COLS].g,
885 user_colors[colorIndex-NUM_STD_COLS].b);
886 return rgb;
887 }/* end conv_color */
888
889
890 /* Converts fill pattern color. The style contains the fill intensity.
891 * 0 - 20 - 40 is equivalent to -1.0 - 0.0 - +1.0. */
conv_fill_color(style,color)892 static int conv_fill_color(style, color)
893 int style;
894 int color;
895 {
896 int rgb, b, g, r;
897 float f;
898
899 rgb = conv_color(color);
900 b = GetBValue(rgb);
901 g = GetGValue(rgb);
902 r = GetRValue(rgb);
903
904 if (style <= 0) { /* Black */
905
906 b = 0;
907 g = 0;
908 r = 0;
909
910 } else if (style < 20) { /* Darkened */
911
912 f = (float)style / 20.0;
913 b = round(b * f);
914 g = round(g * f);
915 r = round(r * f);
916
917 } else if (style == 20) { /* Normal */
918
919 /* : */
920
921 } else if (style < 40) { /* Lightened */
922
923 f = (float)(style - 20) / 20.0;
924 b = round(b + f*(255-b));
925 g = round(g + f*(255-g));
926 r = round(r + f*(255-r));
927
928 } else {/* if (style >= 40) */ /* White */
929
930 b = 0xFF;
931 g = 0xFF;
932 r = 0xFF;
933
934 }/* end if (style >= 40) */
935
936 return RGB(r, g, b);
937 }/* end conv_fill_color */
938
939
940 /* Converts Fig font index to index into font table in the pre-amble,
941 * taking into account the flags. */
conv_fontindex(font,flags)942 static int conv_fontindex(font, flags)
943 int font;
944 int flags;
945 {
946
947 if (flags&4) { /* PostScript fonts */
948 if (font == (-1)) {
949 font = 0; /* Default PostScript is Roman */
950 } else if ((font < 0) || (font >= NUM_PS_FONTS)) {
951 fprintf(stderr, "Unsupported Fig PostScript font index %d.\n",
952 font);
953 font = 0; /* Default font */
954 }
955 } else { /* LaTeX fonts */
956 if ((font < 0) || (font > NUM_LATEX_FONTS)) {
957 fprintf(stderr, "Unsupported Fig LaTeX font index %d.\n", font);
958 font = 0; /* Default font */
959 }
960 else
961 font = ltFonts[font]; /* Convert to PostScript fonts */
962 }
963 return font;
964 }/* end conv_fontindex */
965
966
967 /* Convert fig cap style to EMF line style. */
conv_capstyle(cap)968 static int conv_capstyle(cap)
969 int cap;
970 {
971
972 switch (cap) {
973 case 0: /* Butt. */
974 cap = PS_ENDCAP_FLAT;
975 break;
976 case 1: /* Round. */
977 cap = PS_ENDCAP_ROUND;
978 break;
979 case 2: /* Projecting. */
980 cap = PS_ENDCAP_SQUARE;
981 break;
982 default:
983 fprintf(stderr, "genemf: unknown cap style %d.\n", cap);
984 cap = PS_ENDCAP_FLAT;
985 break;
986 }
987 return cap;
988 }/* end conv_capstyle */
989
990
991 /* Convert fig join style to EMF join style. */
conv_joinstyle(join)992 static int conv_joinstyle(join)
993 int join;
994 {
995
996 switch (join) {
997 case 0: /* Miter. */
998 join = PS_JOIN_MITER;
999 break;
1000 case 1: /* Round. */
1001 join = PS_JOIN_ROUND;
1002 break;
1003 case 2: /* Bevel. */
1004 join = PS_JOIN_BEVEL;
1005 break;
1006 default:
1007 fprintf(stderr, "genemf: unknown join style %d.\n", join);
1008 join = PS_JOIN_MITER;
1009 break;
1010 }
1011 return join;
1012 }/* end conv_joinstyle */
1013
1014
1015 /* Convert fig line style to EMF line style. EMF knows 5 styles with
1016 * fortunately correspond to the first 5 fig line styles. The triple
1017 * dotted fig line style is handled as a solid line here. */
conv_linetype(type)1018 static int conv_linetype(type)
1019 int type;
1020 {
1021
1022 if (type < 0)
1023 type = -1;
1024 else if (type > 4)
1025 type %= 5;
1026 return type;
1027 }/* end conv_linetype */
1028
1029
1030 /* This procedure sets the pen line attributes and selects the pen into
1031 * the device context. */
edgeattr(vis,type,width,color,join,cap)1032 static void edgeattr(vis, type, width, color, join, cap)
1033 int vis; /* visible */
1034 int type; /* line type */
1035 int width, color;
1036 int join; /* join style */
1037 int cap; /* cap style */
1038 {
1039 unsigned handle;
1040 int rgb;
1041 EMREXTCREATEPEN em_pn;
1042 struct emfhandle *h = NULL;
1043 int style;
1044 unsigned styleEntry[8]; /* "- . . . " */
1045 int user_style = False;
1046
1047 if (width == 0)
1048 vis = 0;
1049
1050 /* if a stock object is available, use it */
1051 if (vis == 0) {
1052 handle = ENHMETA_STOCK_OBJECT | NULL_PEN;
1053 goto selectpen;
1054 }
1055
1056 rgb = conv_color(color);
1057 style = PS_GEOMETRIC;
1058
1059 switch (emflevel) {
1060 case EMF_LEVEL_WIN98:
1061 if (type >= 1 && type <= 4) {
1062 fprintf(stderr, "Warning: line style may be ignored\n");
1063 }
1064 break;
1065
1066 case EMF_LEVEL_WIN95:
1067 if (type >= 1 && type <= 4) {
1068 if (width < 20) {
1069 fprintf(stderr, "Warning: this style of line is converted to thin line\n");
1070 style = PS_COSMETIC;
1071 } else
1072 fprintf(stderr, "Warning: line style may be ignored\n");
1073 }
1074 break;
1075
1076 default:
1077 break;
1078 }
1079
1080 switch (emflevel) {
1081 case EMF_LEVEL_WINNT:
1082 if (type == 5) {
1083 style |= PS_USERSTYLE;
1084 user_style = True;
1085 } else
1086 style |= conv_linetype(type);
1087 break;
1088
1089 default:
1090 if (type == 5) {
1091 fprintf(stderr, "Warning: dash-triple-dotted style is converted to solid style\n");
1092 type = 0;
1093 }
1094 style |= conv_linetype(type);
1095 break;
1096 }
1097 style |= conv_capstyle(cap) | conv_joinstyle(join);
1098
1099 /* search for the same pen */
1100 for (h = latesthandle; h != (void *)&handles; h = (void *) h->prev) {
1101 if (h->type == EMFH_PEN &&
1102 h->eh_un.p.pstyle == style && h->eh_un.p.pwidth == width &&
1103 h->eh_un.p.prgb == rgb) {
1104 /* found */
1105 use_handle(h);
1106 handle = h->handle;
1107 goto selectpen;
1108 }
1109 }
1110
1111 /* not found -- create new pen */
1112 h = get_handle(EMFH_PEN);
1113 handle = h->handle;
1114 use_handle(h);
1115
1116 h->eh_un.p.pstyle = style;
1117 h->eh_un.p.pwidth = width;
1118 h->eh_un.p.prgb = rgb;
1119
1120 memset(&em_pn, 0, sizeof(EMREXTCREATEPEN));
1121 em_pn.emr.iType = htofl(EMR_EXTCREATEPEN);
1122 em_pn.ihPen = htofl(handle);
1123 em_pn.offBmi = htofl(sizeof(EMREXTCREATEPEN));
1124 em_pn.offBits = htofl(sizeof(EMREXTCREATEPEN));
1125 em_pn.elp.elpPenStyle = htofl(style);
1126 em_pn.elp.elpWidth = htofl(width);
1127 em_pn.elp.elpColor = htofl(rgb);
1128
1129 if (user_style) {
1130 /* create dash-triple-dotted style */
1131 styleEntry[0] = htofl(width * 4); /* dash */
1132 styleEntry[1] = /* gap */
1133 styleEntry[2] = /* dot */
1134 styleEntry[3] = /* gap */
1135 styleEntry[4] = /* dot */
1136 styleEntry[5] = /* gap */
1137 styleEntry[6] = /* dot */
1138 styleEntry[7] = htofl(width); /* gap */
1139 em_pn.elp.elpNumEntries = htofl(sizeof styleEntry/sizeof styleEntry[0]);
1140 em_pn.emr.nSize = htofl(sizeof(EMREXTCREATEPEN) + sizeof styleEntry);
1141 } else {
1142 em_pn.emr.nSize = htofl(sizeof(EMREXTCREATEPEN));
1143 }
1144
1145 # ifdef __EMF_DEBUG__
1146 fprintf(stderr, "CreatePen (%d): style %d, width %d, rgb %x\n",
1147 handle, style, width, rgb);
1148 # endif
1149
1150 emh_write(&em_pn, sizeof(EMREXTCREATEPEN), (size_t) 1, EMH_RECORD);
1151 if (user_style)
1152 emh_write(&styleEntry, sizeof styleEntry, (size_t) 1, EMH_DATA);
1153
1154 selectpen:
1155 chkcache(handle, lasthandle[EMFH_PEN]);
1156 clear_current_handle(EMFH_PEN);
1157 if (h)
1158 h->is_current = True;
1159 # ifdef __EMF_DEBUG__
1160 fprintf(stderr, "Pen: ");
1161 # endif
1162 select_object(handle);
1163 }/* end edgeattr */
1164
1165
1166 /* This procedure turns off the edge visibility. */
edgevis(onoff)1167 static void edgevis(onoff)
1168 int onoff;
1169 {
1170
1171 edgeattr(onoff, 0, 0, 0, 0, 0);
1172 }/* end edgevis */
1173
1174
bkmode(mode)1175 static void bkmode(mode)
1176 int mode;
1177 {
1178 static int oldbkmode = 0;
1179 EMRSETBKMODE em_bm;
1180
1181 chkcache(mode, oldbkmode);
1182 memset(&em_bm, 0, sizeof(EMRSETBKMODE));
1183 em_bm.emr.iType = htofl(EMR_SETBKMODE);
1184 em_bm.emr.nSize = htofl(sizeof(EMRSETBKMODE));
1185 em_bm.iMode = htofl(mode);
1186
1187 # ifdef __EMF_DEBUG__
1188 fprintf(stderr, "SetBKMode (mode): %d\n", mode);
1189 # endif
1190
1191 emh_write(&em_bm, sizeof(EMRSETBKMODE), (size_t) 1, EMH_RECORD);
1192 }
1193
1194
bkcolor(rgb)1195 static void bkcolor(rgb)
1196 int rgb;
1197 {
1198 static int oldbkcolor = UNDEFVALUE;
1199 EMRSETBKCOLOR em_bc;
1200
1201 chkcache(rgb, oldbkcolor);
1202 memset(&em_bc, 0, sizeof(EMRSETBKCOLOR));
1203 em_bc.emr.iType = htofl(EMR_SETBKCOLOR);
1204 em_bc.emr.nSize = htofl(sizeof(EMRSETBKCOLOR));
1205 em_bc.crColor = htofl(rgb);
1206
1207 # ifdef __EMF_DEBUG__
1208 fprintf(stderr, "SetBKColor (rgb): %x\n", rgb);
1209 # endif
1210
1211 emh_write(&em_bc, sizeof(EMRSETBKCOLOR), (size_t) 1, EMH_RECORD);
1212 }
1213
1214
create_brush_pattern(bits,pattern)1215 static void create_brush_pattern(bits, pattern)
1216 unsigned char *bits;
1217 int pattern;
1218 {
1219 const struct emf_bmpat *pat = &emf_bm_pattern[pattern];
1220 unsigned char *b = pat->bits;
1221 int xbmhbytecnt;
1222 unsigned x;
1223 int y;
1224 unsigned byte, bit;
1225
1226 xbmhbytecnt = (pat->width + 7) / 8;
1227
1228 /* EMF bitmap is encoded from bottom to top */
1229 byte = 0;
1230 for (y = pat->height - 1; y >=0; y--) {
1231 bit = 7;
1232 for (x = 0; x < pat->width; x++) {
1233 if (b[xbmhbytecnt * y + x / 8] & (1 << x % 8))
1234 bits[byte] |= 1 << bit;
1235 if (bit-- == 0) {
1236 byte++;
1237 bit = 7;
1238 }
1239 }
1240 /* size of a line must be a multiple of 4 byte */
1241 if (bit != 7)
1242 byte++;
1243 byte = (byte + 3) & ~(unsigned)3;
1244 }
1245 }
1246
1247
1248 /* Computes and sets fill color for solid filled shapes (fill style 0 to 40). */
fillstyle(fill_color,fill_style,pen_color)1249 static void fillstyle(fill_color, fill_style, pen_color)
1250 int fill_color, fill_style, pen_color;
1251 {
1252 unsigned handle;
1253 int pattern, hatch;
1254 int rgb, hatchbkrgb;
1255 int style;
1256 EMRCREATEBRUSHINDIRECT em_bi;
1257 EMRCREATEDIBPATTERNBRUSHPT em_pb;
1258 BITMAPINFO bmi;
1259 RGBQUAD hatchcolors[2];
1260 int width, height;
1261 size_t bsize;
1262 unsigned char *bits;
1263 struct emfhandle *h = NULL;
1264
1265 if (fill_style < 0) { /* Unfilled shape */
1266 style = BS_HOLLOW;
1267 rgb = 0;
1268 hatchbkrgb = 0;
1269 pattern = 0;
1270 } else if (fill_style <= 40) { /* Solid filled shape */
1271 style = BS_SOLID;
1272 rgb = conv_fill_color(fill_style, fill_color);
1273 hatchbkrgb = 0;
1274 pattern = 0;
1275 } else /* if (fill_style > 40) */ { /* Pattern filled shape */
1276 style = BS_HATCHED;
1277 rgb = conv_color(pen_color);
1278 hatchbkrgb = conv_color(fill_color);
1279 pattern = fill_style - 41;
1280 }
1281
1282 if ((unsigned)pattern > sizeof emf_bm_pattern / sizeof emf_bm_pattern[0]) {
1283 fprintf(stderr, "fig2dev: emf: fill pattern %d is not supported\n",
1284 pattern);
1285 return;
1286 }
1287
1288 if (style == BS_HATCHED && emf_map_pattern[pattern] != -1) {
1289 /*
1290 * Use EMF hatch pattern. Setting of background color is not in brush.
1291 */
1292 bkmode(OPAQUE);
1293 bkcolor(hatchbkrgb);
1294
1295 /* The background color is now handled. */
1296 hatchbkrgb = 0;
1297 }
1298
1299 /* if a stock object is available, use it */
1300 switch (style) {
1301 case BS_HOLLOW:
1302 handle = ENHMETA_STOCK_OBJECT | NULL_BRUSH;
1303 goto selectbrush;
1304 case BS_SOLID:
1305 switch (rgb) {
1306 case 0xffffff:
1307 handle = ENHMETA_STOCK_OBJECT | WHITE_BRUSH;
1308 goto selectbrush;
1309 case 0xc0c0c0:
1310 handle = ENHMETA_STOCK_OBJECT | LTGRAY_BRUSH;
1311 goto selectbrush;
1312 case 0x808080:
1313 handle = ENHMETA_STOCK_OBJECT | GRAY_BRUSH;
1314 goto selectbrush;
1315 case 0x404040:
1316 handle = ENHMETA_STOCK_OBJECT | DKGRAY_BRUSH;
1317 goto selectbrush;
1318 case 0x000000:
1319 handle = ENHMETA_STOCK_OBJECT | BLACK_BRUSH;
1320 goto selectbrush;
1321 default:
1322 break;
1323 }
1324 break;
1325 default:
1326 break;
1327 }
1328
1329 /* search for the same brush */
1330 for (h = latesthandle; h != (void *)&handles; h = (void *) h->prev) {
1331 if (h->type == EMFH_BRUSH &&
1332 h->eh_un.b.bstyle == style && h->eh_un.b.brgb == rgb &&
1333 h->eh_un.b.bpattern == pattern &&
1334 h->eh_un.b.bhatchbkrgb == hatchbkrgb) {
1335 /* found */
1336 use_handle(h);
1337 handle = h->handle;
1338 goto selectbrush;
1339 }
1340 }
1341
1342 /* not found -- create new brush */
1343 h = get_handle(EMFH_BRUSH);
1344 handle = h->handle;
1345 use_handle(h);
1346
1347 h->eh_un.b.bstyle = style;
1348 h->eh_un.b.brgb = rgb;
1349 h->eh_un.b.bpattern = pattern;
1350 h->eh_un.b.bhatchbkrgb = hatchbkrgb;
1351
1352 hatch = 0;
1353 if (style == BS_HATCHED && (hatch = emf_map_pattern[pattern]) == -1) {
1354 /*
1355 * create a pattern brush
1356 */
1357 memset(&em_pb, 0, sizeof(EMRCREATEDIBPATTERNBRUSHPT));
1358 memset(&bmi, 0, sizeof(BITMAPINFO));
1359 em_pb.emr.iType = htofl(EMR_CREATEDIBPATTERNBRUSHPT);
1360 em_pb.ihBrush = htofl(handle);
1361 /* em_pb.iUsage = htofl(DIB_RGB_COLORS); this is default */
1362 em_pb.offBmi = htofl(sizeof(EMRCREATEDIBPATTERNBRUSHPT));
1363 em_pb.cbBmi = htofl(sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD));
1364 em_pb.offBits = htofl(sizeof(EMRCREATEDIBPATTERNBRUSHPT) +
1365 sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD));
1366
1367 width = emf_bm_pattern[pattern].width;
1368 height = emf_bm_pattern[pattern].height;
1369
1370 if (emflevel != EMF_LEVEL_WINNT && (width > 8 || height > 8))
1371 fprintf(stderr, "Warning: fill pattern %d will not appear properly on Windows 95/98/Me\n",
1372 pattern);
1373
1374 /* Windows 95/98/Me doesn't show 8x4 pat properly. Convert to 8x8. */
1375 if (height == 4)
1376 height = 8;
1377
1378 bsize = (width + 31) / 32 * height * 4;
1379
1380 bmi.bmiHeader.biSizeImage = em_pb.cbBits = htofl((EMFulong) bsize);
1381 em_pb.emr.nSize = htofl(sizeof(EMRCREATEDIBPATTERNBRUSHPT) +
1382 sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD) + bsize);
1383
1384 bmi.bmiHeader.biSize = htofl(sizeof(BITMAPINFOHEADER));
1385 bmi.bmiHeader.biWidth = htofl(width);
1386 bmi.bmiHeader.biHeight = htofl(height);
1387 bmi.bmiHeader.biPlanes = bmi.bmiHeader.biBitCount = htofs(1);
1388 bmi.bmiHeader.biCompression = htofl(BI_RGB); /* uncompressed */
1389 bmi.bmiHeader.biXPelsPerMeter =
1390 bmi.bmiHeader.biYPelsPerMeter = htofl(2953); /* 75dpi ? */
1391 bmi.bmiHeader.biClrUsed = htofl(2);
1392 /* bmi.bmiHeader.biClrImportant = htofl(0); */
1393
1394 /* background and foreground colors */
1395 hatchcolors[0].rgbBlue = GetBValue(hatchbkrgb);
1396 hatchcolors[0].rgbGreen = GetGValue(hatchbkrgb);
1397 hatchcolors[0].rgbRed = GetRValue(hatchbkrgb);
1398 hatchcolors[0].rgbReserved = 0;
1399 hatchcolors[1].rgbBlue = GetBValue(rgb);
1400 hatchcolors[1].rgbGreen = GetGValue(rgb);
1401 hatchcolors[1].rgbRed = GetRValue(rgb);
1402 hatchcolors[1].rgbReserved = 0;
1403
1404 if ((bits = malloc(bsize)) == NULL) {
1405 perror("fig2dev: malloc");
1406 exit(1);
1407 }
1408 memset(bits, 0, bsize);
1409
1410 create_brush_pattern(bits, pattern);
1411
1412 /* Windows 95/98/Me doesn't show 8x4 pat properly. Convert to 8x8. */
1413 if (emf_bm_pattern[pattern].height == 4)
1414 create_brush_pattern(bits + bsize / 2, pattern); /* latter half */
1415
1416 # ifdef __EMF_DEBUG__
1417 fprintf(stderr, "CreatePatternBrush (%d): pattern %d, rgb %x, bkrgb %x\n",
1418 handle, pattern, rgb, hatchbkrgb);
1419 # endif
1420
1421 emh_write(&em_pb, sizeof(EMRCREATEDIBPATTERNBRUSHPT), (size_t) 1,
1422 EMH_RECORD);
1423 emh_write(&bmi, sizeof(BITMAPINFO), (size_t) 1, EMH_DATA);
1424 emh_write(hatchcolors, sizeof(RGBQUAD), (size_t) 2, EMH_DATA);
1425 emh_write(bits, bsize, (size_t) 1, EMH_DATA);
1426 free(bits);
1427 } else {
1428 memset(&em_bi, 0, sizeof(EMRCREATEBRUSHINDIRECT));
1429 em_bi.emr.iType = htofl(EMR_CREATEBRUSHINDIRECT);
1430 em_bi.emr.nSize = htofl(sizeof(EMRCREATEBRUSHINDIRECT));
1431 em_bi.ihBrush = htofl(handle);
1432 em_bi.lb.lbStyle = htofl(style);
1433 em_bi.lb.lbColor = htofl(rgb);
1434 em_bi.lb.lbHatch = htofl(hatch);
1435
1436 # ifdef __EMF_DEBUG__
1437 fprintf(stderr, "CreateBrush (%d): style %d, rgb %x, hatch %d\n",
1438 handle, style, rgb, hatch);
1439 # endif
1440
1441 emh_write(&em_bi, sizeof(EMRCREATEBRUSHINDIRECT), (size_t) 1,
1442 EMH_RECORD);
1443 }
1444
1445 selectbrush:
1446 chkcache(handle, lasthandle[EMFH_BRUSH]);
1447 clear_current_handle(EMFH_BRUSH);
1448 if (h)
1449 h->is_current = True;
1450 # ifdef __EMF_DEBUG__
1451 fprintf(stderr, "Brush: ");
1452 # endif
1453 select_object(handle);
1454 }/* end fillstyle */
1455
1456
textfont(font,size,angle)1457 static void textfont(font, size, angle)
1458 int font;
1459 double size;
1460 int angle; /* tenths degree */
1461 {
1462 EMREXTCREATEFONTINDIRECTW em_fn;
1463 short *utext;
1464 int n_chars, n_unicode;
1465 struct emfhandle *h = NULL;
1466 unsigned handle;
1467 int fontsz;
1468
1469 fontsz = -(int)(size * (1200/72.27 * 0.88/*?? font is a bit large*/) + 0.5);
1470
1471 /* search for the same font */
1472 for (h = latesthandle; h != (void *)&handles; h = (void *) h->prev) {
1473 if (h->type == EMFH_FONT &&
1474 h->eh_un.f.ffont == font && h->eh_un.f.fsize == fontsz &&
1475 h->eh_un.f.fangle == angle) {
1476 /* found */
1477 use_handle(h);
1478 handle = h->handle;
1479 goto selectfont;
1480 }
1481 }
1482
1483 /* not found -- create new font */
1484 h = get_handle(EMFH_FONT);
1485 handle = h->handle;
1486 use_handle(h);
1487
1488 h->eh_un.f.ffont = font;
1489 h->eh_un.f.fsize = fontsz;
1490 h->eh_un.f.fangle = angle;
1491
1492 memset(&em_fn, 0, sizeof(EMREXTCREATEFONTINDIRECTW));
1493 em_fn.emr.iType = htofl(EMR_EXTCREATEFONTINDIRECTW);
1494 em_fn.emr.nSize = htofl(sizeof(EMREXTCREATEFONTINDIRECTW));
1495
1496 em_fn.ihFont = htofl(handle);
1497
1498 utext = (short *) em_fn.elfw.elfLogFont.lfFaceName;
1499 n_unicode = sizeof (em_fn.elfw.elfLogFont.lfFaceName);
1500 textunicode(
1501 #if defined(I18N) && defined(USE_ICONV)
1502 (font < 0 /* locale font */)? localeFonts[-1-font][figLanguage].FaceName :
1503 #endif
1504 lfFaceName[font],
1505 &n_chars, &utext, &n_unicode);
1506
1507 em_fn.elfw.elfLogFont.lfHeight = htofl(fontsz);
1508 em_fn.elfw.elfLogFont.lfEscapement = em_fn.elfw.elfLogFont.lfOrientation
1509 = htofl(angle);
1510 #if defined(I18N) && defined(USE_ICONV)
1511 if (font < 0 /* locale font */) {
1512 const struct localefnt *lf = &localeFonts[-1-font][figLanguage];
1513
1514 em_fn.elfw.elfLogFont.lfWeight = htofl(lf->Weight);
1515 em_fn.elfw.elfLogFont.lfItalic = /*uchar*/lf->Italic;
1516 em_fn.elfw.elfLogFont.lfCharSet = /*uchar*/lf->Charset;
1517 em_fn.elfw.elfLogFont.lfPitchAndFamily = /*uchar*/lf->PitchAndFamily;
1518 HTOFL(em_fn.elfw.elfLogFont.lfWidth,
1519 (int)(size * (1200/72.27 *0.40/*?? font is a bit wide*/) + 0.5));
1520 } else
1521 #endif
1522 {
1523 em_fn.elfw.elfLogFont.lfWeight = htofl(lfWeight[font]);
1524 em_fn.elfw.elfLogFont.lfItalic = /*uchar*/lfItalic[font];
1525 em_fn.elfw.elfLogFont.lfCharSet = /*uchar*/lfCharSet[font];
1526 em_fn.elfw.elfLogFont.lfPitchAndFamily =/*uchar*/lfPitchAndFamily[font];
1527 }
1528
1529 emh_write(&em_fn, sizeof(EMREXTCREATEFONTINDIRECTW), (size_t)1, EMH_RECORD);
1530
1531 # ifdef __EMF_DEBUG__
1532 fprintf(stderr,
1533 "Textfont (%d): %s Size: %d Weight: %d Italic: %d Angle: %d\n",
1534 handle,
1535 # if defined(I18N) && defined(USE_ICONV)
1536 (font < 0 /* locale font */)? localeFonts[-1-font][figLanguage].FaceName :
1537 # endif
1538 lfFaceName[font], -ftohl(em_fn.elfw.elfLogFont.lfHeight),
1539 lfWeight[font], lfItalic[font], angle);
1540 # endif
1541
1542 selectfont:
1543 chkcache(handle, lasthandle[EMFH_FONT]);
1544 clear_current_handle(EMFH_FONT);
1545 if (h)
1546 h->is_current = True;
1547 # ifdef __EMF_DEBUG__
1548 fprintf(stderr, "Font: ");
1549 # endif
1550 select_object(handle);
1551 }/* end textfont */
1552
1553
warn_32bit_pos()1554 static void warn_32bit_pos()
1555 {
1556 static int wgiv;
1557
1558 if (emflevel != EMF_LEVEL_WINNT && !wgiv) {
1559 fprintf(stderr, "\
1560 Warning: Coordinates exceed 16bit value.\n\
1561 Some figures will be invisible on Windows 95/98/Me.\n");
1562 wgiv = 1;
1563 }
1564 }
1565
1566
1567 /* Copies coordinates of pos p to point P. */
pos2point(P,p)1568 static void pos2point(P, p)
1569 F_point *P;
1570 F_pos *p;
1571 {
1572
1573 P->x = p->x; P->y = p->y;
1574 }/* end pos2point */
1575
1576
1577 /* Returns length of the arrow. used to shorten lines/arcs at
1578 * an end where an arrow needs to be drawn. */
arrow_length(a)1579 static double arrow_length(a)
1580 F_arrow *a;
1581 {
1582 double len;
1583
1584 switch (a->type) {
1585 case 0: /* stick type */
1586 len = ARROW_EXTRA_LEN(a);
1587 break;
1588 case 1: /* closed triangle */
1589 len = a->ht;
1590 break;
1591 case 2: /* indented hat */
1592 len = ARROW_INDENT_DIST * a->ht;
1593 break;
1594 case 3: /* pointed hat */
1595 len = ARROW_POINT_DIST * a->ht;
1596 break;
1597 default:
1598 len = 0.;
1599 }
1600 if (rounded_arrows)
1601 len -= ARROW_EXTRA_LEN(a);
1602
1603 return len;
1604 }
1605
1606
1607 /* Draws an arrow ending at point p pointing into direction dir.
1608 * type and attributes as required by a and l. This routine works
1609 * for both lines and arc (in that case l should be a F_arc *). */
arrow(P,a,l,dir)1610 static void arrow(P, a, l, dir)
1611 F_point *P;
1612 F_arrow *a;
1613 F_line *l;
1614 Dir *dir;
1615 {
1616 F_point s1, s2, t, p;
1617 EMRPOLYLINE em_pl; /* Little endian format */
1618 POINTL aptl[4]; /* Maximum of four points required for arrows */
1619 POINTS apts[4];
1620 unsigned cpt; /* Number of points in the array */
1621 unsigned itype, itype16;
1622 int bbx_top, bbx_bottom, bbx_left, bbx_right; /* Bounding box */
1623
1624 t.x = 0;
1625 t.y = 0;
1626 p = *P;
1627 if (!rounded_arrows) {
1628 /* Move the arrow backwards in order to let it end
1629 * at the correct spot */
1630 double f = ARROW_EXTRA_LEN(a);
1631 p.x = round(p.x - f * dir->x);
1632 p.y = round(p.y - f * dir->y);
1633 }
1634
1635 if (a->type == 0) { /* Old style stick arrow */
1636 edgeattr(1, 0, (int)a->thickness, l->pen_color, 0, 0);
1637 } else { /* Polygonal arrows */
1638 /* miter join style, butt line cap */
1639 edgeattr(1, 0, (int)a->thickness, l->pen_color, 0, 0);
1640 switch (a->style) {
1641 case 0:
1642 fillstyle(7, 20, 0); /* Fill with white (7) */
1643 break;
1644 case 1:
1645 fillstyle(l->pen_color, 20, 0); /* Use pen color to fill */
1646 break;
1647 default:
1648 fprintf(stderr, "Unsupported fig arrow style %d !!\n", a->style);
1649 }
1650 }
1651
1652 /* Start the bounding box */
1653
1654 bbx_left = bbx_right = P->x; /* Use original point for bounding */
1655 bbx_top = bbx_bottom = P->y;
1656
1657 itype = EMR_POLYGON;
1658 itype16 = EMR_POLYGON16;
1659
1660 switch (a->type) {
1661
1662 case 0: /* Stick type */
1663 itype = EMR_POLYLINE;
1664 itype16 = EMR_POLYLINE16;
1665 cpt = 3;
1666
1667 s1.x = round(p.x - a->ht * dir->x + a->wid*0.5 * dir->y);
1668 s1.y = round(p.y - a->ht * dir->y - a->wid*0.5 * dir->x);
1669 s2.x = round(p.x - a->ht * dir->x - a->wid*0.5 * dir->y);
1670 s2.y = round(p.y - a->ht * dir->y + a->wid*0.5 * dir->x);
1671 break;
1672
1673 case 1: /* Closed triangle */
1674 cpt = 3;
1675
1676 s1.x = round(p.x - a->ht * dir->x + a->wid*0.5 * dir->y);
1677 s1.y = round(p.y - a->ht * dir->y - a->wid*0.5 * dir->x);
1678 s2.x = round(p.x - a->ht * dir->x - a->wid*0.5 * dir->y);
1679 s2.y = round(p.y - a->ht * dir->y + a->wid*0.5 * dir->x);
1680 break;
1681
1682 case 2: /* Indented hat */
1683 cpt = 4;
1684
1685 s1.x = round(p.x - a->ht*ARROW_POINT_DIST * dir->x
1686 + a->wid*0.5 * dir->y);
1687 s1.y = round(p.y - a->ht*ARROW_POINT_DIST * dir->y
1688 - a->wid*0.5 * dir->x);
1689 s2.x = round(p.x - a->ht*ARROW_POINT_DIST * dir->x
1690 - a->wid*0.5 * dir->y);
1691 s2.y = round(p.y - a->ht*ARROW_POINT_DIST * dir->y
1692 + a->wid*0.5 * dir->x);
1693
1694 t.x = round(p.x - a->ht * dir->x);
1695 t.y = round(p.y - a->ht * dir->y);
1696
1697 UPDATE_BBX_X(t.x);
1698 UPDATE_BBX_Y(t.y);
1699 break;
1700
1701 case 3: /* Pointed hat */
1702 cpt = 4;
1703
1704 s1.x = round(p.x - a->ht*ARROW_INDENT_DIST * dir->x
1705 + a->wid*0.5 * dir->y);
1706 s1.y = round(p.y - a->ht*ARROW_INDENT_DIST * dir->y
1707 - a->wid*0.5 * dir->x);
1708 s2.x = round(p.x - a->ht*ARROW_INDENT_DIST * dir->x
1709 - a->wid*0.5 * dir->y);
1710 s2.y = round(p.y - a->ht*ARROW_INDENT_DIST * dir->y
1711 + a->wid*0.5 * dir->x);
1712
1713 t.x = round(p.x - a->ht * dir->x);
1714 t.y = round(p.y - a->ht * dir->y);
1715
1716 UPDATE_BBX_X(t.x);
1717 UPDATE_BBX_Y(t.y);
1718 break;
1719
1720 default:
1721 fprintf(stderr, "Unsupported fig arrow type %d.\n", a->type);
1722 return;
1723
1724 }/* end case */
1725
1726 UPDATE_BBX_X(s1.x);
1727 UPDATE_BBX_Y(s1.y);
1728
1729 UPDATE_BBX_X(s2.x);
1730 UPDATE_BBX_Y(s2.y);
1731
1732 em_pl.rclBounds.left = htofl(bbx_left); /* Store bounding box */
1733 em_pl.rclBounds.right = htofl(bbx_right);
1734 em_pl.rclBounds.top = htofl(bbx_top);
1735 em_pl.rclBounds.bottom = htofl(bbx_bottom);
1736 em_pl.cptl = htofl(cpt); /* Number of points */
1737
1738 if (bbx_left >= -32768 && bbx_right <= 32767
1739 && bbx_top >= -32768 && bbx_bottom <= 32767) {
1740
1741 # ifdef __EMF_DEBUG__
1742 fprintf(stderr, "Arrowhead16 %d rclBounds (ltrb): %d %d %d %d\n",
1743 cpt,
1744 bbx_left, bbx_top, bbx_right, bbx_bottom);
1745 # endif
1746
1747 /* use 16bit point */
1748 em_pl.emr.iType = htofl(itype16);
1749
1750 apts[0].x = htofs(s1.x);
1751 apts[0].y = htofs(s1.y);
1752 apts[1].x = htofs(p.x);
1753 apts[1].y = htofs(p.y);
1754 apts[2].x = htofs(s2.x);
1755 apts[2].y = htofs(s2.y);
1756 apts[3].x = htofs(t.x);
1757 apts[3].y = htofs(t.y);
1758
1759 HTOFL(em_pl.emr.nSize, sizeof(EMRPOLYLINE16) + cpt*sizeof(POINTS));
1760 emh_write(&em_pl, sizeof(EMRPOLYLINE16), (size_t) 1, EMH_RECORD);
1761 emh_write(apts, sizeof(POINTS), (size_t) cpt, EMH_DATA);
1762 } else {
1763
1764 # ifdef __EMF_DEBUG__
1765 fprintf(stderr, "Arrowhead %d rclBounds (ltrb): %d %d %d %d\n",
1766 cpt,
1767 bbx_left, bbx_top, bbx_right, bbx_bottom);
1768 # endif
1769
1770 /* use 32bit point */
1771 warn_32bit_pos();
1772
1773 em_pl.emr.iType = htofl(itype);
1774
1775 aptl[0].x = htofl(s1.x);
1776 aptl[0].y = htofl(s1.y);
1777 aptl[1].x = htofl(p.x);
1778 aptl[1].y = htofl(p.y);
1779 aptl[2].x = htofl(s2.x);
1780 aptl[2].y = htofl(s2.y);
1781 aptl[3].x = htofl(t.x);
1782 aptl[3].y = htofl(t.y);
1783
1784 HTOFL(em_pl.emr.nSize, sizeof(EMRPOLYLINE) + cpt*sizeof(POINTL));
1785 emh_write(&em_pl, sizeof(EMRPOLYLINE), (size_t) 1, EMH_RECORD);
1786 emh_write(aptl, sizeof(POINTL), (size_t) cpt, EMH_DATA);
1787 }
1788 }
1789
1790
1791 /* Draws arc arrow ending at p and starting at q. */
arc_arrow(p,q,arw,arc)1792 static void arc_arrow(p, q, arw, arc)
1793 F_pos *p;
1794 F_point *q;
1795 F_arrow *arw;
1796 F_arc *arc;
1797 {
1798 F_point P;
1799 Dir dir; double d;
1800
1801 if (!arw) return;
1802
1803 pos2point(&P, p);
1804 direction(&P, q, &dir, &d);
1805 arrow(&P, arw, (F_line *)arc, &dir);
1806 }
1807
1808
1809 /* Replaces p by the starting point of the arc arrow ending at p. */
arc_arrow_adjust(p,arwpos,arc,r,arw,adir)1810 static void arc_arrow_adjust(p, arwpos, arc, r, arw, adir)
1811 F_point *p; /* in: end of the arc, out: fixed end of arc */
1812 F_point *arwpos; /* out: origin of arrow */
1813 F_arc *arc;
1814 double r;
1815 F_arrow *arw;
1816 double adir;
1817 {
1818 double l;
1819 double alen, th;
1820 Dir dir; double dirlen;
1821 double d2, d3;
1822 F_point origpos, p1, p2, p3;
1823 struct dpoint {
1824 double x, y;
1825 } p4;
1826 double X, Y, d;
1827 double cx, cy;
1828
1829 if (!arw) return;
1830
1831 cx = arc->center.x; cy = arc->center.y; /* arc center */
1832 origpos = *p; /* save original arc end (to be used later) */
1833
1834 l = arw->type != 0 ? arrow_length(arw) : arw->ht;
1835 arc_rotate(p, cx, cy, adir * l / (1.8 * r + l));
1836
1837 /* length of arrow head */
1838 alen = arw->ht;
1839 if (!rounded_arrows)
1840 alen += ARROW_EXTRA_LEN(arw);
1841
1842 /*
1843 * fix arrow root pos
1844 */
1845
1846 /* if the arrow is longer than the diameter, no way to fix arrow root pos */
1847 if (alen >= 2 * r) {
1848 *arwpos = *p; /* use the fixed arc end */
1849 goto fix_cap;
1850 }
1851
1852 /* make a chord with the arc and the center line of the arrow head */
1853 th = 2 * atan(sqrt(1 / (4 * r * r / (alen * alen) - 1)));
1854 *arwpos = origpos;
1855 arc_rotate(arwpos, cx, cy, adir * th);
1856
1857 /*
1858 * fix arc end pos
1859 */
1860
1861 /* direction from arow root to arrow top */
1862 if (direction(&origpos, arwpos, &dir, &dirlen) == False)
1863 goto fix_cap; /* no way to fix */
1864
1865 /* Calculate the center of the line of arrow top. */
1866 p1 = origpos;
1867 if (!rounded_arrows) {
1868 d = ARROW_EXTRA_LEN(arw);
1869 p1.x = round(p1.x - d * dir.x);
1870 p1.y = round(p1.y - d * dir.y);
1871 }
1872
1873 /* Calculate other points of the arrow head. */
1874 d = p1.x - arw->ht * dir.x + arw->wid*0.5 * dir.y; p2.x = round(d);
1875 d = p1.y - arw->ht * dir.y - arw->wid*0.5 * dir.x; p2.y = round(d);
1876 d = p1.x - arw->ht * dir.x - arw->wid*0.5 * dir.y; p3.x = round(d);
1877 d = p1.y - arw->ht * dir.y + arw->wid*0.5 * dir.x; p3.y = round(d);
1878
1879 /* Calculate distance from the center of the arc to the points. */
1880 d2 = distance(cx, cy, (double) p2.x, (double) p2.y);
1881 d3 = distance(cx, cy, (double) p3.x, (double) p3.y);
1882
1883 /* Use the farther point. */
1884 if (d3 > d2) {
1885 p2 = p3;
1886 d2 = d3;
1887 }
1888
1889 /* The farther point shall be out of the arc. */
1890 if (d2 < r)
1891 goto fix_cap;
1892
1893 /* direction from p1 to p2 */
1894 if (direction(&p2, &p1, &dir, &dirlen) == False)
1895 goto fix_cap;
1896
1897 /*
1898 * Drop a perpendicular line from the arc center
1899 * to the line on which p1 and p2 are.
1900 */
1901 /*
1902 * The line of the arrow head is
1903 * x = p2.x + t * dir.x,
1904 * y = p2.y + t * dir.y, where t is an intermediate parameter.
1905 *
1906 * The distance^2 from the center of the arc to a point on the line is
1907 * (x - cx)^2 + (y - cy)^2 = (dir.x^2 + dir.y^2) * t^2
1908 * + 2*((p2.x - cx) * dir.x + (p2.y - cy) * dir.y) * t
1909 * + (p2.x - cx)^2 + (p2.y - cy)^2
1910 * = t^2 + 2*(X * dir.x + Y * dir.y) * t + X^2 + Y^2
1911 * where dir.x^2 + dir.y^2 = 1 (dir is a unit vector),
1912 * X = p2.x - cx, Y = p2.y - cy
1913 * = t^2 + 2*(X * dir.x + Y * dir.y) * t + (X * dir.x + Y * dir.y)^2
1914 * - (X * dir.x + Y * dir.y)^2
1915 * + X^2 + Y^2
1916 * = (t + (X * dir.x + Y * dir.y))^2
1917 * - X^2*dir.x^2 - 2*X*Y*dir.x*dir.y - Y^2*dir.y^2
1918 * + X^2*(dir.x^2 + dir.y^2) + Y^2*(dir.x^2 + dir.y^2)
1919 * where dir.x^2 + dir.y^2 = 1
1920 * = (t + (X * dir.x + Y * dir.y))^2
1921 * + X^2*dir.y^2 - 2*X*Y*dir.x*dir.y + Y^2*dir.x^2
1922 * = (t + (X * dir.x + Y * dir.y))^2 + (X * dir.y - Y * dir.x)^2
1923 */
1924 X = p2.x - cx;
1925 Y = p2.y - cy;
1926
1927 /* Calculate the pedal point of the perpendicular line. */
1928 d = X * dir.x + Y * dir.y;
1929 p4.x = p2.x - d * dir.x;
1930 p4.y = p2.y - d * dir.y;
1931
1932 /* and the length^2 of the perpendicular line segment is */
1933 d = X * dir.y - Y * dir.x;
1934 d = d * d;
1935
1936 /* length from p4 to the target point */
1937 d = sqrt(r * r - d);
1938
1939 /* Calculate target point. */
1940 p4.x = p4.x + d * dir.x;
1941 p4.y = p4.y + d * dir.y;
1942
1943 p->x = round(p4.x);
1944 p->y = round(p4.y);
1945
1946 fix_cap:
1947 if (arc->cap_style == 2) {
1948 /* Projecting cap style is a little longer. Shorten the arc. */
1949 arc_rotate(p, cx, cy, adir * (double)arc->thickness / (2.0 * r));
1950 }
1951 }
1952
1953
arc_radius(a)1954 static double arc_radius(a)
1955 F_arc *a;
1956 {
1957
1958 return (distance((double)a->point[0].x, (double)a->point[0].y,
1959 a->center.x, a->center.y) +
1960 distance((double)a->point[1].x, (double)a->point[1].y,
1961 a->center.x, a->center.y) +
1962 distance((double)a->point[2].x, (double)a->point[2].y,
1963 a->center.x, a->center.y)) / 3.;
1964 }
1965
1966
translate(x,y,tx,ty)1967 static void translate(x, y, tx, ty)
1968 double *x, *y, tx, ty;
1969 {
1970
1971 *x += tx; *y += ty;
1972 }/* end translate */
1973
1974
1975 /* Rotates counter clockwise around origin */
rotate(x,y,angle)1976 static void rotate(x, y, angle)
1977 double *x, *y, angle;
1978 {
1979 double s = sin(angle), c = cos(angle), xt = *x, yt = *y;
1980
1981 *x = c * xt + s * yt;
1982 *y = -s * xt + c * yt;
1983 }/* end rotate */
1984
1985
1986 /* Rotates the point p counter clockwise along the arc with center c. */
arc_rotate(p,cx,cy,angle)1987 static void arc_rotate(p, cx, cy, angle)
1988 F_point *p;
1989 double cx, cy, angle;
1990 {
1991 double x = p->x, y = p->y;
1992
1993 translate(&x, &y, -cx, -cy);
1994 rotate(&x, &y, angle);
1995 translate(&x, &y, +cx, +cy);
1996 p->x = round(x); p->y = round(y);
1997 }
1998
1999
arcoutline(a)2000 static void arcoutline(a)
2001 F_arc *a;
2002 {
2003 EMRARC em_ar;
2004 double r = arc_radius(a);
2005 F_point p0, p2;
2006 F_point arwp0, arwp2;
2007 int i;
2008
2009 pos2point(&p0, &a->point[0]);
2010 pos2point(&p2, &a->point[2]);
2011 if (a->type == T_OPEN_ARC && a->thickness != 0) {
2012 /* adjust for arrow heads */
2013 arc_arrow_adjust(&p0, &arwp0, a, r, a->back_arrow, +1.);
2014 arc_arrow_adjust(&p2, &arwp2, a, r, a->for_arrow, -1.);
2015
2016 /* calculate inner product */
2017 if ((a->point[0].x - a->point[2].x) * (p0.x - p2.x) +
2018 (a->point[0].y - a->point[2].y) * (p0.y - p2.y) < 0) {
2019 /*
2020 * This is probably because the arc is very short and hidden
2021 * in the arrow heads. Skip drawing the arc in this case.
2022 */
2023 goto draw_arrows;
2024 }
2025 }
2026
2027 i = (a->type == T_OPEN_ARC) ? EMR_ARC : EMR_PIE;
2028 em_ar.emr.iType = htofl(i);
2029 em_ar.emr.nSize = htofl(sizeof(EMRARC));
2030 HTOFL(em_ar.rclBox.left, round(a->center.x - r));
2031 HTOFL(em_ar.rclBox.top, round(a->center.y - r));
2032 HTOFL(em_ar.rclBox.right, round(a->center.x + r));
2033 HTOFL(em_ar.rclBox.bottom, round(a->center.y + r));
2034 em_ar.ptlStart.x = htofl(p0.x);
2035 em_ar.ptlStart.y = htofl(p0.y);
2036 em_ar.ptlEnd.x = htofl(p2.x);
2037 em_ar.ptlEnd.y = htofl(p2.y);
2038
2039 # ifdef __EMF_DEBUG__
2040 fprintf(stderr, "Arc outline rclBox (ltrb): %d %d %d %d\n",
2041 ftohl(em_ar.rclBox.left), ftohl(em_ar.rclBox.top),
2042 ftohl(em_ar.rclBox.right), ftohl(em_ar.rclBox.bottom));
2043 # endif
2044
2045 emh_write(&em_ar, sizeof(EMRARC), (size_t) 1, EMH_RECORD);
2046
2047 draw_arrows:
2048 if (a->type == T_OPEN_ARC && a->thickness != 0) {
2049 /* draw arrow heads */
2050 arc_arrow(&a->point[0], &arwp0, a->back_arrow, a);
2051 arc_arrow(&a->point[2], &arwp2, a->for_arrow, a);
2052 }
2053 }
2054
2055
arcinterior(a)2056 static void arcinterior(a)
2057 F_arc *a;
2058 {
2059 EMRCHORD em_ch;
2060 double r = arc_radius(a);
2061
2062 em_ch.emr.iType = htofl(EMR_CHORD);
2063 em_ch.emr.nSize = htofl(sizeof(EMRCHORD));
2064 HTOFL(em_ch.rclBox.left, round(a->center.x - r));
2065 HTOFL(em_ch.rclBox.top, round(a->center.y - r));
2066 HTOFL(em_ch.rclBox.right, round(a->center.x + r));
2067 HTOFL(em_ch.rclBox.bottom, round(a->center.y + r));
2068 em_ch.ptlStart.x = htofl(a->point[0].x);
2069 em_ch.ptlStart.y = htofl(a->point[0].y);
2070 em_ch.ptlEnd.x = htofl(a->point[2].x);
2071 em_ch.ptlEnd.y = htofl(a->point[2].y);
2072
2073 # ifdef __EMF_DEBUG__
2074 fprintf(stderr, "Arc interior rclBox (ltrb): %d %d %d %d\n",
2075 ftohl(em_ch.rclBox.left), ftohl(em_ch.rclBox.top),
2076 ftohl(em_ch.rclBox.right), ftohl(em_ch.rclBox.bottom));
2077 # endif
2078
2079 emh_write(&em_ch, sizeof(EMRCHORD), (size_t) 1, EMH_RECORD);
2080 }/* end arcinterior */
2081
2082
2083 /* Reverses arc direction by swapping endpoints and arrows */
arc_reverse(arc)2084 static void arc_reverse(arc)
2085 F_arc *arc;
2086 {
2087 F_arrow *arw;
2088 F_pos pp;
2089
2090 pp = arc->point[0]; arc->point[0] = arc->point[2]; arc->point[2] = pp;
2091 arw = arc->for_arrow;
2092 arc->for_arrow = arc->back_arrow;
2093 arc->back_arrow = arw;
2094 }
2095
2096
circle(e)2097 static void circle(e)
2098 F_ellipse *e;
2099 {
2100 EMRELLIPSE em_el;
2101
2102 em_el.emr.iType = htofl(EMR_ELLIPSE);
2103 em_el.emr.nSize = htofl(sizeof(EMRELLIPSE));
2104 em_el.rclBox.left = htofl(e->center.x - e->radiuses.x);
2105 em_el.rclBox.top = htofl(e->center.y - e->radiuses.x);
2106 em_el.rclBox.right = htofl(e->center.x + e->radiuses.x);
2107 em_el.rclBox.bottom = htofl(e->center.y + e->radiuses.x);
2108
2109 # ifdef __EMF_DEBUG__
2110 fprintf(stderr, "Circle rclBox (ltrb): %d %d %d %d\n",
2111 ftohl(em_el.rclBox.left), ftohl(em_el.rclBox.top),
2112 ftohl(em_el.rclBox.right), ftohl(em_el.rclBox.bottom));
2113 # endif
2114
2115 emh_write(&em_el, sizeof(EMRELLIPSE), (size_t) 1, EMH_RECORD);
2116 }/* end circle */
2117
2118
2119 /* non-rotated ellipses */
ellipse(e)2120 static void ellipse(e)
2121 F_ellipse *e;
2122 {
2123 EMRELLIPSE em_el;
2124
2125 em_el.emr.iType = htofl(EMR_ELLIPSE);
2126 em_el.emr.nSize = htofl(sizeof(EMRELLIPSE));
2127 em_el.rclBox.left = htofl(e->center.x - e->radiuses.x);
2128 em_el.rclBox.top = htofl(e->center.y - e->radiuses.y);
2129 em_el.rclBox.right = htofl(e->center.x + e->radiuses.x);
2130 em_el.rclBox.bottom = htofl(e->center.y + e->radiuses.y);
2131
2132 # ifdef __EMF_DEBUG__
2133 fprintf(stderr, "Ellipse rclBox (ltrb): %d %d %d %d\n",
2134 ftohl(em_el.rclBox.left), ftohl(em_el.rclBox.top),
2135 ftohl(em_el.rclBox.right), ftohl(em_el.rclBox.bottom));
2136 # endif
2137
2138 emh_write(&em_el, sizeof(EMRELLIPSE), (size_t) 1, EMH_RECORD);
2139 }/* end ellipse */
2140
2141
2142 /* draw rotated ellipse as a polygon */
2143 #define ELLIPSE_NPOINT 72
rotated_ellipse(e)2144 static void rotated_ellipse(e)
2145 F_ellipse *e;
2146 {
2147 F_line l;
2148 F_point pnt[ELLIPSE_NPOINT];
2149 int i;
2150 const double delta = 2 * M_PI / (double)ELLIPSE_NPOINT;
2151 double th;
2152 double sina = sin(e->angle), cosa = cos(e->angle);
2153 double ex, ey;
2154
2155 for (i = 0; i < ELLIPSE_NPOINT; i++) {
2156 th = delta * i;
2157 ex = (double) e->radiuses.x * cos(th);
2158 ey = (double) e->radiuses.y * sin(th);
2159 pnt[i].x = e->center.x + (int) (cosa * ex + sina * ey);
2160 pnt[i].y = e->center.y + (int) (-sina * ex + cosa * ey);
2161 pnt[i].next = &pnt[i + 1];
2162 }
2163 pnt[ELLIPSE_NPOINT - 1].next = NULL;
2164
2165 /*
2166 * fabricate polygon structure
2167 */
2168
2169 /* copy common fields */
2170
2171 l.style = e->style;
2172 l.thickness = e->thickness;
2173 l.pen_color = e->pen_color;
2174 l.fill_color = e->fill_color;
2175 l.depth = e->depth;
2176 l.pen = e->pen;
2177 l.fill_style = e->fill_style;
2178 l.style_val = e->style_val;
2179
2180 /* setup other fields */
2181 l.points = pnt;
2182 l.type = T_POLYGON;
2183
2184 /* just in case... */
2185 l.for_arrow = l.back_arrow = NULL;
2186 l.cap_style = 0;
2187 l.join_style = 0;
2188 l.radius = 0;
2189 l.pic = NULL;
2190 l.comments = NULL;
2191 l.next = NULL;
2192
2193 shape(&l, 0, 0, polygon);
2194 }/* end rotated_ellipse */
2195
2196
2197 /* Integer cross product */
icprod(x1,y1,x2,y2)2198 static int icprod(x1, y1, x2, y2)
2199 int x1, y1, x2, y2;
2200 {
2201
2202 return x1 * y2 - y1 * x2;
2203 }/* end icprod */
2204
2205
2206 /* Returns True if the arc is a clockwise arc. */
cwarc(a)2207 static int cwarc(a)
2208 F_arc *a;
2209 {
2210 int x1 = a->point[1].x - a->point[0].x,
2211 y1 = a->point[1].y - a->point[0].y,
2212 x2 = a->point[2].x - a->point[1].x,
2213 y2 = a->point[2].y - a->point[1].y;
2214
2215 return (icprod(x1,y1,x2,y2) > 0);
2216 }/* end cwarc */
2217
2218
2219 /* Computes distance and normalized direction vector from q to p.
2220 * returns True if the points do not coincide and False if they do. */
direction(p,q,dir,dist)2221 static int direction(p, q, dir, dist)
2222 F_point *p;
2223 F_point *q;
2224 Dir *dir;
2225 double *dist;
2226 {
2227
2228 dir->x = p->x - q->x;
2229 dir->y = p->y - q->y;
2230 *dist = sqrt((dir->x) * (dir->x) + (dir->y) * (dir->y));
2231 if (*dist < EPSILON)
2232 return False;
2233 dir->x /= *dist;
2234 dir->y /= *dist;
2235 return True;
2236 }/* end direction */
2237
2238
distance(x1,y1,x2,y2)2239 static double distance(x1, y1, x2, y2)
2240 double x1, y1, x2, y2;
2241 {
2242 double dx = x2-x1, dy=y2-y1;
2243
2244 return sqrt(dx*dx + dy*dy);
2245 }/* end distance */
2246
2247
2248 /* Write an enhanced metarecord and keep track of number of bytes written
2249 * and number of records written in the global header record "emh". */
emh_write(ptr,size,nmemb,flag)2250 static size_t emh_write(ptr, size, nmemb, flag)
2251 const void *ptr;
2252 size_t size;
2253 size_t nmemb;
2254 emh_flag flag;
2255 {
2256
2257 if (flag == EMH_RECORD) emh_nRecords++;
2258 emh_nBytes += size * nmemb;
2259 return fwrite(ptr, size, nmemb, tfp);
2260 }/* end emh_write */
2261
2262
is_flip(rot,flip)2263 static int is_flip(rot, flip)
2264 int rot, flip;
2265 {
2266
2267 return (rot == 90 || rot == 270) ? !flip : flip;
2268 }
2269
2270
encode_bitmap(pic,bpp,rot)2271 static void encode_bitmap(pic, bpp, rot)
2272 F_pic *pic;
2273 int bpp, rot;
2274 {
2275 int img_w = pic->bit_size.x;
2276 int img_h = pic->bit_size.y;
2277 int flip;
2278 int i, initi, endi, diri;
2279 int j, initj, endj, dirj;
2280 int pos;
2281 int freebits = 32;
2282 unsigned bits = 0;
2283 unsigned char cbits[4];
2284 unsigned u;
2285
2286 /*
2287 * Note: on EMF, you must output the image
2288 * from left to right and FROM BOTTOM TO TOP.
2289 */
2290 switch (rot) {
2291 case 0: diri = 1; dirj = -1; break;
2292 case 90: diri = 1; dirj = 1; break;
2293 case 180: diri = -1; dirj = 1; break;
2294 case 270: diri = -1; dirj = -1; break;
2295 default:
2296 fprintf(stderr, "fig2dev: emf: pic rotation %d is not supported\n",
2297 rot);
2298 return;
2299 /*NOTREACHED*/
2300 break;
2301 }
2302
2303 if (pic->flipped && (rot == 0 || rot == 180)) {
2304 diri = -diri;
2305 dirj = -dirj;
2306 }
2307
2308 flip = is_flip(rot, pic->flipped);
2309
2310 if (diri < 0) {
2311 initi = img_w - 1; endi = 0;
2312 } else {
2313 initi = 0; endi = img_w - 1;
2314 }
2315 if (dirj < 0) {
2316 initj = img_h - 1; endj = 0;
2317 } else {
2318 initj = 0; endj = img_h - 1;
2319 }
2320
2321 # define SWAP(v1, v2) do { int tmp = v1; v1 = v2; v2 = tmp; } while (0)
2322 if (flip) {
2323 SWAP(initi, initj);
2324 SWAP(endi, endj);
2325 SWAP(diri, dirj);
2326 }
2327 # undef SWAP
2328
2329 # define WRITEBITS \
2330 do {/* MSB first */ \
2331 cbits[0] = bits >> 24; cbits[1] = bits >> 16; \
2332 cbits[2] = bits >> 8; cbits[3] = bits; \
2333 emh_write(cbits, (size_t) 4, (size_t) 1, EMH_DATA); \
2334 freebits = 32; \
2335 bits = 0; \
2336 } while (0)
2337
2338 endi += diri;
2339 endj += dirj;
2340 for (j = initj; j != endj; j += dirj) {
2341 for (i = initi; i != endi; i += diri) {
2342 /*
2343 * normal: x: i, y: j
2344 * flip: x: j, y: i
2345 */
2346 pos = flip ? i * img_w + j : j * img_w + i;
2347
2348 switch (bpp) {
2349 case 1: case 4: case 8:
2350 freebits -= bpp;
2351 bits |= pic->bitmap[pos] << freebits;
2352 if (freebits == 0)
2353 WRITEBITS;
2354 break;
2355 case 24:
2356 for (u = 0; u < 3; u++) {
2357 freebits -= 8;
2358 bits |= pic->bitmap[pos*3 + u] << freebits;
2359 if (freebits == 0)
2360 WRITEBITS;
2361 }
2362 break;
2363 default:
2364 /* should not happen */
2365 fprintf(stderr, "unsupported bpp %d\n", bpp);
2366 break;
2367 }
2368 }
2369 /* size of a line of EMF bitmap must be a multiple of 4 byte */
2370 if (freebits != 32)
2371 WRITEBITS;
2372 }
2373 # undef WRITEBITS
2374 }
2375
2376
picbox(l)2377 static void picbox(l)
2378 F_line *l;
2379 {
2380 EMRSTRETCHDIBITS em_sd;
2381 BITMAPINFO bmi;
2382 char buf[512], realname[PATH_MAX];
2383 int filtype;
2384 int dx, dy;
2385 FILE *picf;
2386 int pllx, plly;
2387 int img_w, img_h;
2388 int rotation;
2389 size_t bsize, coltabsize;
2390 int bpp;
2391 unsigned ncol;
2392 static RGBQUAD coltab[256];
2393 unsigned u;
2394 int flip;
2395
2396 dx = l->points->next->next->x - l->points->x;
2397 dy = l->points->next->next->y - l->points->y;
2398
2399 /* rotation (counter clockwise) */
2400 rotation = 0;
2401 if (dx < 0 && dy < 0)
2402 rotation = 180;
2403 else if (dx < 0 && dy >= 0)
2404 rotation = 270;
2405 else if (dy < 0 && dx >= 0)
2406 rotation = 90;
2407
2408 if ((picf = open_picfile(l->pic->file, &filtype, True, realname)) == NULL) {
2409 fprintf(stderr, "fig2dev: %s: No such picture file\n", l->pic->file);
2410 return;
2411 }
2412 if (fread(buf, (size_t) 16, (size_t) 1, picf) != 1) {
2413 fprintf(stderr, "fig2dev: %s: short read\n", l->pic->file);
2414 close_picfile(picf, filtype);
2415 return;
2416 }
2417 close_picfile(picf, filtype);
2418
2419 memset(&em_sd, 0, sizeof(EMRSTRETCHDIBITS));
2420 em_sd.emr.iType = htofl(EMR_STRETCHDIBITS);
2421
2422 memset(&bmi, 0, sizeof(BITMAPINFO));
2423 bmi.bmiHeader.biSize = htofl(sizeof(BITMAPINFOHEADER));
2424
2425 #ifdef USE_PNG
2426 if (strncmp(buf, "\211\120\116\107\015\012\032\012", (size_t) 8) == 0) {
2427 /* png file */
2428 if ((picf = open_picfile(l->pic->file, &filtype, True, realname)) == NULL) {
2429 perror(l->pic->file);
2430 return;
2431 }
2432 if (read_png(picf, filtype, l->pic, &pllx, &plly) == 0) {
2433 fprintf(stderr, "fig2dev: %s: illegal format\n", l->pic->file);
2434 close_picfile(picf, filtype);
2435 return;
2436 }
2437 close_picfile(picf, filtype);
2438 }
2439 #endif
2440 if (l->pic->subtype == P_GIF || l->pic->subtype == P_PCX ||
2441 l->pic->subtype == P_JPEG || l->pic->subtype == P_PNG) {
2442
2443 img_w = l->pic->bit_size.x;
2444 img_h = l->pic->bit_size.y;
2445 ncol = l->pic->numcols;
2446
2447 flip = is_flip(rotation, l->pic->flipped);
2448
2449 /* EMF bitmap requires the every scan line be a multiple of 4 byte */
2450 if (ncol <= 2) {
2451 bpp = 1;
2452 bsize = (flip ? (img_h + 31) / 32 * img_w :
2453 (img_w + 31) / 32 * img_h) * 4;
2454 coltabsize = 2 * sizeof(RGBQUAD);
2455 } else if (ncol <= 16) {
2456 bpp = 4;
2457 bsize = (flip ? (img_h + 7) / 8 * img_w :
2458 (img_w + 7) / 8 * img_h) * 4;
2459 coltabsize = ncol * sizeof(RGBQUAD);
2460 } else if (ncol <= 256) {
2461 bpp = 8;
2462 bsize = (flip ? (img_h + 3) / 4 * img_w :
2463 (img_w + 3) / 4 * img_h) * 4;
2464 coltabsize = ncol * sizeof(RGBQUAD);
2465 } else {
2466 bpp = 24;
2467 bsize = (flip ? (img_h * 3 + 3) / 4 * img_w :
2468 (img_w * 3 + 3) / 4 * img_h) * 4;
2469 coltabsize = 0;
2470 }
2471
2472 # ifdef __EMF_DEBUG__
2473 fprintf(stderr, "PicBox: %s: %u cols, %d bpp, bsize %u, img(%d,%d), fig(%d,%d)\n",
2474 l->pic->file, ncol, bpp, bsize, img_w, img_h, dx, dy);
2475 # endif
2476
2477 if (dx >= 0) {
2478 em_sd.xDest = em_sd.rclBounds.left = htofl(l->points->x);
2479 em_sd.rclBounds.right = htofl(l->points->next->next->x);
2480 em_sd.cxDest = htofl(dx);
2481 } else {
2482 em_sd.xDest = em_sd.rclBounds.left =htofl(l->points->next->next->x);
2483 em_sd.rclBounds.right = htofl(l->points->x);
2484 em_sd.cxDest = htofl(-dx);
2485 }
2486 if (dy >= 0) {
2487 em_sd.yDest = em_sd.rclBounds.top = htofl(l->points->y);
2488 em_sd.rclBounds.bottom = htofl(l->points->next->next->y);
2489 em_sd.cyDest = htofl(dy);
2490 } else {
2491 em_sd.yDest = em_sd.rclBounds.top = htofl(l->points->next->next->y);
2492 em_sd.rclBounds.bottom = htofl(l->points->y);
2493 em_sd.cyDest = htofl(-dy);
2494 }
2495
2496 /* em_sd.xSrc = em_sd.ySrc = htofl(0); already cleared */
2497
2498 if (flip) {
2499 bmi.bmiHeader.biWidth = em_sd.cxSrc = htofl(img_h);
2500 bmi.bmiHeader.biHeight = em_sd.cySrc = htofl(img_w);
2501 } else {
2502 bmi.bmiHeader.biWidth = em_sd.cxSrc = htofl(img_w);
2503 bmi.bmiHeader.biHeight = em_sd.cySrc = htofl(img_h);
2504 }
2505
2506 /* em_sd.iUsageSrc = htofl(DIB_RGB_COLORS); this is default */
2507 em_sd.dwRop = htofl(SRCCOPY);
2508
2509 em_sd.offBmiSrc = htofl(sizeof(EMRSTRETCHDIBITS));
2510 em_sd.cbBmiSrc = htofl(sizeof(BITMAPINFO) + coltabsize);
2511 em_sd.offBitsSrc = htofl(sizeof(EMRSTRETCHDIBITS) +
2512 sizeof(BITMAPINFO) + coltabsize);
2513
2514 bmi.bmiHeader.biSizeImage = em_sd.cbBitsSrc = htofl(bsize);
2515
2516 em_sd.emr.nSize = htofl(sizeof(EMRSTRETCHDIBITS) + sizeof(BITMAPINFO) +
2517 coltabsize + bsize);
2518
2519 bmi.bmiHeader.biPlanes = htofs(1);
2520 bmi.bmiHeader.biBitCount = htofs(bpp);
2521 bmi.bmiHeader.biCompression = htofl(BI_RGB); /* uncompressed */
2522 bmi.bmiHeader.biXPelsPerMeter =
2523 bmi.bmiHeader.biYPelsPerMeter = htofl(2953); /* 75dpi ? */
2524 if (bpp <= 8)
2525 bmi.bmiHeader.biClrUsed = htofl(ncol);
2526 /* bmi.bmiHeader.biClrImportant = htofl(0); */
2527
2528 emh_write(&em_sd, sizeof(EMRSTRETCHDIBITS), (size_t) 1, EMH_RECORD);
2529 emh_write(&bmi, sizeof(BITMAPINFO), (size_t) 1, EMH_DATA);
2530
2531 /* color table */
2532 if (coltabsize) {
2533 coltab[0].rgbBlue = coltab[0].rgbGreen = coltab[0].rgbRed = 0;
2534 coltab[1].rgbBlue = coltab[1].rgbGreen = coltab[1].rgbRed = 0;
2535 for (u = 0; u < ncol; u++) {
2536 coltab[u].rgbBlue = l->pic->cmap[BLUE][u];
2537 coltab[u].rgbGreen = l->pic->cmap[GREEN][u];
2538 coltab[u].rgbRed = l->pic->cmap[RED][u];
2539 }
2540 emh_write(coltab, coltabsize, (size_t) 1, EMH_DATA);
2541 }
2542
2543 /* bitmap */
2544 encode_bitmap(l->pic, bpp, rotation);
2545
2546 /* need 4 byte align, but the size of EMF bitmap is 4 byte aligned */
2547 } else {
2548 fprintf(stderr, "fig2dev: %s: emf: unsupported picture format\n",
2549 l->pic->file);
2550 return;
2551 }
2552 }/* end picbox */
2553
2554
2555 /* Draws polygon boundary */
polygon(l)2556 static void polygon(l)
2557 F_line *l;
2558 {
2559 F_point *p;
2560 int count;
2561 EMRPOLYGON em_pg; /* Polygon in little endian format */
2562 POINTL *aptl;
2563 POINTS *apts;
2564 int bbx_top, bbx_bottom, bbx_left, bbx_right; /* Bounding box */
2565 unsigned cpt; /* Number of points in the array */
2566
2567 /* Calculate the number of points and the bounding box. */
2568 if (!(p = l->points)) return;
2569 bbx_left = p->x;
2570 bbx_top = p->y;
2571 bbx_right = p->x;
2572 bbx_bottom = p->y;
2573 for (cpt = 0; p; p = p->next) {
2574 UPDATE_BBX_X(p->x);
2575 UPDATE_BBX_Y(p->y);
2576 cpt++;
2577 }
2578
2579 /* Windows 95/98/Me: maximum points allowed is approx. 1360 */
2580 if (cpt > 1360 && emflevel != EMF_LEVEL_WINNT)
2581 fprintf(stderr, "Warning: polygon has too many points -- may be partially invisible\n");
2582
2583 /* Store bounding box in little endian format */
2584 em_pg.cptl = htofl(cpt);
2585 em_pg.rclBounds.left = htofl(bbx_left);
2586 em_pg.rclBounds.top = htofl(bbx_top);
2587 em_pg.rclBounds.right = htofl(bbx_right);
2588 em_pg.rclBounds.bottom = htofl(bbx_bottom);
2589
2590 if (bbx_left >= -32768 && bbx_right <= 32767
2591 && bbx_top >= -32768 && bbx_bottom <= 32767) {
2592
2593 # ifdef __EMF_DEBUG__
2594 fprintf(stderr, "Polygon16 %d rclBounds (ltrb): %d %d %d %d\n",
2595 cpt,
2596 bbx_left, bbx_top, bbx_right, bbx_bottom);
2597 # endif
2598
2599 /* use 16bit point */
2600 /* Fill the array with the points of the polygon */
2601 if ((apts = malloc(cpt * sizeof(POINTS))) == NULL) {
2602 perror("fig2dev: malloc");
2603 exit(1);
2604 }
2605 for (p=l->points, count=0; p; p=p->next, count++) {
2606 apts[count].x = htofs(p->x);
2607 apts[count].y = htofs(p->y);
2608 }
2609
2610 em_pg.emr.iType = htofl(EMR_POLYGON16);
2611 em_pg.emr.nSize = htofl(sizeof(EMRPOLYGON16) + cpt * sizeof(POINTS));
2612
2613 emh_write(&em_pg, sizeof(EMRPOLYGON16), (size_t) 1, EMH_RECORD);
2614 emh_write(apts, sizeof(POINTS), (size_t) cpt, EMH_DATA);
2615
2616 free(apts);
2617 } else {
2618 # ifdef __EMF_DEBUG__
2619 fprintf(stderr, "Polygon %d rclBounds (ltrb): %d %d %d %d\n",
2620 cpt,
2621 bbx_left, bbx_top, bbx_right, bbx_bottom);
2622 # endif
2623
2624 /* use 32bit point */
2625 warn_32bit_pos();
2626
2627 /* Fill the array with the points of the polygon */
2628 if ((aptl = malloc(cpt * sizeof(POINTL))) == NULL) {
2629 perror("fig2dev: malloc");
2630 exit(1);
2631 }
2632 for (p=l->points, count=0; p; p=p->next, count++) {
2633 aptl[count].x = htofl(p->x);
2634 aptl[count].y = htofl(p->y);
2635 }
2636
2637 em_pg.emr.iType = htofl(EMR_POLYGON);
2638 em_pg.emr.nSize = htofl(sizeof(EMRPOLYGON) + cpt * sizeof(POINTL));
2639
2640 emh_write(&em_pg, sizeof(EMRPOLYGON), (size_t) 1, EMH_RECORD);
2641 emh_write(aptl, sizeof(POINTL), (size_t) cpt, EMH_DATA);
2642
2643 free(aptl);
2644 }
2645 }/* end polygon */
2646
2647
2648 /* Replaces p by the shortened starting point of the line segment. */
polyline_adjust(p,q,l)2649 static int polyline_adjust(p, q, l)
2650 F_point *p;
2651 F_point *q;
2652 double l;
2653 {
2654 double d; Dir dir;
2655
2656 if (direction(p, q, &dir, &d)) {
2657 p->x = round(p->x - l * dir.x);
2658 p->y = round(p->y - l * dir.y);
2659 return (l < d);
2660 }
2661 fprintf(stderr, "Warning: Arrow at zero-length line segment omitted.\n");
2662 return True;
2663 }/* end polyline_arrow_adjust */
2664
2665
2666 /* Draws polyline boundary (with arrows if needed) */
polyline(l)2667 static void polyline(l)
2668 F_line *l;
2669 {
2670 F_point *p, *q, p0, pn;
2671 Dir dir;
2672 double d;
2673 EMRPOLYLINE em_pl; /* Polyline in little endian format */
2674 POINTL *aptl;
2675 POINTS *apts;
2676 double alen, seglen;
2677
2678 int bbx_top, bbx_bottom, bbx_left, bbx_right; /* Bounding box */
2679 unsigned cpt; /* Number of points in the array */
2680 unsigned u;
2681
2682 /* Calculate the number of points and the bounding box. */
2683 if (!(p = l->points)) return;
2684 bbx_left = p->x;
2685 bbx_top = p->y;
2686 bbx_right = p->x;
2687 bbx_bottom = p->y;
2688 for (cpt = 0, q = p; p; q = p, p = p->next) {
2689 UPDATE_BBX_X(p->x);
2690 UPDATE_BBX_Y(p->y);
2691 cpt++;
2692 }
2693 p0 = *l->points; /* first point */
2694 pn = *q; /* last point */
2695
2696 if (cpt == 1) {
2697 /* Draw single point as a short line. */
2698 cpt = 2;
2699 pn.y++;
2700 } else {
2701 /*
2702 * Delete line segments which may overlap arrow heads.
2703 */
2704 if (l->back_arrow) { /* First point with arrow */
2705 alen = arrow_length(l->back_arrow);
2706 while (cpt > 1) {
2707 q = p0.next;
2708 seglen = distance((double)p0.x, (double)p0.y, (double)q->x, (double)q->y);
2709 if (seglen > alen) {
2710 break;
2711 } else {
2712 /* delete this segment */
2713 cpt--;
2714 p0 = *q;
2715 alen -= seglen;
2716 }
2717 }
2718 if (cpt > 1)
2719 polyline_adjust(&p0, p0.next, alen); /* shorten line segment */
2720 }
2721 if (l->for_arrow) { /* Last point with arrow */
2722 alen = arrow_length(l->for_arrow);
2723 while (cpt > 1) {
2724 for (p = &p0, u = cpt; --u > 0; q = p, p = p->next)
2725 ;
2726 seglen = distance((double)p->x, (double)p->y, (double)q->x, (double)q->y);
2727 if (seglen > alen) {
2728 break;
2729 } else {
2730 /* delete this segment */
2731 cpt--;
2732 pn = *q;
2733 alen -= seglen;
2734 }
2735 }
2736 if (cpt > 1)
2737 polyline_adjust(&pn, q, alen); /* shorten line segment */
2738 }
2739 if (cpt <= 1) /* if all line segments are removed, */
2740 goto draw_arrows; /* skip drawing line segments */
2741 }
2742
2743 /* Windows 95/98/Me: maximum points allowed is approx. 1360 */
2744 if (cpt > 1360 && emflevel != EMF_LEVEL_WINNT)
2745 fprintf(stderr, "Warning: polyline has too many points -- may be partially invisible\n");
2746
2747 /* Store bounding box in little endian format */
2748 em_pl.cptl = htofl(cpt);
2749 em_pl.rclBounds.left = htofl(bbx_left);
2750 em_pl.rclBounds.top = htofl(bbx_top);
2751 em_pl.rclBounds.right = htofl(bbx_right);
2752 em_pl.rclBounds.bottom = htofl(bbx_bottom);
2753
2754 if (bbx_left >= -32768 && bbx_right <= 32767
2755 && bbx_top >= -32768 && bbx_bottom <= 32767) {
2756
2757 # ifdef __EMF_DEBUG__
2758 fprintf(stderr, "Polyline16 %d rclBounds (ltrb): %d %d %d %d\n",
2759 cpt,
2760 bbx_left, bbx_top, bbx_right, bbx_bottom);
2761 # endif
2762
2763 /* use 16bit point */
2764 /* Fill the array with the points of the polyline */
2765 if ((apts = malloc(cpt * sizeof(POINTS))) == NULL) {
2766 perror("fig2dev: malloc");
2767 exit(1);
2768 }
2769 for (p = &p0, u = 0; u + 1 < cpt; p= p->next, u++) {
2770 apts[u].x = htofs(p->x);
2771 apts[u].y = htofs(p->y);
2772 }
2773 apts[u].x = htofs(pn.x);
2774 apts[u].y = htofs(pn.y);
2775
2776 em_pl.emr.iType = htofl(EMR_POLYLINE16);
2777 HTOFL(em_pl.emr.nSize, sizeof(EMRPOLYLINE16) + cpt * sizeof(POINTS));
2778
2779 emh_write(&em_pl, sizeof(EMRPOLYLINE16), (size_t) 1, EMH_RECORD);
2780 emh_write(apts, sizeof(POINTS), (size_t) cpt, EMH_DATA);
2781 free(apts);
2782 } else {
2783
2784 # ifdef __EMF_DEBUG__
2785 fprintf(stderr, "Polyline %d rclBounds (ltrb): %d %d %d %d\n",
2786 cpt,
2787 bbx_left, bbx_top, bbx_right, bbx_bottom);
2788 # endif
2789
2790 /* use 32bit point */
2791 warn_32bit_pos();
2792
2793 /* Fill the array with the points of the polyline */
2794 if ((aptl = malloc(cpt * sizeof(POINTL))) == NULL) {
2795 perror("fig2dev: malloc");
2796 exit(1);
2797 }
2798 for (p = &p0, u = 0; u + 1 < cpt; p= p->next, u++) {
2799 aptl[u].x = htofl(p->x);
2800 aptl[u].y = htofl(p->y);
2801 }
2802 aptl[u].x = htofl(pn.x);
2803 aptl[u].y = htofl(pn.y);
2804
2805 em_pl.emr.iType = htofl(EMR_POLYLINE);
2806 HTOFL(em_pl.emr.nSize, sizeof(EMRPOLYLINE) + cpt * sizeof(POINTL));
2807
2808 emh_write(&em_pl, sizeof(EMRPOLYLINE), (size_t) 1, EMH_RECORD);
2809 emh_write(aptl, sizeof(POINTL), (size_t) cpt, EMH_DATA);
2810 free(aptl);
2811 }
2812
2813 draw_arrows:
2814 if (!l->points->next) {
2815 if (l->for_arrow || l->back_arrow)
2816 fprintf(stderr, "Warning: Arrow at zero-length line segment omitted.\n");
2817 return;
2818 } /* At least two different points now */
2819
2820
2821 if (l->back_arrow) {
2822 p = l->points;
2823 q = l->points->next;
2824 if (direction(p, q, &dir, &d)) {
2825 arrow(p, l->back_arrow, l, &dir);
2826 }
2827 }
2828
2829 if (l->for_arrow) {
2830 for (q=l->points, p=l->points->next; p->next; q=p, p=p->next) {}
2831 /* q is the one but last point */
2832 if (direction(p, q, &dir, &d)) {
2833 arrow(p, l->for_arrow, l, &dir);
2834 }
2835 }
2836 }/* end polyline */
2837
2838
rect(l)2839 static void rect(l)
2840 F_line *l;
2841 {
2842 EMRRECTANGLE em_rt;
2843
2844 if (!l->points || !l->points->next || !l->points->next->next) {
2845 fprintf(stderr, "Warning: Invalid fig box omitted.\n");
2846 return;
2847 }
2848
2849 em_rt.emr.iType = htofl(EMR_RECTANGLE);
2850 em_rt.emr.nSize = htofl(sizeof(EMRRECTANGLE));
2851 em_rt.rclBox.left = htofl(l->points->x);
2852 em_rt.rclBox.top = htofl(l->points->y);
2853 em_rt.rclBox.right = htofl(l->points->next->next->x);
2854 em_rt.rclBox.bottom = htofl(l->points->next->next->y);
2855
2856 # ifdef __EMF_DEBUG__
2857 fprintf(stderr, "Rectangle rclBox (ltrb): %d %d %d %d\n",
2858 ftohl(em_rt.rclBox.left), ftohl(em_rt.rclBox.top),
2859 ftohl(em_rt.rclBox.right), ftohl(em_rt.rclBox.bottom));
2860 # endif
2861
2862 emh_write(&em_rt, sizeof(EMRRECTANGLE), (size_t) 1, EMH_RECORD);
2863 }/* end rect */
2864
2865
roundrect(l)2866 static void roundrect(l)
2867 F_line *l;
2868 {
2869 EMRROUNDRECT em_rr;
2870
2871 if (!l->points || !l->points->next || !l->points->next->next) {
2872 fprintf(stderr, "Warning: Invalid fig box omitted.\n");
2873 return;
2874 }
2875
2876 em_rr.emr.iType = htofl(EMR_ROUNDRECT);
2877 em_rr.emr.nSize = htofl(sizeof(EMRROUNDRECT));
2878 em_rr.rclBox.left = htofl(l->points->x);
2879 em_rr.rclBox.top = htofl(l->points->y);
2880 em_rr.rclBox.right = htofl(l->points->next->next->x);
2881 em_rr.rclBox.bottom = htofl(l->points->next->next->y);
2882 em_rr.szlCorner.cx = em_rr.szlCorner.cy = htofl(l->radius * 2);
2883
2884 # ifdef __EMF_DEBUG__
2885 fprintf(stderr, "RoundRectangle rclBox (ltrb): %d %d %d %d\n",
2886 ftohl(em_rr.rclBox.left), ftohl(em_rr.rclBox.top),
2887 ftohl(em_rr.rclBox.right), ftohl(em_rr.rclBox.bottom));
2888 # endif
2889
2890 emh_write(&em_rr, sizeof(EMRROUNDRECT), (size_t) 1, EMH_RECORD);
2891 }
2892
2893
2894 /* Draws interior and outline of a simple closed shape. Cannot be
2895 * used for polylines and arcs (open shapes) or for arcboxes
2896 * (closed but not a simple emf primitive). */
shape(l,join,cap,drawshape)2897 static void shape(l, join, cap, drawshape)
2898 F_line *l;
2899 int join; /* join style */
2900 int cap; /* cap style */
2901 void (*drawshape)(F_line *);
2902 {
2903
2904 edgeattr(1, l->style, l->thickness, l->pen_color, join, cap);
2905 fillstyle(l->fill_color, l->fill_style, l->pen_color);
2906 drawshape(l);
2907 }/* end shape */
2908
2909
2910 /* Draws interior of a closed shape, taking into account fill color
2911 * and pattern. Boundary must be drawn separately. Used for
2912 * polylines, arcboxes and arcs. */
shape_interior(l,drawshape)2913 static void shape_interior(l, drawshape)
2914 F_line *l;
2915 void (*drawshape)(F_line *);
2916 {
2917
2918 if (l->fill_style >= 0) {
2919 edgevis(0); /* Don't draw edges */
2920 fillstyle(l->fill_color, l->fill_style, l->pen_color);
2921 drawshape(l);
2922 }
2923 }/* end shape_interior */
2924
2925
2926 /* Converts regular strings to unicode strings. If the utext pointer is
2927 * null, memory is allocated. Note, that carriage returns are converted
2928 * to nulls. */
textunicode(str,n_chars,utext,n_unicode)2929 static void textunicode(str, n_chars, utext, n_unicode)
2930 char *str;
2931 int *n_chars;
2932 short **utext; /* If *utext is null, memory is allocated */
2933 int *n_unicode;
2934 {
2935 #if defined(I18N) && defined(USE_ICONV)
2936 iconv_t icd = (iconv_t) -1;
2937 const char *src;
2938 char *dst, *p;
2939 size_t srcleft, srccnt, dstleft, dstcnt;
2940 int i;
2941
2942 if (figLanguage != LANG_DEFAULT) {
2943 if ((icd = iconv_open(EMF_ICONV_CODESET, iconvCharset[figLanguage])) ==
2944 (iconv_t) -1)
2945 perror("genemf: iconv");
2946 }
2947
2948 src = str;
2949 srcleft = srccnt = strlen(str);
2950 if ((dst = (char *) *utext) == NULL) {
2951 dst = (char *) (*utext = calloc(srcleft + 2/*null termination + align*/,
2952 sizeof(short)));
2953 dstleft = dstcnt = srcleft * sizeof(short);
2954 } else
2955 dstleft = dstcnt = *n_unicode;
2956
2957 if (icd != (iconv_t) -1) {
2958 if (iconv(icd, &src, &srcleft, &dst, &dstleft) == (size_t) -1)
2959 fprintf(stderr, "genemf: iconv: illegal byte sequence\n");
2960
2961 (void) iconv_close(icd);
2962
2963 *n_chars = srccnt - srcleft;
2964 *n_unicode = dstcnt - dstleft;
2965
2966 /* Convert '\n' to 0 */
2967 p = (void *)*utext;
2968 for (i = 0; i < *n_unicode; i += 2) {
2969 #ifdef EMF_ICONV_NEED_SWAP
2970 /* swap byte order */
2971 char c = p[i];
2972 p[i] = p[i + 1];
2973 p[i + 1] = c;
2974 #endif
2975 if (p[i] == '\n' && p[i+1] == 0)
2976 p[i] = 0;
2977 }
2978 } else {
2979 *n_chars = srccnt;
2980 *n_unicode = srccnt * 2;
2981 for (i = 0; i < srccnt; i++) {
2982 if (str[i] == '\n')
2983 (*utext)[i] = 0;
2984 else
2985 (*utext)[i] = htofs(str[i]);
2986 }
2987 }
2988 #else /* !(defined(I18N) && defined(USE_ICONV)) */
2989 int i;
2990
2991 *n_chars = strlen(str);
2992 *n_unicode = *n_chars * 2;
2993 if (*utext == NULL) {
2994 *utext = (short *)calloc((size_t) *n_unicode + 4 /* null + align */,
2995 (size_t) 1);
2996 }
2997 for (i = 0; i < *n_chars; i++) { /* Convert to unicode. */
2998 if (str[i] == '\n') {
2999 (*utext)[i] = 0;
3000 } else {
3001 (*utext)[i] = htofs(str[i]);
3002 }
3003 }
3004 #endif
3005 }/* end textunicode */
3006
3007
text(x,y,bbx,str)3008 static void text(x, y, bbx, str)
3009 int x, y; /* reference point */
3010 RECTL *bbx; /* bounding box */
3011 char *str;
3012 {
3013 int n_chars, n_unicode;
3014 short *utext = NULL;
3015 EMREXTTEXTOUTW em_tx; /* Text structure in little endian format */
3016
3017 memset(&em_tx, 0, sizeof(EMREXTTEXTOUTW));
3018 em_tx.emr.iType = htofl(EMR_EXTTEXTOUTW);
3019
3020 em_tx.rclBounds = *bbx;
3021
3022 # ifdef __EMF_DEBUG__
3023 fprintf(stderr, "Textout |%s| rclBounds (ltrb): %d %d %d %d\n",
3024 str,
3025 ftohl(em_tx.rclBounds.left), ftohl(em_tx.rclBounds.top),
3026 ftohl(em_tx.rclBounds.right), ftohl(em_tx.rclBounds.bottom));
3027 # endif
3028
3029 em_tx.iGraphicsMode = htofl(GM_COMPATIBLE);
3030 em_tx.exScale.bit_uint = htofl(PIXEL_01MM_BITPATTERN);
3031 em_tx.eyScale.bit_uint = htofl(PIXEL_01MM_BITPATTERN);
3032
3033 em_tx.emrtext.ptlReference.x = htofl(x);
3034 em_tx.emrtext.ptlReference.y = htofl(y);
3035
3036 textunicode(str, &n_chars, &utext, &n_unicode);
3037
3038 em_tx.emrtext.nChars = htofl(n_unicode / 2); /* number of unicode chars */
3039 em_tx.emrtext.offString = htofl(sizeof(EMREXTTEXTOUTW));
3040
3041 n_unicode = (n_unicode + 4) & ~3; /* null termination + align */
3042 em_tx.emr.nSize = htofl(sizeof(EMREXTTEXTOUTW) + n_unicode);
3043
3044 emh_write(&em_tx, sizeof(EMREXTTEXTOUTW), (size_t) 1, EMH_RECORD);
3045 emh_write(utext, (size_t) 1, (size_t) n_unicode, EMH_DATA);
3046
3047 free(utext);
3048 }/* end text */
3049
3050
textcolr(color)3051 static void textcolr(color)
3052 int color;
3053 {
3054 static int oldcolor = UNDEFVALUE;
3055 EMRSETTEXTCOLOR em_tc;
3056
3057 bkmode(TRANSPARENT); /* fig doesn't have text background */
3058 chkcache(color, oldcolor);
3059
3060 memset(&em_tc, 0, sizeof(EMRSETTEXTCOLOR));
3061 em_tc.emr.iType = htofl(EMR_SETTEXTCOLOR);
3062 em_tc.emr.nSize = htofl(sizeof(EMRSETTEXTCOLOR));
3063 HTOFL(em_tc.crColor, conv_color(color));
3064
3065 # ifdef __EMF_DEBUG__
3066 fprintf(stderr, "SetTextColor (rgb): %x\n", ftohl(em_tc.crColor));
3067 # endif
3068
3069 emh_write(&em_tc, sizeof(EMRSETTEXTCOLOR), (size_t) 1, EMH_RECORD);
3070 }/* end textcolr */
3071
3072
textalign(align)3073 static void textalign(align)
3074 int align;
3075 {
3076 static int oldalign = TA_LEFT|TA_TOP|TA_NOUPDATECP; /* startup default */
3077 EMRSETTEXTALIGN em_ta;
3078
3079 chkcache(align, oldalign);
3080 em_ta.emr.iType = htofl(EMR_SETTEXTALIGN);
3081 em_ta.emr.nSize = htofl(sizeof(EMRSETTEXTALIGN));
3082 em_ta.iMode = htofl(align);
3083
3084 # ifdef __EMF_DEBUG__
3085 fprintf(stderr, "SetTextAlign (mode): 0x%x\n", align);
3086 # endif
3087
3088 emh_write(&em_ta, sizeof(EMRSETTEXTALIGN), (size_t) 1, EMH_RECORD);
3089 }
3090
3091
3092 #if defined(I18N) && defined(USE_ICONV)
moveto(x,y)3093 static void moveto(x, y)
3094 int x, y;
3095 {
3096 EMRMOVETOEX em_mv;
3097
3098 em_mv.emr.iType = htofl(EMR_MOVETOEX);
3099 em_mv.emr.nSize = htofl(sizeof(EMRMOVETOEX));
3100 em_mv.ptl.x = htofl(x);
3101 em_mv.ptl.y = htofl(y);
3102
3103 # ifdef __EMF_DEBUG__
3104 fprintf(stderr, "MoveTo (x, y): %d, %d\n", x, y);
3105 # endif
3106
3107 emh_write(&em_mv, sizeof(EMRMOVETOEX), (size_t) 1, EMH_RECORD);
3108 }
3109 #endif /* defined(I18N) && defined(USE_ICONV) */
3110
3111
3112 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_option(opt,optarg)3113 void genemf_option(opt, optarg)
3114 char opt;
3115 char *optarg;
3116 {
3117
3118 rounded_arrows = False;
3119 switch (opt) {
3120 case 'r':
3121 rounded_arrows = True;
3122 break;
3123
3124 case 'l':
3125 if (strcasecmp(optarg, "win95") == 0)
3126 emflevel = EMF_LEVEL_WIN95;
3127 else if (strcasecmp(optarg, "win98") == 0)
3128 emflevel = EMF_LEVEL_WIN98;
3129 else if (strcasecmp(optarg, "winnt") == 0)
3130 emflevel = EMF_LEVEL_WINNT;
3131 else
3132 fprintf(stderr, "warning: unknown level %s ignored\n", optarg);
3133 break;
3134
3135 case 'f': /* Ignore magnification, font sizes and lang here */
3136 case 'm':
3137 case 's':
3138 case 'L':
3139 break;
3140
3141 default:
3142 put_msg(Err_badarg, opt, "emf");
3143 exit(1);
3144 }
3145 }/* end genemf_option */
3146
3147
3148 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_start(objects)3149 void genemf_start(objects)
3150 F_compound *objects;
3151 {
3152 EMRSETMAPMODE em_sm;
3153 short *uni_description = NULL; /* Unitext description. */
3154 int n_chars, n_unicode;
3155 F_comment comm, *p;
3156 size_t commlen;
3157 short *ud;
3158 char *figname;
3159
3160 #if defined(I18N) && defined(USE_ICONV)
3161 if (support_i18n) {
3162 char *locale;
3163
3164 locale = getenv("LANG");
3165 if (locale == NULL) {
3166 fprintf(stderr, "fig2dev: LANG not defined; assuming C locale\n");
3167 locale = "C";
3168 }
3169 if (strncmp(locale, "zh_CN", (size_t) 5) == 0)
3170 figLanguage = LANG_ZH_CN;
3171 else if (strncmp(locale, "zh_TW", (size_t) 5) == 0)
3172 figLanguage = LANG_ZH_TW;
3173 else if (strncmp(locale, "ja", (size_t) 2) == 0)
3174 figLanguage = LANG_JA;
3175 else if (strncmp(locale, "ko", (size_t) 2) == 0)
3176 figLanguage = LANG_KO;
3177 }
3178 #endif
3179
3180 memset(&emh, 0, sizeof(ENHMETAHEADER));
3181 emh.iType = htofl(EMR_HEADER);
3182
3183 emh.dSignature = htofl(ENHMETA_SIGNATURE);
3184 emh.nVersion = htofl(ENHMETA_VERSION);
3185 emh_nHandles = 0;
3186 handles = NULL;
3187 latesthandle = (void *) &handles;
3188
3189 memset(lasthandle, 0, sizeof(lasthandle)); /* Initialize the DC handles */
3190
3191 /* Create a description string. */
3192
3193 if (from)
3194 figname=from;
3195 else
3196 figname=strdup("stdin");
3197
3198 comm.next = objects->comments;
3199 if ((comm.comment = malloc(strlen(figname) +
3200 80 + sizeof VERSION + sizeof PATCHLEVEL)) == NULL) {
3201 perror("fig2dev: malloc");
3202 exit(1);
3203 }
3204 sprintf(comm.comment,
3205 "Converted from %s using fig2dev %s.%s for %s",
3206 figname, VERSION, PATCHLEVEL, emflevelname[emflevel]);
3207
3208 /* prescan comment strings and (over)estimate the total length */
3209 commlen = 0;
3210 for (p = &comm; p; p = p->next)
3211 commlen += strlen(p->comment) + 1;
3212
3213 commlen = commlen * 2 + 2; /* 2byte/char (+ align) */
3214 if ((uni_description = malloc(commlen)) == NULL) {
3215 perror("fig2dev: malloc");
3216 exit(1);
3217 }
3218
3219 /* convert comment strings to unicode */
3220 ud = uni_description;
3221 for (p = &comm; p; p = p->next) {
3222 # ifdef __EMF_DEBUG__
3223 fprintf(stderr, "%s\n", p->comment);
3224 # endif
3225 n_unicode = commlen;
3226 textunicode(p->comment, &n_chars, &ud, &n_unicode);
3227 commlen -= n_unicode;
3228 ud += n_unicode/2;
3229 *ud++ = 0;
3230 }
3231 *ud = 0; /* for align */
3232 n_unicode = (char *)ud - (char *)uni_description; /* length in byte */
3233
3234 emh.nDescription = htofl(n_unicode / 2);
3235 emh.offDescription = htofl(sizeof(ENHMETAHEADER));
3236
3237 /* The size of the reference device in pixels. We will define a pixel
3238 * in xfig uints of 1200 dots per inch and we'll use an 250 x 200 mm
3239 * or 10.24 x 8.46 inch viewing area. */
3240
3241 emh.szlMillimeters.cx = htofl(260); /* 10.24 inches wide. */
3242 emh.szlMillimeters.cy = htofl(215); /* 8.46 inches high. */
3243
3244 HTOFL(emh.szlDevice.cx, round(260 * 47.244094));
3245 HTOFL(emh.szlDevice.cy, round(215 * 47.244094));
3246
3247 /* Inclusive-inclusive bounds in device units (1200 dpi) and
3248 * 0.01 mm units. Add 1/20 inch all the way around. */
3249
3250 emh.rclBounds.left = htofl(llx - 48);
3251 emh.rclBounds.top = htofl(lly - 48);
3252 emh.rclBounds.right = htofl(urx + 48);
3253 emh.rclBounds.bottom = htofl(ury + 48);
3254
3255 HTOFL(emh.rclFrame.left, floor((llx - 48) * PIXEL_01MM));
3256 HTOFL(emh.rclFrame.top, floor((lly - 48) * PIXEL_01MM));
3257 HTOFL(emh.rclFrame.right, ceil((urx + 48) * PIXEL_01MM));
3258 HTOFL(emh.rclFrame.bottom, ceil((ury + 48) * PIXEL_01MM));
3259
3260 # ifdef __EMF_DEBUG__
3261 fprintf(stderr, "rclBounds (ltrb): %d %d %d %d\n",
3262 ftohl(emh.rclBounds.left), ftohl(emh.rclBounds.top),
3263 ftohl(emh.rclBounds.right), ftohl(emh.rclBounds.bottom));
3264 fprintf(stderr, "rclFrame (ltrb): %d %d %d %d\n",
3265 ftohl(emh.rclFrame.left), ftohl(emh.rclFrame.top),
3266 ftohl(emh.rclFrame.right), ftohl(emh.rclFrame.bottom));
3267 # endif
3268
3269 n_unicode = (n_unicode + 3) & ~3; /* null termination + align */
3270 emh.nSize = htofl(sizeof(ENHMETAHEADER) + n_unicode);
3271
3272 emh_write(&emh, sizeof(ENHMETAHEADER), (size_t) 1, EMH_RECORD);
3273 emh_write(uni_description, (size_t) 1, (size_t) n_unicode, EMH_DATA);
3274
3275 /* The SetMapMode function sets the mapping mode of the specified
3276 * device context. The mapping mode defines the unit of measure used
3277 * to transform page-space units into device-space units, and also
3278 * defines the orientation of the device's x and y axes. */
3279 em_sm.emr.iType = htofl(EMR_SETMAPMODE);
3280 em_sm.emr.nSize = htofl(sizeof(EMRSETMAPMODE));
3281
3282 /* MM_TEXT Each logical unit is mapped to one device pixel. Positive
3283 * x is to the right; positive y is down. The MM_TEXT mode allows
3284 * applications to work in device pixels, whose size varies from device
3285 * to device. */
3286 em_sm.iMode = htofl(MM_TEXT);
3287 # ifdef __EMF_DEBUG__
3288 fprintf(stderr, "SetMapMode: %d\n", ftohl(em_sm.iMode));
3289 # endif
3290 emh_write(&em_sm, sizeof(EMRSETMAPMODE), (size_t) 1, EMH_RECORD);
3291
3292 free(comm.comment);
3293 free(uni_description);
3294 }/* end genemf_start */
3295
3296
3297 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_arc(_a)3298 void genemf_arc(_a)
3299 F_arc *_a;
3300 {
3301 F_arc a = *_a;
3302
3303 if (cwarc(&a))
3304 arc_reverse(&a); /* make counter clockwise arc */
3305
3306 switch (a.type) {
3307 case T_OPEN_ARC:
3308 /* open arcs should be drawn separately */
3309 shape_interior((F_line *)(void *)&a, (void (*)(F_line *))arcinterior);
3310 if (a.thickness > 0) {
3311 edgeattr(1, a.style, a.thickness, a.pen_color, 0, a.cap_style);
3312 arcoutline(&a);
3313 }
3314 break;
3315 case T_PIE_WEDGE_ARC:
3316 shape((F_line *)(void *)&a, a.cap_style, 0,
3317 (void (*)(F_line *))arcoutline);
3318 break;
3319 default:
3320 fprintf(stderr, "Unsupported fig arc type %d.\n", a.type);
3321 }
3322 }/* end genemf_arc */
3323
3324
3325 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_ellipse(e)3326 void genemf_ellipse(e)
3327 F_ellipse *e;
3328 {
3329
3330 switch (e->type) {
3331 case T_ELLIPSE_BY_RAD:
3332 case T_ELLIPSE_BY_DIA:
3333 if (fabs(e->angle) > EPSILON && fabs(sin(e->angle)) > EPSILON)
3334 rotated_ellipse(e);
3335 else
3336 shape((F_line *)e, 0, 0, (void (*)(F_line *))ellipse);
3337 break;
3338 case T_CIRCLE_BY_RAD:
3339 case T_CIRCLE_BY_DIA:
3340 shape((F_line *)e, 0, 0, (void (*)(F_line *))circle);
3341 break;
3342 default:
3343 fprintf(stderr, "Unsupported FIG ellipse type %d.\n", e->type);
3344 }
3345 }/* end genemf_ellipse */
3346
3347
3348 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_line(l)3349 void genemf_line(l)
3350 F_line *l;
3351 {
3352
3353 switch (l->type) {
3354 case T_POLYLINE:
3355 shape_interior(l, polygon); /* draw interior */
3356
3357 if (l->points->next == NULL /* single point line */
3358 && l->cap_style == 0) { /* butt style */
3359 /* draw as projecting style but in smaller size */
3360 edgeattr(1, l->style, (l->thickness + 1) / 2, l->pen_color,
3361 l->join_style, 2);
3362 } else {
3363 edgeattr(1, l->style, l->thickness, l->pen_color,
3364 l->join_style, l->cap_style);
3365 }
3366
3367 polyline(l); /* draw boundary */
3368 break;
3369 case T_BOX:
3370 shape(l, l->join_style, l->cap_style, rect); /* simple closed shape */
3371 break;
3372 case T_POLYGON:
3373 shape(l, l->join_style, l->cap_style, polygon);
3374 break;
3375 case T_ARC_BOX:
3376 shape(l, 0, 0, roundrect); /* simple closed shape */
3377 break;
3378 case T_PIC_BOX:
3379 picbox(l);
3380 break;
3381 default:
3382 fprintf(stderr, "Unsupported FIG polyline type %d.\n", l->type);
3383 return;
3384 }
3385 }/* end genemf_line */
3386
3387
3388 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
3389 /*ARGSUSED*/
genemf_spline(s)3390 void genemf_spline(s)
3391 F_spline *s;
3392 {
3393 static int wgiv = 0;
3394
3395 if (!wgiv) {
3396 fprintf(stderr, "\
3397 Warning: the EMF driver doesn't support (old style) FIG splines.\n\
3398 Suggestion: convert your (old?) FIG image by loading it into xfig v3.2 or\n\
3399 or higher and saving again.\n");
3400 wgiv = 1;
3401 }
3402 }/* end genemf_spline */
3403
3404
3405 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_text(t)3406 void genemf_text(t)
3407 F_text *t;
3408 {
3409 int font;
3410 RECTL rclBounds;
3411 int x, y;
3412 double sin_theta, cos_theta;
3413 #if defined(I18N) && defined(USE_ICONV)
3414 unsigned char *s, *s1, bak;
3415 int nascii, neuc;
3416 #endif
3417
3418 textcolr(t->color);
3419 font = conv_fontindex(t->font, t->flags); /* Convert the font index */
3420
3421 /*
3422 * calculate start position
3423 */
3424 x = t->base_x;
3425 y = t->base_y;
3426 sin_theta = sin(t->angle);
3427 cos_theta = cos(t->angle);
3428 switch (t->type) {
3429 case T_LEFT_JUSTIFIED:
3430 break;
3431 case T_CENTER_JUSTIFIED:
3432 x = x + (-(t->length/2.0) * cos_theta);
3433 y = y + ((t->length/2.0) * sin_theta);
3434 break;
3435 case T_RIGHT_JUSTIFIED:
3436 x = x + (-t->length * cos_theta);
3437 y = y + (t->length * sin_theta);
3438 break;
3439 default:
3440 fprintf(stderr, "Unsupported fig text type %d.\n", t->type);
3441 }
3442
3443 HTOFL(rclBounds.left, round(x - t->size * sin_theta));
3444 HTOFL(rclBounds.top, round(y - t->size * cos_theta));
3445 HTOFL(rclBounds.right, round(x + t->length * cos_theta));
3446 HTOFL(rclBounds.bottom, round(y + t->length * sin_theta));
3447
3448 #if defined(I18N) && defined(USE_ICONV)
3449 if (figLanguage != LANG_DEFAULT && IS_LOCALE_FONT(font)) {
3450 /* prescan text to decide if font switching is needed */
3451 nascii = neuc = 0;
3452 for (s = (void *) t->cstring; *s; s++) {
3453 if (*s > 127)
3454 neuc++;
3455 else
3456 nascii++;
3457 }
3458
3459 if (neuc == 0)
3460 ; /* ASCII only */
3461 else if (nascii == 0) {
3462 /* locale font only */
3463 font = (font == FONT_TIMES_ROMAN) ?
3464 FONT_LOCALE_ROMAN : FONT_LOCALE_BOLD;
3465 } else {
3466 /*
3467 * need font switching
3468 */
3469
3470 /*
3471 * use home grown alignment
3472 */
3473 /* use and update current position */
3474 textalign(TA_LEFT | TA_BASELINE | TA_UPDATECP);
3475
3476 /* move to the first (left) position */
3477 moveto(x, y);
3478
3479 for (s = (void *) t->cstring; *s; s = s1) {
3480 if (*s & 0x80) {
3481 /* EUC 2byte char */
3482 for (s1 = s; *s1 & 0x80; s1 += 2)
3483 ;
3484 textfont((font == FONT_TIMES_ROMAN) ?
3485 FONT_LOCALE_ROMAN : FONT_LOCALE_BOLD,
3486 t->size, round(t->angle * RAD_01DEG));
3487 } else {
3488 /* ascii */
3489 for (s1 = s; *s1 && (*s1 & 0x80) == 0; s1++)
3490 ;
3491 textfont(font, t->size, round(t->angle * RAD_01DEG));
3492 }
3493 bak = *s1;
3494 *s1 = '\0';
3495
3496 text(0, 0, &rclBounds, s);
3497
3498 *s1 = bak;
3499 }
3500 return;
3501 }
3502 }
3503 #endif /* defined(I18N) && defined(USE_ICONV) */
3504
3505 /*
3506 * Use alignment of EMF, which shall be better than that of home grown.
3507 * Do not use current position.
3508 */
3509 switch (t->type) {
3510 case T_LEFT_JUSTIFIED:
3511 textalign(TA_LEFT | TA_BASELINE | TA_NOUPDATECP);
3512 break;
3513 case T_CENTER_JUSTIFIED:
3514 textalign(TA_CENTER | TA_BASELINE | TA_NOUPDATECP);
3515 break;
3516 case T_RIGHT_JUSTIFIED:
3517 textalign(TA_RIGHT | TA_BASELINE | TA_NOUPDATECP);
3518 break;
3519 }
3520
3521 textfont(font, t->size, round(t->angle * RAD_01DEG));
3522 text(t->base_x, t->base_y, &rclBounds, t->cstring);
3523 }/* end genemf_text */
3524
3525
3526 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_end()3527 int genemf_end()
3528 {
3529 EMREOF em_eof;
3530 struct emfhandle *h, *h1;
3531
3532 /* delete all created handles */
3533 for (h = handles; h; h = h1) {
3534 delete_handle(h);
3535 h1 = h->next;
3536 free(h);
3537 }
3538
3539 memset(&em_eof, 0, sizeof(EMREOF));
3540 em_eof.emr.iType = htofl(EMR_EOF);
3541 em_eof.emr.nSize = htofl(sizeof(EMREOF));
3542 em_eof.offPalEntries = htofl(sizeof(EMREOF) - sizeof(EMFulong));
3543 em_eof.nSizeLast = htofl(sizeof(EMREOF));
3544 emh_write(&em_eof, sizeof(EMREOF), (size_t) 1, EMH_RECORD);
3545
3546 # ifdef __EMF_DEBUG__
3547 fprintf(stderr, "Metafile Bytes: %d Records: %d Handles: %d\n",
3548 emh_nBytes, emh_nRecords, emh_nHandles);
3549 # endif
3550
3551 /* Rewrite the updated header record at the beginning of the file. */
3552
3553 emh.nBytes = htofl(emh_nBytes);
3554 emh.nRecords = htofl(emh_nRecords);
3555 emh_nHandles++; /* size of handle table is last handle number + 1 */
3556 emh.nHandles = htofs(emh_nHandles);
3557
3558 if (fseek(tfp, 0L, SEEK_SET) < 0) {
3559 fprintf(stderr,"\
3560 fig2dev: error: fseek() failed. EMF language requires the output is seekable.\
3561 \n\t\tOutput to a plain file, not to a pipe.\n");
3562 return -1;
3563 }
3564 if (fwrite(&emh, (size_t) 1, sizeof(ENHMETAHEADER), tfp)
3565 != sizeof(ENHMETAHEADER) || fseek(tfp, 0L, SEEK_END) < 0) {
3566 fprintf(stderr,"fig2dev: error: failed to write EMF header\n");
3567 return -1;
3568 }
3569
3570 /* all ok */
3571 return 0;
3572 }/* end genemf_end */
3573
3574
3575 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
3576 struct driver dev_emf = {
3577 genemf_option,
3578 genemf_start,
3579 gendev_null, /* TODO - Create genemf_grid for 3.2.4 */
3580 genemf_arc,
3581 genemf_ellipse,
3582 genemf_line,
3583 genemf_spline,
3584 genemf_text,
3585 genemf_end,
3586 INCLUDE_TEXT
3587 };
3588