1 /* output-emf.c --- output in Enhanced Metafile format
2
3 Copyright (C) 2000, 2001 Enrico Persiani
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License
7 as published by the Free Software Foundation; either version 2.1 of
8 the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 USA. */
19
20 /*
21 ** Notes:
22 **
23 ** Since EMF files are binary files, their persistent
24 ** format have to deal with endianess problems
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif /* Def: HAVE_CONFIG_H */
30
31 #include <stdio.h>
32 #include <string.h>
33 #include "spline.h"
34 #include "xstd.h"
35
36 /* EMF record-number definitions */
37
38 #define ENMT_HEADER 1
39 #define ENMT_EOF 14
40 #define ENMT_POLYLINETO 6
41 #define ENMT_MOVETO 27
42 #define ENMT_POLYBEZIERTO 5
43 #define ENMT_BEGINPATH 59
44 #define ENMT_ENDPATH 60
45 #define ENMT_FILLPATH 62
46 #define ENMT_CREATEPEN 38
47 #define ENMT_CREATEBRUSHINDIRECT 39
48 #define ENMT_SELECTOBJECT 37
49 #define ENMT_SETWORLDTRANSFORM 35
50 #define ENMT_SETPOLYFILLMODE 19
51 #define ENMT_STROKEPATH 64
52 #define ENMT_LINETO 54
53 #define ENMT_POLYBEZIERTO16 88
54
55 #define STOCK_NULL_PEN 0x80000008
56
57 #define FM_ALTERNATE 1
58
59 #define WDEVPIXEL 1280
60 #define HDEVPIXEL 1024
61 #define WDEVMLMTR 320
62 #define HDEVMLMTR 240
63
64 #define SCALE (at_real) 1.0
65
66 #define MAKE_COLREF(r,g,b) (((r) & 0x0FF) | (((g) & 0x0FF) << 8) | (((b) & 0x0FF) << 16))
67 #define MK_PEN(n) ((n) * 2 + 1)
68 #define MK_BRUSH(n) ((n) * 2 + 2)
69 #define X_FLOAT_TO_UI32(num) ((UI32)(num * SCALE))
70 #define X_FLOAT_TO_UI16(num) ((UI16)(num * SCALE))
71 #define Y_FLOAT_TO_UI32(num) ((UI32)(y_offset - num * SCALE))
72 #define Y_FLOAT_TO_UI16(num) ((UI16)(y_offset - num * SCALE))
73
74 /* maybe these definitions be put into types.h
75 with some ifdefs ... */
76
77 typedef unsigned long int UI32;
78 typedef unsigned short int UI16;
79 typedef unsigned char UI8;
80
81 /* color list type */
82
83 typedef struct EMFColorListType
84 {
85 UI32 colref;
86 struct EMFColorListType *next;
87 } EMFColorList;
88
89 /* Emf stats needed for outputting EHNMETAHEADER*/
90
91 typedef struct
92 {
93 int ncolors;
94 int nrecords;
95 int filesize;
96 } EMFStats;
97
98 /* globals */
99
100 static EMFColorList *color_list = NULL; /* Color list */
101 static UI32 *color_table = NULL; /* Color table */
102 static float y_offset;
103
104 /* color list & table functions */
105
SearchColor(EMFColorList * head,UI32 colref)106 static int SearchColor(EMFColorList *head, UI32 colref)
107 {
108 while(head != NULL)
109 {
110 if(head->colref == colref)
111 return 1;
112 head = head->next;
113 }
114 return 0;
115 }
116
AddColor(EMFColorList ** head,UI32 colref)117 static void AddColor(EMFColorList **head, UI32 colref)
118 {
119 EMFColorList *temp;
120
121 XMALLOC(temp, sizeof(EMFColorList));
122
123 temp->colref = colref;
124 temp->next = *head;
125 *head = temp;
126 }
127
ColorListToColorTable(EMFColorList ** head,UI32 ** table,int len)128 static void ColorListToColorTable(EMFColorList **head, UI32 **table, int len)
129 {
130 EMFColorList *temp;
131 int i = 0;
132
133 XMALLOC(*table, sizeof(UI32) * len);
134
135 while(*head != NULL)
136 {
137 temp = *head;
138 *head = (*head)->next;
139 (*table)[i] = temp->colref;
140 i++;
141 free(temp);
142 }
143 }
144
ColorLookUp(UI32 colref,UI32 * table,int len)145 static int ColorLookUp(UI32 colref, UI32 *table, int len)
146 {
147 int i;
148
149 for(i=0; i<len; i++)
150 {
151 if(colref == table[i])
152 return i;
153 }
154 return 0;
155 }
156
157 /* endianess independent IO functions */
158
write32(FILE * fdes,UI32 data)159 static at_bool write32(FILE *fdes, UI32 data)
160 {
161 size_t count = 0;
162 UI8 outch;
163
164 outch = (UI8) (data & 0x0FF);
165 count += fwrite(&outch, 1, 1, fdes);
166
167 outch = (UI8) ((data >> 8) & 0x0FF);
168 count += fwrite(&outch, 1, 1, fdes);
169
170 outch = (UI8) ((data >> 16) & 0x0FF);
171 count += fwrite(&outch, 1, 1, fdes);
172
173 outch = (UI8) ((data >> 24) & 0x0FF);
174 count += fwrite(&outch, 1, 1, fdes);
175
176 return (count == sizeof(UI32)) ? true : false;
177 }
178
write16(FILE * fdes,UI16 data)179 static at_bool write16(FILE *fdes, UI16 data)
180 {
181 size_t count = 0;
182 UI8 outch;
183
184 outch = (UI8) (data & 0x0FF);
185 count += fwrite(&outch, 1, 1, fdes);
186
187 outch = (UI8) ((data >> 8) & 0x0FF);
188 count += fwrite(&outch, 1, 1, fdes);
189
190 return (count == sizeof(UI16)) ? true : false;
191 }
192
193 /* EMF record-type function definitions */
194
WriteMoveTo(FILE * fdes,at_real_coord * pt)195 static int WriteMoveTo(FILE* fdes, at_real_coord *pt)
196 {
197 int recsize = sizeof(UI32) * 4;
198
199 if(fdes != NULL)
200 {
201 write32(fdes, ENMT_MOVETO);
202 write32(fdes, (UI32) recsize);
203 write32(fdes, (UI32) X_FLOAT_TO_UI32(pt->x));
204 write32(fdes, (UI32) Y_FLOAT_TO_UI32(pt->y));
205 }
206 return recsize;
207 }
208
WriteLineTo(FILE * fdes,spline_type * spl)209 static int WriteLineTo(FILE* fdes, spline_type *spl)
210 {
211 int recsize = sizeof(UI32) * 4;
212
213 if(fdes != NULL)
214 {
215 write32(fdes, ENMT_LINETO);
216 write32(fdes, (UI32) recsize);
217 write32(fdes, (UI32) X_FLOAT_TO_UI32(END_POINT(*spl).x));
218 write32(fdes, (UI32) Y_FLOAT_TO_UI32(END_POINT(*spl).y));
219 }
220 return recsize;
221 }
222
223 /* CorelDraw 9 can't handle PolyLineTo nor PolyLineTo16, so we
224 do not use this function but divide it to single lines instead
225 int WritePolyLineTo(FILE* fdes, spline_type *spl, int nlines)
226 {
227 int i;
228 int recsize = sizeof(UI32) * (7 + nlines * 1);
229
230 if(fdes != NULL)
231 {
232 write32(fdes, ENMT_POLYLINETO);
233 write32(fdes, (UI32) recsize);
234 write32(fdes, (UI32) 0x0);
235 write32(fdes, (UI32) 0x0);
236 write32(fdes, (UI32) 0xFFFFFFFF);
237 write32(fdes, (UI32) 0xFFFFFFFF);
238 write32(fdes, (UI32) nlines);
239
240 for(i=0; i<nlines; i++)
241 {
242 write16(fdes, (UI16) FLOAT_TO_UI32(END_POINT(spl[i]).x));
243 write16(fdes, (UI16) FLOAT_TO_UI32(END_POINT(spl[i]).y));
244 }
245 }
246 return recsize;
247 } */
248
MyWritePolyLineTo(FILE * fdes,spline_type * spl,int nlines)249 static int MyWritePolyLineTo(FILE* fdes, spline_type *spl, int nlines)
250 {
251 int i;
252 int recsize = nlines * WriteLineTo(NULL, NULL);
253
254 if(fdes != NULL)
255 {
256 for(i=0; i<nlines; i++)
257 {
258 WriteLineTo(fdes, &spl[i]);
259 }
260 }
261 return recsize;
262 }
263
264 /* CorelDraw 9 can't handle PolyBezierTo so we do not use this
265 function but use PolyBezierTo16 instead
266
267 int WritePolyBezierTo(FILE *fdes, spline_type *spl, int ncurves)
268 {
269 int i;
270 int recsize = sizeof(UI32) * (7 + ncurves * 6);
271
272 if(fdes != NULL)
273 {
274 write32(fdes, ENMT_POLYBEZIERTO);
275 write32(fdes, (UI32) recsize);
276 write32(fdes, (UI32) 0x0);
277 write32(fdes, (UI32) 0x0);
278 write32(fdes, (UI32) 0xFFFFFFFF);
279 write32(fdes, (UI32) 0xFFFFFFFF);
280 write32(fdes, (UI32) ncurves * 3);
281
282 for(i=0; i<ncurves; i++)
283 {
284 write16(fdes, (UI32) FLOAT_TO_UI32(CONTROL1(spl[i]).x));
285 write16(fdes, (UI32) FLOAT_TO_UI32(CONTROL1(spl[i]).y));
286 write16(fdes, (UI32) FLOAT_TO_UI32(CONTROL2(spl[i]).x));
287 write16(fdes, (UI32) FLOAT_TO_UI32(CONTROL2(spl[i]).y));
288 write16(fdes, (UI32) FLOAT_TO_UI32(END_POINT(spl[i]).x));
289 write16(fdes, (UI32) FLOAT_TO_UI32(END_POINT(spl[i]).y));
290 }
291 }
292 return recsize;
293 } */
294
WritePolyBezierTo16(FILE * fdes,spline_type * spl,int ncurves)295 static int WritePolyBezierTo16(FILE *fdes, spline_type *spl, int ncurves)
296 {
297 int i;
298 int recsize = sizeof(UI32) * 7 + sizeof(UI16) * ncurves * 6;
299
300 if(fdes != NULL)
301 {
302 write32(fdes, ENMT_POLYBEZIERTO16);
303 write32(fdes, (UI32) recsize);
304 write32(fdes, (UI32) 0x0);
305 write32(fdes, (UI32) 0x0);
306 write32(fdes, (UI32) 0xFFFFFFFF);
307 write32(fdes, (UI32) 0xFFFFFFFF);
308 write32(fdes, (UI32) ncurves * 3);
309
310 for(i=0; i<ncurves; i++)
311 {
312 write16(fdes, (UI16) X_FLOAT_TO_UI16(CONTROL1(spl[i]).x));
313 write16(fdes, (UI16) Y_FLOAT_TO_UI16(CONTROL1(spl[i]).y));
314 write16(fdes, (UI16) X_FLOAT_TO_UI16(CONTROL2(spl[i]).x));
315 write16(fdes, (UI16) Y_FLOAT_TO_UI16(CONTROL2(spl[i]).y));
316 write16(fdes, (UI16) X_FLOAT_TO_UI16(END_POINT(spl[i]).x));
317 write16(fdes, (UI16) Y_FLOAT_TO_UI16(END_POINT(spl[i]).y));
318 }
319 }
320 return recsize;
321 }
322
323
WriteSetPolyFillMode(FILE * fdes)324 static int WriteSetPolyFillMode(FILE *fdes)
325 {
326 int recsize = sizeof(UI32) * 3;
327
328 if(fdes != NULL)
329 {
330 write32(fdes, ENMT_SETPOLYFILLMODE);
331 write32(fdes, (UI32) recsize);
332 write32(fdes, (UI32) FM_ALTERNATE);
333 }
334 return recsize;
335 }
336
WriteBeginPath(FILE * fdes)337 static int WriteBeginPath(FILE *fdes)
338 {
339 int recsize = sizeof(UI32) * 2;
340
341 if(fdes != NULL)
342 {
343 write32(fdes, ENMT_BEGINPATH);
344 write32(fdes, (UI32) recsize);
345 }
346 return recsize;
347 }
348
WriteEndPath(FILE * fdes)349 static int WriteEndPath(FILE *fdes)
350 {
351 int recsize = sizeof(UI32) * 2;
352
353 if(fdes != NULL)
354 {
355 write32(fdes, ENMT_ENDPATH);
356 write32(fdes, (UI32) recsize);
357 }
358 return recsize;
359 }
360
WriteFillPath(FILE * fdes)361 static int WriteFillPath(FILE *fdes)
362 {
363 int recsize = sizeof(UI32) * 6;
364
365 if(fdes != NULL)
366 {
367 write32(fdes, ENMT_FILLPATH);
368 write32(fdes, (UI32) recsize);
369 write32(fdes, (UI32) 0x0);
370 write32(fdes, (UI32) 0x0);
371 write32(fdes, (UI32) 0xFFFFFFFF);
372 write32(fdes, (UI32) 0xFFFFFFFF);
373 }
374 return recsize;
375 }
376
WriteStrokePath(FILE * fdes)377 static int WriteStrokePath(FILE *fdes)
378 {
379 int recsize = sizeof(UI32) * 6;
380
381 if(fdes != NULL)
382 {
383 write32(fdes, ENMT_STROKEPATH);
384 write32(fdes, (UI32) recsize);
385 write32(fdes, (UI32) 0x0);
386 write32(fdes, (UI32) 0x0);
387 write32(fdes, (UI32) 0xFFFFFFFF);
388 write32(fdes, (UI32) 0xFFFFFFFF);
389 }
390 return recsize;
391 }
392
393 #if 0
394 static int WriteSetWorldTransform(FILE *fdes, UI32 height)
395 {
396 int recsize = sizeof(UI32) * 8;
397 float fHeight;
398
399 if(fdes != NULL)
400 {
401 float s1 = (float) (1.0/SCALE);
402 float s2 = (float) (1.0/SCALE);
403 UI32 t1;
404 UI32 t2;
405 /* conversion to float */
406 fHeight = (float) height;
407 /* binary copy for serialization */
408 memcpy((void *) &height, (void *) &fHeight, sizeof(UI32));
409 memcpy((void *) &t1, (void *) &s1, sizeof(UI32));
410 memcpy((void *) &t2, (void *) &s2, sizeof(UI32));
411
412 write32(fdes, ENMT_SETWORLDTRANSFORM);
413 write32(fdes, (UI32) recsize);
414 write32(fdes, (UI32) t1);
415 write32(fdes, (UI32) 0x0);
416 write32(fdes, (UI32) 0x0);
417 write32(fdes, (UI32) t2);
418 write32(fdes, (UI32) 0x0);
419 write32(fdes, (UI32) 0x0);
420 }
421 return recsize;
422 }
423 #endif /* 0 */
424
WriteCreateSolidPen(FILE * fdes,int hndNum,UI32 colref)425 static int WriteCreateSolidPen(FILE *fdes, int hndNum, UI32 colref)
426 {
427 int recsize = sizeof(UI32) * 7;
428
429 if(fdes != NULL)
430 {
431 write32(fdes, ENMT_CREATEPEN);
432 write32(fdes, (UI32) recsize);
433 write32(fdes, (UI32) hndNum);
434 write32(fdes, (UI32) 0x0); /* solid pen style */
435 write32(fdes, (UI32) 0x0); /* 1 pixel ... */
436 write32(fdes, (UI32) 0x0); /* ... pen size */
437 write32(fdes, (UI32) colref);
438 }
439 return recsize;
440 }
441
WriteCreateSolidBrush(FILE * fdes,int hndNum,UI32 colref)442 static int WriteCreateSolidBrush(FILE *fdes, int hndNum, UI32 colref)
443 {
444 int recsize = sizeof(UI32) * 6;
445
446 if(fdes != NULL)
447 {
448 write32(fdes, ENMT_CREATEBRUSHINDIRECT);
449 write32(fdes, (UI32) recsize);
450 write32(fdes, (UI32) hndNum);
451 write32(fdes, (UI32) 0x0); /* solid brush style */
452 write32(fdes, (UI32) colref);
453 write32(fdes, (UI32) 0x0); /* ignored when solid */
454
455 }
456 return recsize;
457 }
458
WriteSelectObject(FILE * fdes,int hndNum)459 static int WriteSelectObject(FILE *fdes, int hndNum)
460 {
461 int recsize = sizeof(UI32) * 3;
462
463 if(fdes != NULL)
464 {
465 write32(fdes, ENMT_SELECTOBJECT);
466 write32(fdes, (UI32) recsize);
467 write32(fdes, (UI32) hndNum);
468 }
469 return recsize;
470 }
471
WriteEndOfMetafile(FILE * fdes)472 static int WriteEndOfMetafile(FILE *fdes)
473 {
474 int recsize = sizeof(UI32) * 5;
475
476 if(fdes != NULL)
477 {
478 write32(fdes, ENMT_EOF);
479 write32(fdes, (UI32) recsize);
480 write32(fdes, (UI32) 0);
481 write32(fdes, (UI32) recsize - sizeof(UI32));
482 write32(fdes, (UI32) recsize);
483
484 }
485 return recsize;
486 }
487
WriteHeader(FILE * fdes,at_string name,int width,int height,int fsize,int nrec,int nhand)488 static int WriteHeader(FILE *fdes, at_string name, int width, int height, int fsize, int nrec, int nhand)
489 {
490 int i, recsize;
491 size_t desclen;
492 const char * editor = at_version(true);
493
494 desclen = (strlen(editor) + strlen(name) + 3);
495 recsize = sizeof(UI32) * 25 + (desclen * 2) + ((desclen * 2) % 4);
496
497 if(fdes != NULL)
498 {
499 write32(fdes, ENMT_HEADER);
500 write32(fdes, (UI32) recsize);
501 /* pixel bounds */
502 write32(fdes, (UI32) 0);
503 write32(fdes, (UI32) 0);
504 write32(fdes, (UI32) width);
505 write32(fdes, (UI32) height);
506 /* millimeter bounds */
507 write32(fdes, (UI32) 0);
508 write32(fdes, (UI32) 0);
509 write32(fdes, (UI32) width * WDEVMLMTR * 100 / WDEVPIXEL);
510 write32(fdes, (UI32) height * HDEVMLMTR * 100 / HDEVPIXEL);
511 /* signature " EMF" */
512 write32(fdes, (UI32) 0x464D4520);
513 /* current version */
514 write32(fdes, (UI32) 0x00010000);
515 /* file size */
516 write32(fdes, (UI32) fsize);
517 /* number of records */
518 write32(fdes, (UI32) nrec);
519 /* number of handles */
520 write16(fdes, (UI16) nhand);
521 /* reserved */
522 write16(fdes, (UI16) 0);
523 /* size of description */
524 write32(fdes, (UI32) desclen);
525 /* description offset */
526 write32(fdes, (UI32) 100);
527 /* palette entries */
528 write32(fdes, (UI32) 0);
529 /* device width & height in pixel & millimeters */
530 write32(fdes, (UI32) WDEVPIXEL);
531 write32(fdes, (UI32) HDEVPIXEL);
532 write32(fdes, (UI32) WDEVMLMTR);
533 write32(fdes, (UI32) HDEVMLMTR);
534 /* pixel format & opengl (not used) */
535 write32(fdes, (UI32) 0);
536 write32(fdes, (UI32) 0);
537 write32(fdes, (UI32) 0);
538 /* description string in Unicode */
539 for(i=0;editor[i]; i++)
540 {
541 write16(fdes, ((UI16) (editor[i] & 0x07F)) );
542 }
543 write16(fdes, (UI16) 0);
544 for(i=0;name[i]; i++)
545 {
546 write16(fdes, ((UI16) (name[i] & 0x07F)) );
547 }
548 write32(fdes, (UI32) 0);
549 if((desclen * 2) % 4)
550 write16(fdes, (UI16) 0);
551 }
552 return recsize;
553 }
554
555 /* EMF stats collector */
556
GetEmfStats(EMFStats * stats,at_string name,spline_list_array_type shape)557 static void GetEmfStats(EMFStats *stats, at_string name, spline_list_array_type shape)
558 {
559 unsigned int i, j;
560 int ncolors = 0;
561 int ncolorchng = 0;
562 int nrecords = 0;
563 int filesize = 0;
564 UI32 last_color = 0xFFFFFFFF, curr_color;
565 spline_list_type curr_list;
566 spline_type curr_spline;
567 int last_degree;
568 int nlines;
569
570 /* visit each spline-list */
571 for(i=0; i<SPLINE_LIST_ARRAY_LENGTH(shape); i++)
572 {
573 curr_list = SPLINE_LIST_ARRAY_ELT(shape, i);
574 curr_color = MAKE_COLREF(curr_list.color.r,curr_list.color.g,curr_list.color.b);
575 if(i == 0 || curr_color != last_color)
576 {
577 ncolorchng++;
578 if(!SearchColor(color_list, curr_color))
579 {
580 ncolors++;
581 AddColor(&color_list, curr_color);
582 }
583 last_color = curr_color;
584 /* emf stats :: BeginPath + EndPath + FillPath */
585 nrecords += 3;
586 filesize += WriteBeginPath(NULL) + WriteEndPath(NULL) + WriteFillPath(NULL);
587 }
588 /* emf stats :: MoveTo */
589 nrecords ++;
590 filesize += WriteMoveTo(NULL,NULL);
591 /* visit each spline */
592 j = 0;
593 last_degree = -1;
594 /* the outer loop iterates through spline
595 groups of the same degree */
596 while(j<SPLINE_LIST_LENGTH(curr_list))
597 {
598 nlines = 0;
599 curr_spline = SPLINE_LIST_ELT(curr_list, j);
600 last_degree = ((int)SPLINE_DEGREE(curr_spline));
601
602 /* the inner loop iterates through lists
603 of spline having the same degree */
604 while(last_degree == ((int)SPLINE_DEGREE(curr_spline)))
605 {
606 nlines++;
607 j++;
608 if(j>=SPLINE_LIST_LENGTH(curr_list))
609 break;
610 curr_spline = SPLINE_LIST_ELT(curr_list, j);
611 }
612 switch((polynomial_degree)last_degree)
613 {
614 case LINEARTYPE:
615 /* emf stats :: PolyLineTo */
616 nrecords += nlines;
617 filesize += MyWritePolyLineTo(NULL, NULL, nlines);
618 break;
619 default:
620 /* emf stats :: PolyBezierTo */
621 nrecords++;
622 filesize += WritePolyBezierTo16(NULL, NULL, nlines);
623 break;
624 }
625 }
626 }
627
628 /* emf stats :: CreateSolidPen & CreateSolidBrush*/
629 nrecords += ncolors * 2;
630 filesize += (WriteCreateSolidPen(NULL, 0, 0) + WriteCreateSolidBrush(NULL, 0, 0)) * ncolors;
631
632 /* emf stats :: SelectObject */
633 nrecords += ncolorchng * 2;
634 filesize += WriteSelectObject(NULL, 0) * ncolorchng * 2;
635 /* emf stats :: header + footer */
636 nrecords += 2;
637 filesize += WriteEndOfMetafile(NULL) + WriteHeader(NULL, name, 0, 0, 0, 0, 0);
638
639 /* emf stats :: SetPolyFillMode */
640 nrecords++;
641 filesize += WriteSetPolyFillMode(NULL);
642
643 stats->ncolors = ncolors;
644 stats->nrecords = nrecords;
645 stats->filesize = filesize;
646
647 /* convert the color list into a color table */
648 ColorListToColorTable(&color_list, &color_table, ncolors);
649 }
650
651
652 /* EMF output */
653
OutputEmf(FILE * fdes,EMFStats * stats,at_string name,int width,int height,spline_list_array_type shape)654 static void OutputEmf(FILE* fdes, EMFStats *stats, at_string name, int width, int height, spline_list_array_type shape)
655 {
656 unsigned int i, j;
657 int color_index;
658 UI32 last_color = 0xFFFFFFFF, curr_color;
659 spline_list_type curr_list;
660 spline_type curr_spline;
661 int last_degree;
662 int nlines;
663
664 /* output EMF header */
665 WriteHeader(fdes, name, width, height, stats->filesize, stats->nrecords, (stats->ncolors * 2) +1);
666
667 y_offset = SCALE * height;
668 /* output pens & brushes */
669 for(i=0; i<(unsigned int) stats->ncolors; i++)
670 {
671 WriteCreateSolidPen(fdes, MK_PEN(i), color_table[i]);
672 WriteCreateSolidBrush(fdes, MK_BRUSH(i), color_table[i]);
673 }
674
675 /* output fill mode */
676 WriteSetPolyFillMode(fdes);
677
678 /* visit each spline-list */
679 for(i=0; i<SPLINE_LIST_ARRAY_LENGTH(shape); i++)
680 {
681 curr_list = SPLINE_LIST_ARRAY_ELT(shape, i);
682
683 /* output pen & brush selection */
684 curr_color = MAKE_COLREF(curr_list.color.r,curr_list.color.g,curr_list.color.b);
685 if(i == 0 || curr_color != last_color)
686 {
687 if (i > 0)
688 {
689 /* output EndPath */
690 WriteEndPath(fdes);
691
692 if (shape.centerline)
693 /* output StrokePath */
694 WriteStrokePath(fdes);
695 else
696 /* output StrokePath */
697 WriteFillPath(fdes);
698 }
699 /* output a BeginPath for current shape */
700 WriteBeginPath(fdes);
701
702 color_index = ColorLookUp(curr_color, color_table, stats->ncolors);
703 if (shape.centerline)
704 WriteSelectObject(fdes, MK_PEN(color_index));
705 else
706 WriteSelectObject(fdes, STOCK_NULL_PEN);
707 WriteSelectObject(fdes, MK_BRUSH(color_index));
708 last_color = curr_color;
709 }
710 /* output MoveTo first point */
711 curr_spline = SPLINE_LIST_ELT(curr_list, 0);
712 WriteMoveTo(fdes, &(START_POINT(curr_spline)));
713
714 /* visit each spline */
715 j = 0;
716 /* the outer loop iterates through spline
717 groups of the same degree */
718 while (j<SPLINE_LIST_LENGTH(curr_list))
719 {
720 nlines = 0;
721 curr_spline = SPLINE_LIST_ELT(curr_list, j);
722 last_degree = ((int)SPLINE_DEGREE(curr_spline));
723
724 /* the inner loop iterates through lists
725 of spline having the same degree */
726 while(last_degree == ((int)SPLINE_DEGREE(curr_spline)))
727 {
728 nlines++;
729 j++;
730 if(j>=SPLINE_LIST_LENGTH(curr_list))
731 break;
732 curr_spline = SPLINE_LIST_ELT(curr_list, j);
733 }
734 switch((polynomial_degree)last_degree)
735 {
736 case LINEARTYPE:
737 /* output PolyLineTo */
738 MyWritePolyLineTo(fdes, &(SPLINE_LIST_ELT(curr_list, j - nlines)), nlines);
739 break;
740 default:
741 /* output PolyBezierTo */
742 WritePolyBezierTo16(fdes, &(SPLINE_LIST_ELT(curr_list, j - nlines)), nlines);
743 break;
744 }
745 }
746 }
747 if (SPLINE_LIST_ARRAY_LENGTH(shape) > 0)
748 {
749 /* output EndPath */
750 WriteEndPath(fdes);
751
752 if (shape.centerline)
753 /* output StrokePath */
754 WriteStrokePath(fdes);
755 else
756 /* output StrokePath */
757 WriteFillPath(fdes);
758 }
759
760 /* output EndOfMetafile */
761 WriteEndOfMetafile(fdes);
762
763 /* delete color table */
764 free((void *)color_table);
765 }
766
767
output_emf_writer(FILE * file,at_string name,int llx,int lly,int urx,int ury,at_output_opts_type * opts,spline_list_array_type shape)768 int output_emf_writer(FILE* file, at_string name,
769 int llx, int lly, int urx, int ury,
770 at_output_opts_type * opts,
771 spline_list_array_type shape)
772 {
773 EMFStats stats;
774
775 #ifdef _WINDOWS
776 if(file == stdout)
777 {
778 fprintf(stderr, "This driver couldn't write to stdout!\n");
779 return -1;
780 }
781 #endif
782
783 /* Get EMF stats */
784 GetEmfStats(&stats, name, shape);
785
786 /* Output EMF */
787 OutputEmf(file, &stats, name, urx, ury, shape);
788
789 return 0;
790 }
791