]> granicus.if.org Git - imagemagick/blob - coders/wmf.c
(no commit message)
[imagemagick] / coders / wmf.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                             W   W   M   M  FFFFF                            %
7 %                             W   W   MM MM  F                                %
8 %                             W W W   M M M  FFF                              %
9 %                             WW WW   M   M  F                                %
10 %                             W   W   M   M  F                                %
11 %                                                                             %
12 %                                                                             %
13 %                        Read Windows Metafile Format                         %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                               December 2000                                 %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 */
36 \f
37 /*
38   Include declarations.
39 */
40 #include "MagickCore/studio.h"
41 #include "MagickCore/property.h"
42 #include "MagickCore/blob.h"
43 #include "MagickCore/blob-private.h"
44 #include "MagickCore/color.h"
45 #include "MagickCore/color-private.h"
46 #include "MagickCore/constitute.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/image.h"
50 #include "MagickCore/image-private.h"
51 #include "MagickCore/list.h"
52 #include "MagickCore/log.h"
53 #include "MagickCore/magick.h"
54 #include "MagickCore/memory_.h"
55 #include "MagickCore/monitor.h"
56 #include "MagickCore/monitor-private.h"
57 #include "MagickCore/paint.h"
58 #include "MagickCore/quantum-private.h"
59 #include "MagickCore/static.h"
60 #include "MagickCore/string_.h"
61 #include "MagickCore/module.h"
62 #include "MagickCore/type.h"
63 #include "MagickCore/module.h"
64 #include "MagickWand/MagickWand.h"
65
66 #if defined(__CYGWIN__)
67 #undef MAGICKCORE_WMF_DELEGATE 
68 #endif
69
70 #if defined(MAGICKCORE_WMF_DELEGATE)
71 #include "libwmf/api.h"
72 #include "libwmf/eps.h"
73 \f
74 /*
75 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 %                                                                             %
77 %                                                                             %
78 %                                                                             %
79 %   R e a d W M F I m a g e                                                   %
80 %                                                                             %
81 %                                                                             %
82 %                                                                             %
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 %
85 %  ReadWMFImage() reads an Windows Metafile image file and returns it.  It
86 %  allocates the memory necessary for the new Image structure and returns a
87 %  pointer to the new image.
88 %
89 %  The format of the ReadWMFImage method is:
90 %
91 %      Image *ReadWMFImage(const ImageInfo *image_info,ExceptionInfo *exception)
92 %
93 %  A description of each parameter follows:
94 %
95 %    o image_info: the image info.
96 %
97 %    o exception: return any errors or warnings in this structure.
98 %
99 */
100
101 static int WMFReadBlob(void *image)
102 {
103   return(ReadBlobByte((Image *) image));
104 }
105
106 static int WMFSeekBlob(void *image,long offset)
107 {
108   return((int) SeekBlob((Image *) image,(MagickOffsetType) offset,SEEK_SET));
109 }
110
111 static long WMFTellBlob(void *image)
112 {
113   return((long) TellBlob((Image*) image));
114 }
115
116 static Image *ReadWMFImage(const ImageInfo *image_info,ExceptionInfo *exception)
117 {
118   char
119     filename[MaxTextExtent];
120
121   int
122     unique_file;
123
124   FILE
125     *file;
126
127   Image
128     *image;
129
130   ImageInfo
131     *read_info;
132
133   MagickBooleanType
134     status;
135
136   size_t
137     flags;
138
139   wmfAPI
140     *wmf_info;
141
142   wmfAPI_Options
143     options;
144
145   wmfD_Rect
146     bounding_box;
147
148   wmf_eps_t
149     *eps_info;
150
151   wmf_error_t
152     wmf_status;
153
154   /*
155     Read WMF image.
156   */
157   image=AcquireImage(image_info,exception);
158   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
159   if (status == MagickFalse)
160     {
161       image=DestroyImageList(image);
162       return((Image *) NULL);
163     }
164   wmf_info=(wmfAPI *) NULL;
165   flags=0;
166   flags|=WMF_OPT_IGNORE_NONFATAL;
167   flags|=WMF_OPT_FUNCTION;
168   options.function=wmf_eps_function;
169   wmf_status=wmf_api_create(&wmf_info,(unsigned long) flags,&options);
170   if (wmf_status != wmf_E_None)
171     {
172       if (wmf_info != (wmfAPI *) NULL)
173         wmf_api_destroy(wmf_info);
174       ThrowReaderException(DelegateError,"UnableToInitializeWMFLibrary");
175     }
176   wmf_status=wmf_bbuf_input(wmf_info,WMFReadBlob,WMFSeekBlob,WMFTellBlob,
177     (void *) image);
178   if (wmf_status != wmf_E_None)
179     {
180       wmf_api_destroy(wmf_info);
181       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
182         image->filename);
183       image=DestroyImageList(image);
184       return((Image *) NULL);
185     }
186   wmf_status=wmf_scan(wmf_info,0,&bounding_box);
187   if (wmf_status != wmf_E_None)
188     {
189       wmf_api_destroy(wmf_info);
190       ThrowReaderException(DelegateError,"FailedToScanFile");
191     }
192   eps_info=WMF_EPS_GetData(wmf_info);
193   file=(FILE *) NULL;
194   unique_file=AcquireUniqueFileResource(filename);
195   if (unique_file != -1)
196     file=fdopen(unique_file,"wb");
197   if ((unique_file == -1) || (file == (FILE *) NULL))
198     {
199       wmf_api_destroy(wmf_info);
200       ThrowReaderException(FileOpenError,"UnableToCreateTemporaryFile");
201     }
202   eps_info->out=wmf_stream_create(wmf_info,file);
203   eps_info->bbox=bounding_box;
204   wmf_status=wmf_play(wmf_info,0,&bounding_box);
205   if (wmf_status != wmf_E_None)
206     {
207       wmf_api_destroy(wmf_info);
208       ThrowReaderException(DelegateError,"FailedToRenderFile");
209     }
210   (void) fclose(file);
211   wmf_api_destroy(wmf_info);
212   (void) CloseBlob(image);
213   image=DestroyImage(image);
214   /*
215     Read EPS image.
216   */
217   read_info=CloneImageInfo(image_info);
218   SetImageInfoBlob(read_info,(void *) NULL,0);
219   (void) FormatLocaleString(read_info->filename,MaxTextExtent,"eps:%s",
220     filename);
221   image=ReadImage(read_info,exception);
222   read_info=DestroyImageInfo(read_info);
223   if (image != (Image *) NULL)
224     {
225       (void) CopyMagickString(image->filename,image_info->filename,
226         MaxTextExtent);
227       (void) CopyMagickString(image->magick_filename,image_info->filename,
228         MaxTextExtent);
229       (void) CopyMagickString(image->magick,"WMF",MaxTextExtent);
230     }
231   (void) RelinquishUniqueFileResource(filename);
232   return(GetFirstImageInList(image));
233 }
234 #elif defined(MAGICKCORE_WMFLITE_DELEGATE)
235
236 #define ERR(API)  ((API)->err != wmf_E_None)
237 #define XC(x) ((double) x)
238 #define YC(y) ((double) y)
239
240 #if !defined(M_PI)
241 #  define M_PI  MagickPI
242 #endif
243
244 #if defined(MAGICKCORE_HAVE_FT2BUILD_H)
245 #  include <ft2build.h>
246 #endif
247
248 #include "libwmf/fund.h"
249 #include "libwmf/types.h"
250 #include "libwmf/api.h"
251 #undef SRCCOPY
252 #undef SRCPAINT
253 #undef SRCAND
254 #undef SRCINVERT
255 #undef SRCERASE
256 #undef NOTSRCCOPY
257 #undef NOTSRCERASE
258 #undef MERGECOPY
259 #undef MERGEPAINT
260 #undef PATCOPY
261 #undef PATPAINT
262 #undef PATINVERT
263 #undef DSTINVERT
264 #undef BLACKNESS
265 #undef WHITENESS
266
267 /* The following additinal undefs were required for MinGW */
268 #undef BS_HOLLOW
269 #undef PS_STYLE_MASK
270 #undef PS_ENDCAP_ROUND
271 #undef PS_ENDCAP_SQUARE
272 #undef PS_ENDCAP_FLAT
273 #undef PS_ENDCAP_MASK
274 #undef PS_JOIN_ROUND
275 #undef PS_JOIN_BEVEL
276 #undef PS_JOIN_MITER
277 #undef PS_COSMETIC
278 #undef PS_GEOMETRIC
279 #undef PS_TYPE_MASK
280 #undef STRETCH_ANDSCANS
281 #undef STRETCH_ORSCANS
282 #undef STRETCH_DELETESCANS
283 #undef STRETCH_HALFTONE
284 #undef ETO_OPAQUE
285 #undef ETO_CLIPPED
286 #undef ETO_GLYPH_INDEX
287 #undef ETO_RTLREADING
288
289 #include "libwmf/defs.h"
290 #include "libwmf/ipa.h"
291 #include "libwmf/color.h"
292 #include "libwmf/macro.h"
293
294 /* Unit conversions */
295 #define TWIPS_PER_INCH        1440
296 #define CENTIMETERS_PER_INCH  2.54
297 #define POINTS_PER_INCH       72
298
299 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
300 # define wmf_api_create(api,flags,options) wmf_lite_create(api,flags,options)
301 # define wmf_api_destroy(api) wmf_lite_destroy(api)
302 # undef WMF_FONT_PSNAME
303 # define WMF_FONT_PSNAME(F) ((F)->user_data ? ((wmf_magick_font_t*) (F)->user_data)->ps_name : 0)
304
305 typedef struct _wmf_magick_font_t wmf_magick_font_t;
306
307 struct _wmf_magick_font_t
308 {
309   char*  ps_name;
310   double pointsize;
311 };
312
313 #endif
314
315 typedef struct _wmf_magick_t wmf_magick_t;
316
317 struct _wmf_magick_t
318 {
319   /* Bounding box */
320   wmfD_Rect
321     bbox;
322
323   /* Scale and translation factors */
324   double
325     scale_x,
326     scale_y,
327     translate_x,
328     translate_y,
329     rotate;
330
331   /* Vector output */
332   DrawingWand
333     *draw_wand;
334
335   ExceptionInfo
336     *exception;
337
338   /* ImageMagick image */
339   Image
340     *image;
341
342   /* ImageInfo */
343   const ImageInfo
344     *image_info;
345
346   /* DrawInfo */
347   DrawInfo
348     *draw_info;
349
350   /* Pattern ID */
351   unsigned long
352     pattern_id;
353
354   /* Clip path flag */
355   MagickBooleanType
356     clipping;
357
358   /* Clip path ID */
359   unsigned long
360     clip_mask_id;
361
362   /* Push depth */
363   long
364     push_depth;
365 };
366
367
368 #define WMF_MAGICK_GetData(Z) ((wmf_magick_t*)((Z)->device_data))
369 #define WMF_MAGICK_GetFontData(Z) \
370   ((wmf_magick_font_t*)((wmfFontData *)Z->font_data)->user_data)
371
372 #define WmfDrawingWand (((wmf_magick_t*)((API)->device_data))->draw_wand)
373
374 /* Enum to control whether util_set_brush applies brush to fill or
375    stroke. */
376 typedef enum
377 {
378   BrushApplyFill,
379   BrushApplyStroke
380 } BrushApply;
381
382
383 /* Enum to specify arc type */
384 typedef enum
385 {
386   magick_arc_ellipse = 0,
387   magick_arc_open,
388   magick_arc_pie,
389   magick_arc_chord
390 }
391 magick_arc_t;
392
393 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
394 static void  lite_font_init (wmfAPI* API, wmfAPI_Options* options);
395 static void  lite_font_map(wmfAPI* API,wmfFont* font);
396 static float lite_font_stringwidth(wmfAPI* API, wmfFont* font, char* str);
397 #endif
398
399 static void         draw_fill_color_rgb(wmfAPI* API, const wmfRGB* rgb);
400 static void         draw_stroke_color_rgb(wmfAPI* API, const wmfRGB* rgb);
401 static void         draw_pattern_push(wmfAPI* API, unsigned long id, unsigned long columns, unsigned long rows);
402 static int          ipa_blob_read(void* wand);
403 static int          ipa_blob_seek(void* wand,long position);
404 static long         ipa_blob_tell(void* wand);
405 static void         ipa_bmp_draw(wmfAPI * API, wmfBMP_Draw_t * bmp_draw);
406 static void         ipa_bmp_free(wmfAPI * API, wmfBMP * bmp);
407 static void         ipa_bmp_read(wmfAPI * API, wmfBMP_Read_t * bmp_read);
408 static void         ipa_device_begin(wmfAPI * API);
409 static void         ipa_device_close(wmfAPI * API);
410 static void         ipa_device_end(wmfAPI * API);
411 static void         ipa_device_open(wmfAPI * API);
412 static void         ipa_draw_arc(wmfAPI * API, wmfDrawArc_t * draw_arc);
413 static void         ipa_draw_chord(wmfAPI * API, wmfDrawArc_t * draw_arc);
414 static void         ipa_draw_ellipse(wmfAPI * API, wmfDrawArc_t * draw_arc);
415 static void         ipa_draw_line(wmfAPI * API, wmfDrawLine_t * draw_line);
416 static void         ipa_draw_pie(wmfAPI * API, wmfDrawArc_t * draw_arc);
417 static void         ipa_draw_pixel(wmfAPI * API, wmfDrawPixel_t * draw_pixel);
418 static void         ipa_draw_polygon(wmfAPI * API, wmfPolyLine_t * poly_line);
419 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
420 static void         ipa_draw_polypolygon(wmfAPI * API, wmfPolyPoly_t* polypolygon);
421 #endif
422 static void         ipa_draw_rectangle(wmfAPI * API, wmfDrawRectangle_t * draw_rect);
423 static void         ipa_draw_text(wmfAPI * API, wmfDrawText_t * draw_text);
424 static void         ipa_flood_exterior(wmfAPI * API, wmfFlood_t * flood);
425 static void         ipa_flood_interior(wmfAPI * API, wmfFlood_t * flood);
426 static void         ipa_functions(wmfAPI * API);
427 static void         ipa_poly_line(wmfAPI * API, wmfPolyLine_t * poly_line);
428 static void         ipa_region_clip(wmfAPI * API, wmfPolyRectangle_t * poly_rect);
429 static void         ipa_region_frame(wmfAPI * API, wmfPolyRectangle_t * poly_rect);
430 static void         ipa_region_paint(wmfAPI * API, wmfPolyRectangle_t * poly_rect);
431 static void         ipa_rop_draw(wmfAPI * API, wmfROP_Draw_t * rop_draw);
432 static void         ipa_udata_copy(wmfAPI * API, wmfUserData_t * userdata);
433 static void         ipa_udata_free(wmfAPI * API, wmfUserData_t * userdata);
434 static void         ipa_udata_init(wmfAPI * API, wmfUserData_t * userdata);
435 static void         ipa_udata_set(wmfAPI * API, wmfUserData_t * userdata);
436 static int          magick_progress_callback(void* wand,float quantum);
437 static void         util_draw_arc(wmfAPI * API, wmfDrawArc_t * draw_arc,magick_arc_t finish);
438 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
439 /*static int          util_font_weight( const char* font );*/
440 #endif
441 static double       util_pointsize( wmfAPI* API, wmfFont* font, char* str, double font_height, ExceptionInfo *);
442 static void         util_set_brush(wmfAPI * API, wmfDC * dc, const BrushApply brush_apply);
443 static void         util_set_pen(wmfAPI * API, wmfDC * dc);
444
445 /* Progress callback */
446 int magick_progress_callback(void *context,float quantum)
447 {
448   Image
449     *image;
450
451   MagickBooleanType
452     status;
453
454   image=(Image *) context;
455   assert(image->signature == MagickSignature);
456   status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
457     GetBlobSize(image));
458   return(status == MagickTrue ? 0 : 1);
459 }
460
461 /* Set fill color */
462 static void draw_fill_color_string(DrawingWand *drawing_wand,const char *color)
463 {
464   PixelWand
465     *fill_color;
466
467   fill_color=NewPixelWand();
468   PixelSetColor(fill_color,color);
469   DrawSetFillColor(drawing_wand,fill_color);
470   fill_color=DestroyPixelWand(fill_color);
471 }
472 static void draw_fill_color_rgb( wmfAPI* API, const wmfRGB* rgb )
473 {
474   PixelWand
475     *fill_color;
476
477   fill_color=NewPixelWand();
478   PixelSetRedQuantum(fill_color,ScaleCharToQuantum(rgb->r));
479   PixelSetGreenQuantum(fill_color,ScaleCharToQuantum(rgb->g));
480   PixelSetBlueQuantum(fill_color,ScaleCharToQuantum(rgb->b));
481   PixelSetAlphaQuantum(fill_color,OpaqueAlpha);
482   DrawSetFillColor(WmfDrawingWand,fill_color);
483   fill_color=DestroyPixelWand(fill_color);
484 }
485
486 /* Set stroke color */
487 static void draw_stroke_color_string(DrawingWand *drawing_wand,const char *color)
488 {
489   PixelWand
490     *stroke_color;
491
492   stroke_color=NewPixelWand();
493   PixelSetColor(stroke_color,color);
494   DrawSetStrokeColor(drawing_wand,stroke_color);
495   stroke_color=DestroyPixelWand(stroke_color);
496 }
497
498 static void draw_stroke_color_rgb( wmfAPI* API, const wmfRGB* rgb )
499 {
500   PixelWand
501     *stroke_color;
502
503   stroke_color=NewPixelWand();
504   PixelSetRedQuantum(stroke_color,ScaleCharToQuantum(rgb->r));
505   PixelSetGreenQuantum(stroke_color,ScaleCharToQuantum(rgb->g));
506   PixelSetBlueQuantum(stroke_color,ScaleCharToQuantum(rgb->b));
507   PixelSetAlphaQuantum(stroke_color,OpaqueAlpha);
508   DrawSetStrokeColor(WmfDrawingWand,stroke_color);
509   stroke_color=DestroyPixelWand(stroke_color);
510 }
511
512 /* Set under color */
513 static void draw_under_color_string(DrawingWand *drawing_wand,const char *color)
514 {
515   PixelWand
516     *under_color;
517
518   under_color=NewPixelWand();
519   PixelSetColor(under_color,color);
520   DrawSetTextUnderColor(drawing_wand,under_color);
521   under_color=DestroyPixelWand(under_color);
522 }
523
524 static void draw_pattern_push( wmfAPI* API,
525                                unsigned long id,
526                                unsigned long columns,
527                                unsigned long rows )
528 {
529   char
530     pattern_id[30];
531
532   (void) FormatLocaleString(pattern_id,MaxTextExtent,"brush_%lu",id);
533   (void) DrawPushPattern(WmfDrawingWand,pattern_id,0,0,columns,rows);
534 }
535
536 /* Pattern/Bit BLT with raster operation (ROP) support.  Invoked by
537    META_PATBLT, which is equivalent to Windows PatBlt() call, or by
538    META_DIBBITBLT which is equivalent to Windows BitBlt() call. */
539
540 /* The BitBlt function transfers pixels from a rectangular area in one
541    device wand called the 'source', to a rectangular area of the
542    same size in another device wand, called the 'destination'. */
543
544 static void ipa_rop_draw(wmfAPI * API, wmfROP_Draw_t * rop_draw)
545 {
546 /*   wmfBrush */
547 /*     *brush = WMF_DC_BRUSH(rop_draw->dc); */
548
549 /*   wmfBMP */
550 /*     *brush_bmp = WMF_BRUSH_BITMAP(brush); */
551
552   if (TO_FILL(rop_draw) == 0)
553     return;
554
555   /* Save graphic wand */
556   (void) PushDrawingWand(WmfDrawingWand);
557
558   /* FIXME: finish implementing (once we know what it is supposed to do!) */
559
560   /*
561   struct _wmfROP_Draw_t
562   {       wmfDC* dc;
563
564     wmfD_Coord TL;
565     wmfD_Coord BR;
566
567     U32 ROP;
568
569     double pixel_width;
570     double pixel_height;
571   };
572   */
573
574 /*   if (brush_bmp && brush_bmp->data != 0) */
575 /*     printf("Have an image!\n"); */
576
577   switch (rop_draw->ROP) /* Ternary raster operations */
578     {
579     case SRCCOPY: /* dest = source */
580       printf("ipa_rop_draw SRCCOPY ROP mode not implemented\n");
581       break;
582     case SRCPAINT: /* dest = source OR dest */
583       printf("ipa_rop_draw SRCPAINT ROP mode not implemented\n");
584       break;
585     case SRCAND: /* dest = source AND dest */
586       printf("ipa_rop_draw SRCAND ROP mode not implemented\n");
587       break;
588     case SRCINVERT: /* dest = source XOR dest */
589       printf("ipa_rop_draw SRCINVERT ROP mode not implemented\n");
590       break;
591     case SRCERASE: /* dest = source AND (NOT dest) */
592       printf("ipa_rop_draw SRCERASE ROP mode not implemented\n");
593       break;
594     case NOTSRCCOPY: /* dest = (NOT source) */
595       printf("ipa_rop_draw NOTSRCCOPY ROP mode not implemented\n");
596       break;
597     case NOTSRCERASE: /* dest = (NOT src) AND (NOT dest) */
598       printf("ipa_rop_draw NOTSRCERASE ROP mode not implemented\n");
599       break;
600     case MERGECOPY: /* dest = (source AND pattern) */
601       printf("ipa_rop_draw MERGECOPY ROP mode not implemented\n");
602       break;
603     case MERGEPAINT: /* dest = (NOT source) OR dest */
604       printf("ipa_rop_draw MERGEPAINT ROP mode not implemented\n");
605       break;
606     case PATCOPY: /* dest = pattern */
607       util_set_brush(API, rop_draw->dc, BrushApplyFill);
608       break;
609     case PATPAINT: /* dest = DPSnoo */
610       printf("ipa_rop_draw PATPAINT ROP mode not implemented\n");
611       break;
612     case PATINVERT: /* dest = pattern XOR dest */
613       printf("ipa_rop_draw PATINVERT ROP mode not implemented\n");
614       break;
615     case DSTINVERT: /* dest = (NOT dest) */
616       printf("ipa_rop_draw DSTINVERT ROP mode not implemented\n");
617       break;
618     case BLACKNESS: /* dest = BLACK */
619       draw_fill_color_string(WmfDrawingWand,"black");
620       break;
621     case WHITENESS: /* dest = WHITE */
622       draw_fill_color_string(WmfDrawingWand,"white");
623       break;
624     default:
625       printf("ipa_rop_draw 0x%x ROP mode not implemented\n", rop_draw->ROP);
626       break;
627     }
628
629   DrawRectangle(WmfDrawingWand,
630                  XC(rop_draw->TL.x), YC(rop_draw->TL.y),
631                  XC(rop_draw->BR.x), YC(rop_draw->BR.y));
632
633   /* Restore graphic wand */
634   (void) PopDrawingWand(WmfDrawingWand);
635 }
636
637 static void ipa_bmp_draw(wmfAPI *API, wmfBMP_Draw_t *bmp_draw)
638 {
639   wmf_magick_t
640     *ddata = WMF_MAGICK_GetData(API);
641
642   ExceptionInfo
643     *exception;
644
645   Image
646     *image;
647
648   MagickWand
649     *magick_wand;
650
651   double
652     height,
653     width;
654
655   PixelInfo
656     white;
657
658   if (bmp_draw->bmp.data == 0)
659     return;
660
661   image = (Image*)bmp_draw->bmp.data;
662   if (!image)
663      return;
664
665   exception=ddata->exception;
666   if (bmp_draw->crop.x || bmp_draw->crop.y ||
667      (bmp_draw->crop.w != bmp_draw->bmp.width) ||
668      (bmp_draw->crop.h != bmp_draw->bmp.height))
669     {
670       /* Image needs to be cropped */
671       Image
672         *crop_image;
673
674       RectangleInfo
675         crop_info;
676
677       crop_info.x = bmp_draw->crop.x;
678       crop_info.y = bmp_draw->crop.y;
679       crop_info.width = bmp_draw->crop.w;
680       crop_info.height = bmp_draw->crop.h;
681
682       crop_image = CropImage( image, &crop_info, exception );
683       if (crop_image)
684         {
685           image=DestroyImageList(image);
686           image = crop_image;
687           bmp_draw->bmp.data = (void*)image;
688         }
689     }
690
691   QueryColorCompliance( "white", AllCompliance, &white, exception );
692
693   if ( ddata->image_info->texture ||
694        !(IsPixelInfoEquivalent(&ddata->image_info->background_color,&white)) ||
695        ddata->image_info->background_color.alpha != OpaqueAlpha )
696   {
697     /*
698       Set image white background to transparent so that it may be
699       overlaid over non-white backgrounds.
700     */
701     QueryColorCompliance( "white", AllCompliance, &white, exception );
702     TransparentPaintImage( image, &white, QuantumRange, MagickFalse, exception );
703   }
704
705   width = fabs(bmp_draw->pixel_width * (double) bmp_draw->crop.w);
706   height = fabs(bmp_draw->pixel_height * (double) bmp_draw->crop.h);
707   magick_wand=NewMagickWandFromImage(image);
708   (void) DrawComposite(WmfDrawingWand, CopyCompositeOp,
709     XC(bmp_draw->pt.x) * ddata->scale_x, YC(bmp_draw->pt.y) * ddata->scale_y,
710     width * ddata->scale_x, height * ddata->scale_y, magick_wand);
711   magick_wand=DestroyMagickWand(magick_wand);
712
713 #if 0
714   printf("bmp_draw->bmp.data   = 0x%lx\n", (long)bmp_draw->bmp.data);
715   printf("registry id          = %li\n", id);
716   /* printf("pixel_width          = %g\n", bmp_draw->pixel_width); */
717   /* printf("pixel_height         = %g\n", bmp_draw->pixel_height); */
718   printf("bmp_draw->bmp WxH    = %ix%i\n", bmp_draw->bmp.width, bmp_draw->bmp.height);
719   printf("bmp_draw->crop WxH   = %ix%i\n", bmp_draw->crop.w, bmp_draw->crop.h);
720   printf("bmp_draw->crop x,y   = %i,%i\n", bmp_draw->crop.x, bmp_draw->crop.y);
721   printf("image size WxH       = %lux%lu\n", image->columns, image->rows);
722 #endif
723 }
724
725 static void ipa_bmp_read(wmfAPI * API, wmfBMP_Read_t * bmp_read) {
726   wmf_magick_t
727     *ddata = WMF_MAGICK_GetData(API);
728
729   ExceptionInfo
730     *exception;
731
732   Image
733     *image;
734
735   ImageInfo
736     *image_info;
737
738   bmp_read->bmp.data = 0;
739
740   image_info=CloneImageInfo(ddata->image_info);
741   exception=ddata->exception;
742   (void) CopyMagickString(image_info->magick,"DIB",MaxTextExtent);
743   if (bmp_read->width || bmp_read->height)
744     {
745       char
746         size[MaxTextExtent];
747
748       (void) FormatLocaleString(size,MaxTextExtent,"%ux%u",bmp_read->width,
749         bmp_read->height);
750       CloneString(&image_info->size,size);
751     }
752 #if 0
753   printf("ipa_bmp_read: buffer=0x%lx length=%ld, width=%i, height=%i\n",
754    (long) bmp_read->buffer, bmp_read->length,
755    bmp_read->width, bmp_read->height);
756 #endif
757   image=BlobToImage(image_info, (const void *) bmp_read->buffer,
758     bmp_read->length, exception);
759   image_info=DestroyImageInfo(image_info);
760   if (image != (Image *) NULL)
761     {
762 #if 0
763       printf("ipa_bmp_read: rows=%ld,columns=%ld\n\n", image->rows, image->columns);
764 #endif
765
766       bmp_read->bmp.data   = (void*)image;
767       bmp_read->bmp.width  = (U16)image->columns;
768       bmp_read->bmp.height = (U16)image->rows;
769     }
770 }
771
772 static void ipa_bmp_free(wmfAPI * API, wmfBMP * bmp)
773 {
774   (void) API;
775   DestroyImageList((Image*)bmp->data);
776   bmp->data = (void*) 0;
777   bmp->width = (U16) 0;
778   bmp->height = (U16) 0;
779 }
780
781 /*
782   This called by wmf_play() the *first* time the meta file is played
783  */
784 static void ipa_device_open(wmfAPI * API)
785 {
786   wmf_magick_t
787     *ddata = WMF_MAGICK_GetData (API);
788
789   ddata->pattern_id = 0;
790   ddata->clipping = MagickFalse;
791   ddata->clip_mask_id = 0;
792
793   ddata->push_depth = 0;
794
795   ddata->draw_wand = DrawAllocateWand(ddata->draw_info,ddata->image);
796 }
797
798 /*
799   This called by wmf_api_destroy()
800  */
801 static void ipa_device_close(wmfAPI * API)
802 {
803   wmf_magick_t
804     *ddata = WMF_MAGICK_GetData(API);
805
806   DestroyDrawingWand(ddata->draw_wand);
807   DestroyDrawInfo(ddata->draw_info);
808   RelinquishMagickMemory(WMF_MAGICK_GetFontData(API)->ps_name);
809 }
810
811 /*
812   This called from the beginning of each play for initial page setup
813  */
814 static void ipa_device_begin(wmfAPI * API)
815 {
816   char
817     comment[MaxTextExtent];
818
819   wmf_magick_t
820     *ddata = WMF_MAGICK_GetData(API);
821
822   /* Make SVG output happy */
823   (void) PushDrawingWand(WmfDrawingWand);
824
825   DrawSetViewbox(WmfDrawingWand, 0, 0, ddata->image->columns, ddata->image->rows );
826
827   (void) FormatLocaleString(comment,MaxTextExtent,"Created by ImageMagick %s",
828     GetMagickVersion((size_t *) NULL));
829   DrawComment(WmfDrawingWand,comment);
830
831   /* Scale width and height to image */
832   DrawScale(WmfDrawingWand, ddata->scale_x, ddata->scale_y);
833
834   /* Translate to TL corner of bounding box */
835   DrawTranslate(WmfDrawingWand, ddata->translate_x, ddata->translate_y);
836
837   /* Apply rotation */
838   DrawRotate(WmfDrawingWand, ddata->rotate);
839
840   if (ddata->image_info->texture == NULL)
841     {
842       PixelWand
843         *background_color;
844
845       /* Draw rectangle in background color */
846       background_color=NewPixelWand();
847       PixelSetPixelColor(background_color,&ddata->image->background_color);
848       DrawSetFillColor(WmfDrawingWand,background_color);
849       background_color=DestroyPixelWand(background_color);
850       DrawRectangle(WmfDrawingWand,
851                      XC(ddata->bbox.TL.x),YC(ddata->bbox.TL.y),
852                      XC(ddata->bbox.BR.x),YC(ddata->bbox.BR.y));
853     }
854   else
855     {
856       /* Draw rectangle with texture image the SVG way */
857       Image
858         *image;
859
860       ImageInfo
861         *image_info;
862
863       ExceptionInfo
864         exception;
865
866       GetExceptionInfo(&exception);
867
868       image_info = CloneImageInfo((ImageInfo *) 0);
869       (void) CopyMagickString(image_info->filename,ddata->image_info->texture,
870         MaxTextExtent);
871       if ( ddata->image_info->size )
872         CloneString(&image_info->size,ddata->image_info->size);
873
874       image = ReadImage(image_info,&exception);
875       image_info=DestroyImageInfo(image_info);
876       if (image)
877         {
878           char
879             pattern_id[30];
880
881           MagickWand
882             *magick_wand;
883
884           (void) CopyMagickString(image->magick,"MIFF",MaxTextExtent);
885           DrawPushDefs(WmfDrawingWand);
886           draw_pattern_push(API,ddata->pattern_id,image->columns,image->rows);
887           magick_wand=NewMagickWandFromImage(image);
888           (void) DrawComposite(WmfDrawingWand,CopyCompositeOp,0,0,
889             image->columns,image->rows,magick_wand);
890           magick_wand=DestroyMagickWand(magick_wand);
891           (void) DrawPopPattern(WmfDrawingWand);
892           DrawPopDefs(WmfDrawingWand);
893           (void) FormatLocaleString(pattern_id,MaxTextExtent,"#brush_%lu",
894             ddata->pattern_id);
895           (void) DrawSetFillPatternURL(WmfDrawingWand,pattern_id);
896           ++ddata->pattern_id;
897           DrawRectangle(WmfDrawingWand,
898             XC(ddata->bbox.TL.x),YC(ddata->bbox.TL.y),
899             XC(ddata->bbox.BR.x),YC(ddata->bbox.BR.y));
900           image=DestroyImageList(image);
901         }
902       else
903         {
904           LogMagickEvent(CoderEvent,GetMagickModule(),
905             "reading texture image failed!");
906         }
907     }
908
909   DrawSetClipRule(WmfDrawingWand,EvenOddRule); /* Default for WMF is ALTERNATE polygon fill mode */
910   draw_fill_color_string(WmfDrawingWand,"none"); /* Default brush is WHITE_BRUSH */
911   draw_stroke_color_string(WmfDrawingWand,"none"); /* Default pen is BLACK_PEN */
912   DrawSetStrokeLineCap(WmfDrawingWand,ButtCap); /* Default linecap is PS_ENDCAP_FLAT */
913   DrawSetStrokeLineJoin(WmfDrawingWand,MiterJoin); /* Default linejoin is PS_JOIN_MITER */
914   draw_under_color_string(WmfDrawingWand,"white"); /* Default text box is white */
915 }
916
917 /*
918   This called from the end of each play for page termination
919  */
920 static void ipa_device_end(wmfAPI * API)
921 {
922   wmf_magick_t
923     *ddata = WMF_MAGICK_GetData(API);
924
925   /* Reset any existing clip paths by popping wand */
926   if (ddata->clipping)
927     (void) PopDrawingWand(WmfDrawingWand);
928   ddata->clipping = MagickFalse;
929
930   /* Make SVG output happy */
931   (void) PopDrawingWand(WmfDrawingWand);
932 }
933
934 static void ipa_flood_interior(wmfAPI * API, wmfFlood_t * flood)
935 {
936   /* Save graphic wand */
937   (void) PushDrawingWand(WmfDrawingWand);
938
939   draw_fill_color_rgb(API,&(flood->color));
940
941   DrawColor(WmfDrawingWand,XC(flood->pt.x), YC(flood->pt.y),
942             FillToBorderMethod);
943
944   /* Restore graphic wand */
945   (void) PopDrawingWand(WmfDrawingWand);
946 }
947
948 static void ipa_flood_exterior(wmfAPI * API, wmfFlood_t * flood)
949 {
950   /* Save graphic wand */
951   (void) PushDrawingWand(WmfDrawingWand);
952
953   draw_fill_color_rgb(API,&(flood->color));
954
955   if (flood->type == FLOODFILLSURFACE)
956     DrawColor(WmfDrawingWand, XC(flood->pt.x), YC(flood->pt.y),
957               FloodfillMethod);
958   else
959     DrawColor(WmfDrawingWand, XC(flood->pt.x), YC(flood->pt.y),
960               FillToBorderMethod);
961
962   /* Restore graphic wand */
963   (void) PopDrawingWand(WmfDrawingWand);
964 }
965
966 static void ipa_draw_pixel(wmfAPI * API, wmfDrawPixel_t * draw_pixel)
967 {
968   /* Save graphic wand */
969   (void) PushDrawingWand(WmfDrawingWand);
970
971   draw_stroke_color_string(WmfDrawingWand,"none");
972
973   draw_fill_color_rgb(API,&(draw_pixel->color));
974
975   DrawRectangle(WmfDrawingWand,
976                  XC(draw_pixel->pt.x),
977                  YC(draw_pixel->pt.y),
978                  XC(draw_pixel->pt.x + draw_pixel->pixel_width),
979                  YC(draw_pixel->pt.y + draw_pixel->pixel_height));
980
981   /* Restore graphic wand */
982   (void) PopDrawingWand(WmfDrawingWand);
983 }
984
985 static void ipa_draw_pie(wmfAPI * API, wmfDrawArc_t * draw_arc)
986 {
987   util_draw_arc(API, draw_arc, magick_arc_pie);
988 }
989
990 static void ipa_draw_chord(wmfAPI * API, wmfDrawArc_t * draw_arc)
991 {
992   util_draw_arc(API, draw_arc, magick_arc_chord);
993 }
994
995 static void ipa_draw_arc(wmfAPI * API, wmfDrawArc_t * draw_arc)
996 {
997   util_draw_arc(API, draw_arc, magick_arc_open);
998 }
999
1000 static void ipa_draw_ellipse(wmfAPI * API, wmfDrawArc_t * draw_arc)
1001 {
1002   util_draw_arc(API, draw_arc, magick_arc_ellipse);
1003 }
1004
1005 static void util_draw_arc(wmfAPI * API,
1006           wmfDrawArc_t * draw_arc, magick_arc_t finish)
1007 {
1008   wmfD_Coord
1009     BR,
1010     O,
1011     TL,
1012     center,
1013     end,
1014     start;
1015
1016   double
1017     phi_e = 360,
1018     phi_s = 0;
1019
1020   double
1021     Rx,
1022     Ry;
1023
1024   /* Save graphic wand */
1025   (void) PushDrawingWand(WmfDrawingWand);
1026
1027   if (TO_FILL(draw_arc) || TO_DRAW(draw_arc))
1028     {
1029       center.x = (draw_arc->TL.x + draw_arc->BR.x) / 2;
1030       center.y = (draw_arc->TL.y + draw_arc->BR.y) / 2;
1031       start = center;
1032       end = center;
1033
1034       if (finish != magick_arc_ellipse)
1035         {
1036           draw_arc->start.x += center.x;
1037           draw_arc->start.y += center.y;
1038
1039           draw_arc->end.x += center.x;
1040           draw_arc->end.y += center.y;
1041         }
1042
1043       TL = draw_arc->TL;
1044       BR = draw_arc->BR;
1045
1046       O = center;
1047
1048       if (finish != magick_arc_ellipse)
1049         {
1050           start = draw_arc->start;
1051           end = draw_arc->end;
1052         }
1053
1054       Rx = (BR.x - TL.x) / 2;
1055       Ry = (BR.y - TL.y) / 2;
1056
1057       if (finish != magick_arc_ellipse)
1058         {
1059           start.x -= O.x;
1060           start.y -= O.y;
1061
1062           end.x -= O.x;
1063           end.y -= O.y;
1064
1065           phi_s = atan2((double) start.y, (double) start.x) * 180 / MagickPI;
1066           phi_e = atan2((double) end.y, (double) end.x) * 180 / MagickPI;
1067
1068           if (phi_e <= phi_s)
1069             phi_e += 360;
1070         }
1071
1072       util_set_pen(API, draw_arc->dc);
1073       if (finish == magick_arc_open)
1074         draw_fill_color_string(WmfDrawingWand,"none");
1075       else
1076         util_set_brush(API, draw_arc->dc, BrushApplyFill);
1077
1078       if (finish == magick_arc_ellipse)
1079         DrawEllipse(WmfDrawingWand, XC(O.x), YC(O.y), Rx, Ry, 0, 360);
1080       else if (finish == magick_arc_pie)
1081         {
1082           DrawPathStart(WmfDrawingWand);
1083           DrawPathMoveToAbsolute(WmfDrawingWand, XC(O.x+start.x),
1084             YC(O.y+start.y));
1085           DrawPathEllipticArcAbsolute(WmfDrawingWand, Rx, Ry, 0, MagickFalse,
1086             MagickTrue, XC(O.x+end.x), YC(O.y+end.y));
1087           DrawPathLineToAbsolute(WmfDrawingWand, XC(O.x), YC(O.y));
1088           DrawPathClose(WmfDrawingWand);
1089           DrawPathFinish(WmfDrawingWand);
1090         }
1091         else if (finish == magick_arc_chord)
1092         {
1093           DrawArc(WmfDrawingWand, XC(draw_arc->TL.x), YC(draw_arc->TL.y),
1094             XC(draw_arc->BR.x), XC(draw_arc->BR.y), phi_s, phi_e);
1095           DrawLine(WmfDrawingWand, XC(draw_arc->BR.x-start.x),
1096             YC(draw_arc->BR.y-start.y), XC(draw_arc->BR.x-end.x),
1097             YC(draw_arc->BR.y-end.y));
1098         }
1099         else      /* if (finish == magick_arc_open) */
1100           DrawArc(WmfDrawingWand, XC(draw_arc->TL.x), YC(draw_arc->TL.y),
1101             XC(draw_arc->BR.x), XC(draw_arc->BR.y), phi_s, phi_e);
1102     }
1103
1104   /* Restore graphic wand */
1105   (void) PopDrawingWand(WmfDrawingWand);
1106 }
1107
1108 static void ipa_draw_line(wmfAPI * API, wmfDrawLine_t * draw_line)
1109 {
1110   /* Save graphic wand */
1111   (void) PushDrawingWand(WmfDrawingWand);
1112
1113   if (TO_DRAW(draw_line))
1114     {
1115       util_set_pen(API, draw_line->dc);
1116       DrawLine(WmfDrawingWand,
1117                XC(draw_line->from.x), YC(draw_line->from.y),
1118                XC(draw_line->to.x), YC(draw_line->to.y));
1119     }
1120
1121   /* Restore graphic wand */
1122   (void) PopDrawingWand(WmfDrawingWand);
1123 }
1124
1125 static void ipa_poly_line(wmfAPI * API, wmfPolyLine_t * polyline)
1126 {
1127   if (polyline->count <= 2)
1128     return;
1129
1130   if (TO_DRAW(polyline))
1131     {
1132       int
1133         point;
1134
1135       /* Save graphic wand */
1136       (void) PushDrawingWand(WmfDrawingWand);
1137
1138       util_set_pen(API, polyline->dc);
1139
1140       DrawPathStart(WmfDrawingWand);
1141       DrawPathMoveToAbsolute(WmfDrawingWand,
1142                              XC(polyline->pt[0].x),
1143                              YC(polyline->pt[0].y));
1144       for (point = 1; point < polyline->count; point++)
1145         {
1146           DrawPathLineToAbsolute(WmfDrawingWand,
1147                                  XC(polyline->pt[point].x),
1148                                  YC(polyline->pt[point].y));
1149         }
1150       DrawPathFinish(WmfDrawingWand);
1151
1152       /* Restore graphic wand */
1153       (void) PopDrawingWand(WmfDrawingWand);
1154     }
1155 }
1156
1157 static void ipa_draw_polygon(wmfAPI * API, wmfPolyLine_t * polyline)
1158 {
1159   if (polyline->count <= 2)
1160     return;
1161
1162   if (TO_FILL(polyline) || TO_DRAW(polyline))
1163     {
1164       int
1165         point;
1166
1167       /* Save graphic wand */
1168       (void) PushDrawingWand(WmfDrawingWand);
1169
1170       util_set_pen(API, polyline->dc);
1171       util_set_brush(API, polyline->dc, BrushApplyFill);
1172
1173       DrawPathStart(WmfDrawingWand);
1174       DrawPathMoveToAbsolute(WmfDrawingWand,
1175                              XC(polyline->pt[0].x),
1176                              YC(polyline->pt[0].y));
1177       for (point = 1; point < polyline->count; point++)
1178         {
1179           DrawPathLineToAbsolute(WmfDrawingWand,
1180                                  XC(polyline->pt[point].x),
1181                                  YC(polyline->pt[point].y));
1182         }
1183       DrawPathClose(WmfDrawingWand);
1184       DrawPathFinish(WmfDrawingWand);
1185
1186       /* Restore graphic wand */
1187       (void) PopDrawingWand(WmfDrawingWand);
1188     }
1189 }
1190
1191 /* Draw a polypolygon.  A polypolygon is a list of polygons */
1192 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
1193 static void ipa_draw_polypolygon(wmfAPI * API, wmfPolyPoly_t* polypolygon)
1194 {
1195   if (TO_FILL(polypolygon) || TO_DRAW(polypolygon))
1196     {
1197       int
1198         polygon,
1199         point;
1200
1201       wmfPolyLine_t
1202         polyline;
1203
1204       /* Save graphic wand */
1205       (void) PushDrawingWand(WmfDrawingWand);
1206
1207       util_set_pen(API, polypolygon->dc);
1208       util_set_brush(API, polypolygon->dc, BrushApplyFill);
1209
1210       DrawPathStart(WmfDrawingWand);
1211       for (polygon = 0; polygon < polypolygon->npoly; polygon++)
1212         {
1213           polyline.dc = polypolygon->dc;
1214           polyline.pt = polypolygon->pt[polygon];
1215           polyline.count = polypolygon->count[polygon];
1216           if ((polyline.count > 2) && polyline.pt)
1217             {
1218               DrawPathMoveToAbsolute(WmfDrawingWand,
1219                                      XC(polyline.pt[0].x),
1220                                      YC(polyline.pt[0].y));
1221               for (point = 1; point < polyline.count; point++)
1222                 {
1223                   DrawPathLineToAbsolute(WmfDrawingWand,
1224                                          XC(polyline.pt[point].x),
1225                                          YC(polyline.pt[point].y));
1226                 }
1227               DrawPathClose(WmfDrawingWand);
1228             }
1229         }
1230       DrawPathFinish(WmfDrawingWand);
1231
1232       /* Restore graphic wand */
1233       (void) PopDrawingWand(WmfDrawingWand);
1234     }
1235 }
1236 #endif
1237
1238 static void ipa_draw_rectangle(wmfAPI * API, wmfDrawRectangle_t * draw_rect)
1239 {
1240   /* Save graphic wand */
1241   (void) PushDrawingWand(WmfDrawingWand);
1242
1243   if (TO_FILL(draw_rect) || TO_DRAW(draw_rect))
1244     {
1245       util_set_pen(API, draw_rect->dc);
1246       util_set_brush(API, draw_rect->dc, BrushApplyFill);
1247
1248       if ((draw_rect->width > 0) || (draw_rect->height > 0))
1249         DrawRoundRectangle(WmfDrawingWand,
1250                            XC(draw_rect->TL.x), YC(draw_rect->TL.y),
1251                            XC(draw_rect->BR.x), YC(draw_rect->BR.y),
1252                            draw_rect->width / 2, draw_rect->height / 2);
1253       else
1254         DrawRectangle(WmfDrawingWand,
1255                       XC(draw_rect->TL.x), YC(draw_rect->TL.y),
1256                       XC(draw_rect->BR.x), YC(draw_rect->BR.y));
1257     }
1258
1259   /* Restore graphic wand */
1260   (void) PopDrawingWand(WmfDrawingWand);
1261 }
1262
1263 /* Draw an un-filled rectangle using the current brush */
1264 static void ipa_region_frame(wmfAPI * API, wmfPolyRectangle_t * poly_rect)
1265 {
1266   /* Save graphic wand */
1267   (void) PushDrawingWand(WmfDrawingWand);
1268
1269   if (TO_FILL(poly_rect) || TO_DRAW(poly_rect))
1270     {
1271       long
1272         i;
1273
1274       draw_fill_color_string(WmfDrawingWand,"none");
1275       util_set_brush(API, poly_rect->dc, BrushApplyStroke);
1276
1277       for (i = 0; i < (long) poly_rect->count; i++)
1278         {
1279           DrawRectangle(WmfDrawingWand,
1280                          XC(poly_rect->TL[i].x), YC(poly_rect->TL[i].y),
1281                          XC(poly_rect->BR[i].x), YC(poly_rect->BR[i].y));
1282         }
1283     }
1284
1285   /* Restore graphic wand */
1286   (void) PopDrawingWand(WmfDrawingWand);
1287 }
1288
1289 static void ipa_region_paint(wmfAPI * API, wmfPolyRectangle_t * poly_rect)
1290 {
1291
1292   if (poly_rect->count == 0)
1293     return;
1294
1295   /* Save graphic wand */
1296   (void) PushDrawingWand(WmfDrawingWand);
1297
1298   if (TO_FILL (poly_rect))
1299     {
1300       long
1301         i;
1302
1303       draw_stroke_color_string(WmfDrawingWand,"none");
1304       util_set_brush(API, poly_rect->dc, BrushApplyFill);
1305
1306       for (i = 0; i < (long) poly_rect->count; i++)
1307         {
1308           DrawRectangle(WmfDrawingWand,
1309                          XC(poly_rect->TL[i].x), YC(poly_rect->TL[i].y),
1310                          XC(poly_rect->BR[i].x), YC(poly_rect->BR[i].y));
1311         }
1312     }
1313
1314   /* Restore graphic wand */
1315   (void) PopDrawingWand(WmfDrawingWand);
1316 }
1317
1318 static void ipa_region_clip(wmfAPI *API, wmfPolyRectangle_t *poly_rect)
1319 {
1320   long
1321     i;
1322
1323   wmf_magick_t
1324     *ddata = WMF_MAGICK_GetData (API);
1325
1326   /* Reset any existing clip paths by popping wand */
1327   if (ddata->clipping)
1328     (void) PopDrawingWand(WmfDrawingWand);
1329   ddata->clipping = MagickFalse;
1330
1331   if (poly_rect->count > 0)
1332     {
1333       char
1334         clip_mask_id[30];
1335
1336       /* Define clip path */
1337       ddata->clip_mask_id++;
1338       DrawPushDefs(WmfDrawingWand);
1339       (void) FormatLocaleString(clip_mask_id,MaxTextExtent,"clip_%lu",
1340         ddata->clip_mask_id);
1341       DrawPushClipPath(WmfDrawingWand,clip_mask_id);
1342       (void) PushDrawingWand(WmfDrawingWand);
1343       for (i = 0; i < (long) poly_rect->count; i++)
1344         {
1345           DrawRectangle(WmfDrawingWand,
1346                          XC(poly_rect->TL[i].x), YC(poly_rect->TL[i].y),
1347                          XC(poly_rect->BR[i].x), YC(poly_rect->BR[i].y));
1348         }
1349       (void) PopDrawingWand(WmfDrawingWand);
1350       DrawPopClipPath(WmfDrawingWand);
1351       DrawPopDefs(WmfDrawingWand);
1352
1353       /* Push wand for new clip paths */
1354       (void) PushDrawingWand(WmfDrawingWand);
1355       (void) DrawSetClipPath(WmfDrawingWand,clip_mask_id);
1356       ddata->clipping = MagickTrue;
1357     }
1358 }
1359
1360 static void ipa_functions(wmfAPI *API)
1361 {
1362   wmf_magick_t
1363     *ddata = 0;
1364
1365   wmfFunctionReference
1366     *FR = (wmfFunctionReference *) API->function_reference;
1367
1368   /*
1369      IPA function reference links
1370    */
1371   FR->device_open = ipa_device_open;
1372   FR->device_close = ipa_device_close;
1373   FR->device_begin = ipa_device_begin;
1374   FR->device_end = ipa_device_end;
1375   FR->flood_interior = ipa_flood_interior;
1376   FR->flood_exterior = ipa_flood_exterior;
1377   FR->draw_pixel = ipa_draw_pixel;
1378   FR->draw_pie = ipa_draw_pie;
1379   FR->draw_chord = ipa_draw_chord;
1380   FR->draw_arc = ipa_draw_arc;
1381   FR->draw_ellipse = ipa_draw_ellipse;
1382   FR->draw_line = ipa_draw_line;
1383   FR->poly_line = ipa_poly_line;
1384   FR->draw_polygon = ipa_draw_polygon;
1385 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
1386   FR->draw_polypolygon = ipa_draw_polypolygon;
1387 #endif
1388   FR->draw_rectangle = ipa_draw_rectangle;
1389   FR->rop_draw = ipa_rop_draw;
1390   FR->bmp_draw = ipa_bmp_draw;
1391   FR->bmp_read = ipa_bmp_read;
1392   FR->bmp_free = ipa_bmp_free;
1393   FR->draw_text = ipa_draw_text;
1394   FR->udata_init = ipa_udata_init;
1395   FR->udata_copy = ipa_udata_copy;
1396   FR->udata_set = ipa_udata_set;
1397   FR->udata_free = ipa_udata_free;
1398   FR->region_frame = ipa_region_frame;
1399   FR->region_paint = ipa_region_paint;
1400   FR->region_clip = ipa_region_clip;
1401
1402   /*
1403      Allocate device data structure
1404    */
1405   ddata = (wmf_magick_t *) wmf_malloc(API, sizeof(wmf_magick_t));
1406   if (ERR(API))
1407     return;
1408
1409   (void) ResetMagickMemory((void *) ddata, 0, sizeof(wmf_magick_t));
1410   API->device_data = (void *) ddata;
1411
1412   /*
1413      Device data defaults
1414    */
1415   ddata->image = 0;
1416 }
1417
1418 static void ipa_draw_text(wmfAPI * API, wmfDrawText_t * draw_text)
1419 {
1420   double
1421     angle = 0,      /* text rotation angle */
1422     bbox_height,    /* bounding box height */
1423     bbox_width,      /* bounding box width */
1424     pointsize = 0;    /* pointsize to output font with desired height */
1425
1426   ExceptionInfo
1427     *exception;
1428
1429   TypeMetric
1430     metrics;
1431
1432   wmfD_Coord
1433     BL,        /* bottom left of bounding box */
1434     BR,        /* bottom right of bounding box */
1435     TL,        /* top left of bounding box */
1436     TR;        /* top right of bounding box */
1437
1438   wmfD_Coord
1439     point;      /* text placement point */
1440
1441   wmfFont
1442     *font;
1443
1444   wmf_magick_t
1445     * ddata = WMF_MAGICK_GetData(API);
1446
1447   point = draw_text->pt;
1448
1449   /* Choose bounding box and calculate its width and height */
1450   {
1451     double dx,
1452       dy;
1453
1454     if ( draw_text->flags)
1455       {
1456         TL = draw_text->TL;
1457         BR = draw_text->BR;
1458         TR.x = draw_text->BR.x;
1459         TR.y = draw_text->TL.y;
1460         BL.x = draw_text->TL.x;
1461         BL.y = draw_text->BR.y;
1462       }
1463     else
1464       {
1465         TL = draw_text->bbox.TL;
1466         BR = draw_text->bbox.BR;
1467         TR = draw_text->bbox.TR;
1468         BL = draw_text->bbox.BL;
1469       }
1470     dx = ((TR.x - TL.x) + (BR.x - BL.x)) / 2;
1471     dy = ((TR.y - TL.y) + (BR.y - BL.y)) / 2;
1472     bbox_width = hypot(dx,dy);
1473     dx = ((BL.x - TL.x) + (BR.x - TR.x)) / 2;
1474     dy = ((BL.y - TL.y) + (BR.y - TR.y)) / 2;
1475     bbox_height = hypot(dx,dy);
1476   }
1477
1478   font = WMF_DC_FONT(draw_text->dc);
1479
1480   /* Convert font_height to equivalent pointsize */
1481   exception=ddata->exception;
1482   pointsize = util_pointsize( API, font, draw_text->str, draw_text->font_height, exception);
1483
1484   /* Save graphic wand */
1485   (void) PushDrawingWand(WmfDrawingWand);
1486
1487   (void) bbox_width;
1488   (void) bbox_height;
1489 #if 0
1490   printf("\nipa_draw_text\n");
1491   printf("Text                    = \"%s\"\n", draw_text->str);
1492   /* printf("WMF_FONT_NAME:          = \"%s\"\n", WMF_FONT_NAME(font)); */
1493   printf("WMF_FONT_PSNAME:        = \"%s\"\n", WMF_FONT_PSNAME(font));
1494   printf("Bounding box            TL=%g,%g BR=%g,%g\n",
1495          TL.x, TL.y, BR.x, BR.y );
1496   /* printf("Text box                = %gx%g\n", bbox_width, bbox_height); */
1497   /* printf("WMF_FONT_HEIGHT         = %i\n", (int)WMF_FONT_HEIGHT(font)); */
1498   printf("Pointsize               = %g\n", pointsize);
1499   fflush(stdout);
1500 #endif
1501
1502   /*
1503    * Obtain font metrics if required
1504    *
1505    */
1506   if ((WMF_DC_TEXTALIGN(draw_text->dc) & TA_CENTER) ||
1507       (WMF_TEXT_UNDERLINE(font)) || (WMF_TEXT_STRIKEOUT(font)))
1508     {
1509       Image
1510         *image = ddata->image;
1511
1512       DrawInfo
1513         *draw_info;
1514
1515       draw_info=ddata->draw_info;
1516       draw_info->font=WMF_FONT_PSNAME(font);
1517       draw_info->pointsize = pointsize;
1518       draw_info->text=draw_text->str;
1519
1520       if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
1521         {
1522           /* Center the text if it is not yet centered and should be */
1523           if ((WMF_DC_TEXTALIGN(draw_text->dc) & TA_CENTER))
1524             {
1525               double
1526                 text_width = metrics.width * (ddata->scale_y / ddata->scale_x);
1527
1528 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
1529               point.x -= text_width / 2;
1530 #else
1531               point.x += bbox_width / 2 - text_width / 2;
1532 #endif
1533             }
1534         }
1535       draw_info->font=NULL;
1536       draw_info->text=NULL;
1537     }
1538
1539   /* Set text background color */
1540   if (draw_text->flags & ETO_OPAQUE)
1541     {
1542       /* Draw bounding-box background color (META_EXTTEXTOUT mode) */
1543       draw_stroke_color_string(WmfDrawingWand,"none");
1544       draw_fill_color_rgb(API,WMF_DC_BACKGROUND(draw_text->dc));
1545       DrawRectangle(WmfDrawingWand,
1546                     XC(draw_text->TL.x),YC(draw_text->TL.y),
1547                     XC(draw_text->BR.x),YC(draw_text->BR.y));
1548       draw_fill_color_string(WmfDrawingWand,"none");
1549     }
1550   else
1551     {
1552       /* Set text undercolor */
1553       if (WMF_DC_OPAQUE(draw_text->dc))
1554         {
1555           wmfRGB
1556             *box = WMF_DC_BACKGROUND(draw_text->dc);
1557
1558           PixelWand
1559             *under_color;
1560
1561           under_color=NewPixelWand();
1562           PixelSetRedQuantum(under_color,ScaleCharToQuantum(box->r));
1563           PixelSetGreenQuantum(under_color,ScaleCharToQuantum(box->g));
1564           PixelSetBlueQuantum(under_color,ScaleCharToQuantum(box->b));
1565           PixelSetAlphaQuantum(under_color,OpaqueAlpha);
1566           DrawSetTextUnderColor(WmfDrawingWand,under_color);
1567           under_color=DestroyPixelWand(under_color);
1568         }
1569       else
1570         draw_under_color_string(WmfDrawingWand,"none");
1571     }
1572
1573   /* Set text clipping (META_EXTTEXTOUT mode) */
1574   if ( draw_text->flags & ETO_CLIPPED)
1575     {
1576     }
1577
1578   /* Set stroke color */
1579   draw_stroke_color_string(WmfDrawingWand,"none");
1580
1581   /* Set fill color */
1582   draw_fill_color_rgb(API,WMF_DC_TEXTCOLOR(draw_text->dc));
1583
1584   /* Output font size */
1585   (void) DrawSetFontSize(WmfDrawingWand,pointsize);
1586
1587   /* Output Postscript font name */
1588   (void) DrawSetFont(WmfDrawingWand, WMF_FONT_PSNAME(font));
1589
1590   /* Translate coordinates so target is 0,0 */
1591   DrawTranslate(WmfDrawingWand, XC(point.x), YC(point.y));
1592
1593   /* Transform horizontal scale to draw text at 1:1 ratio */
1594   DrawScale(WmfDrawingWand, ddata->scale_y / ddata->scale_x, 1.0);
1595
1596   /* Apply rotation */
1597   /* ImageMagick's drawing rotation is clockwise from horizontal
1598      while WMF drawing rotation is counterclockwise from horizontal */
1599   angle = fabs(RadiansToDegrees(2 * MagickPI - WMF_TEXT_ANGLE(font)));
1600   if (angle == 360)
1601     angle = 0;
1602   if (angle != 0)
1603     DrawRotate(WmfDrawingWand, angle);
1604
1605   /*
1606    * Render text
1607    *
1608    */
1609
1610   /* Output string */
1611   DrawAnnotation(WmfDrawingWand, 0, 0, (unsigned char*)draw_text->str);
1612
1613   /* Underline text the Windows way (at the bottom) */
1614   if (WMF_TEXT_UNDERLINE(font))
1615     {
1616       double
1617         line_height;
1618
1619       wmfD_Coord
1620         ulBR,      /* bottom right of underline rectangle */
1621         ulTL;      /* top left of underline rectangle */
1622
1623       line_height = ((double)1/(ddata->scale_x))*metrics.underline_thickness;
1624       if (metrics.underline_thickness < 1.5)
1625         line_height *= 0.55;
1626       ulTL.x = 0;
1627       ulTL.y = fabs(metrics.descent) - line_height;
1628       ulBR.x = metrics.width;
1629       ulBR.y = fabs(metrics.descent);
1630
1631       DrawRectangle(WmfDrawingWand,
1632                     XC(ulTL.x), YC(ulTL.y), XC(ulBR.x), YC(ulBR.y));
1633     }
1634
1635   /* Strikeout text the Windows way */
1636   if (WMF_TEXT_STRIKEOUT(font))
1637     {
1638       double line_height;
1639
1640       wmfD_Coord
1641         ulBR,      /* bottom right of strikeout rectangle */
1642         ulTL;      /* top left of strikeout rectangle */
1643
1644       line_height = ((double)1/(ddata->scale_x))*metrics.underline_thickness;
1645
1646       if (metrics.underline_thickness < 2.0)
1647         line_height *= 0.55;
1648       ulTL.x = 0;
1649       ulTL.y = -(((double) metrics.ascent) / 2 + line_height / 2);
1650       ulBR.x = metrics.width;
1651       ulBR.y = -(((double) metrics.ascent) / 2 - line_height / 2);
1652
1653       DrawRectangle(WmfDrawingWand,
1654                     XC(ulTL.x), YC(ulTL.y), XC(ulBR.x), YC(ulBR.y));
1655
1656     }
1657
1658   /* Restore graphic wand */
1659   (void) PopDrawingWand(WmfDrawingWand);
1660
1661 #if 0
1662   (void) PushDrawingWand(WmfDrawingWand);
1663   draw_stroke_color_string(WmfDrawingWand,"red");
1664   draw_fill_color_string(WmfDrawingWand,"none");
1665   DrawRectangle(WmfDrawingWand,
1666                 XC(TL.x), YC(TL.y),
1667                 XC(BR.x), YC(BR.y));
1668   draw_stroke_color_string(WmfDrawingWand,"none");
1669   (void) PopDrawingWand(WmfDrawingWand);
1670 #endif
1671
1672 }
1673
1674 static void ipa_udata_init(wmfAPI * API, wmfUserData_t * userdata)
1675 {
1676   (void) API;
1677   (void) userdata;
1678   /* wmf_magick_t* ddata = WMF_MAGICK_GetData (API); */
1679
1680 }
1681
1682 static void ipa_udata_copy(wmfAPI * API, wmfUserData_t * userdata)
1683 {
1684   (void) API;
1685   (void) userdata;
1686   /* wmf_magick_t* ddata = WMF_MAGICK_GetData (API); */
1687
1688 }
1689
1690 static void ipa_udata_set(wmfAPI * API, wmfUserData_t * userdata)
1691 {
1692   (void) API;
1693   (void) userdata;
1694   /* wmf_magick_t* ddata = WMF_MAGICK_GetData (API); */
1695
1696 }
1697
1698 static void ipa_udata_free(wmfAPI * API, wmfUserData_t * userdata)
1699 {
1700   (void) API;
1701   (void) userdata;
1702   /* wmf_magick_t* ddata = WMF_MAGICK_GetData (API); */
1703
1704 }
1705
1706 static inline double MagickMin(const double x,const double y)
1707 {
1708   if (x < y)
1709     return(x);
1710   return(y);
1711 }
1712
1713 static void util_set_brush(wmfAPI * API, wmfDC * dc, const BrushApply brush_apply)
1714 {
1715   wmf_magick_t
1716     *ddata = WMF_MAGICK_GetData(API);
1717
1718   wmfBrush
1719     *brush = WMF_DC_BRUSH(dc);
1720
1721   /* Set polygon fill rule */
1722   switch (WMF_DC_POLYFILL(dc))  /* Is this correct ?? */
1723     {
1724     case WINDING:
1725       DrawSetClipRule(WmfDrawingWand,NonZeroRule);
1726       break;
1727
1728     case ALTERNATE:
1729     default:
1730       DrawSetClipRule(WmfDrawingWand,EvenOddRule);
1731       break;
1732     }
1733
1734   switch (WMF_BRUSH_STYLE(brush))
1735     {
1736     case BS_SOLID /* 0 */:
1737       /* WMF_BRUSH_COLOR specifies brush color, WMF_BRUSH_HATCH
1738          ignored */
1739       {
1740         if ( brush_apply == BrushApplyStroke )
1741           draw_stroke_color_rgb(API,WMF_BRUSH_COLOR(brush));
1742         else
1743           draw_fill_color_rgb(API,WMF_BRUSH_COLOR(brush));
1744         break;
1745       }
1746     case BS_HOLLOW /* 1 */:    /* BS_HOLLOW & BS_NULL share enum */
1747       /* WMF_BRUSH_COLOR and WMF_BRUSH_HATCH ignored */
1748       {
1749         if ( brush_apply == BrushApplyStroke )
1750           draw_stroke_color_string(WmfDrawingWand,"none");
1751         else
1752           draw_fill_color_string(WmfDrawingWand,"none");
1753         break;
1754       }
1755     case BS_HATCHED /* 2 */:
1756       /* WMF_BRUSH_COLOR specifies the hatch color, WMF_BRUSH_HATCH
1757          specifies the hatch brush style. If WMF_DC_OPAQUE, then
1758          WMF_DC_BACKGROUND specifies hatch background color.  */
1759       {
1760         DrawPushDefs(WmfDrawingWand);
1761         draw_pattern_push(API, ddata->pattern_id, 8, 8);
1762         (void) PushDrawingWand(WmfDrawingWand);
1763
1764         if (WMF_DC_OPAQUE(dc))
1765           {
1766             if ( brush_apply == BrushApplyStroke )
1767               draw_stroke_color_rgb(API,WMF_DC_BACKGROUND(dc));
1768             else
1769               draw_fill_color_rgb(API,WMF_DC_BACKGROUND(dc));
1770
1771             DrawRectangle(WmfDrawingWand, 0, 0, 7, 7 );
1772           }
1773
1774         DrawSetStrokeAntialias(WmfDrawingWand, MagickFalse);
1775         DrawSetStrokeWidth(WmfDrawingWand, 1);
1776
1777         draw_stroke_color_rgb(API,WMF_BRUSH_COLOR(brush));
1778
1779         switch ((unsigned int) WMF_BRUSH_HATCH(brush))
1780           {
1781
1782           case HS_HORIZONTAL:  /* ----- */
1783             {
1784               DrawLine(WmfDrawingWand, 0, 3, 7,3);
1785               break;
1786             }
1787           case HS_VERTICAL:  /* ||||| */
1788             {
1789               DrawLine(WmfDrawingWand, 3, 0, 3, 7);
1790               break;
1791             }
1792           case HS_FDIAGONAL:  /* \\\\\ */
1793             {
1794               DrawLine(WmfDrawingWand, 0, 0, 7, 7);
1795               break;
1796             }
1797           case HS_BDIAGONAL:  /* / */
1798             {
1799               DrawLine(WmfDrawingWand, 0, 7, 7, 0 );
1800               break;
1801             }
1802           case HS_CROSS:  /* +++++ */
1803             {
1804               DrawLine(WmfDrawingWand, 0, 3, 7, 3 );
1805               DrawLine(WmfDrawingWand, 3, 0, 3, 7 );
1806               break;
1807             }
1808           case HS_DIAGCROSS:  /* xxxxx */
1809             {
1810               DrawLine(WmfDrawingWand, 0, 0, 7, 7 );
1811               DrawLine(WmfDrawingWand, 0, 7, 7, 0 );
1812               break;
1813             }
1814           default:
1815             {
1816               printf("util_set_brush: unexpected brush hatch enumeration %u\n",
1817                      (unsigned int)WMF_BRUSH_HATCH(brush));
1818             }
1819           }
1820         (void) PopDrawingWand(WmfDrawingWand);
1821         (void) DrawPopPattern(WmfDrawingWand);
1822         DrawPopDefs(WmfDrawingWand);
1823         {
1824           char
1825             pattern_id[30];
1826
1827           (void) FormatLocaleString(pattern_id,MaxTextExtent,"#brush_%lu",
1828             ddata->pattern_id);
1829           if (brush_apply == BrushApplyStroke )
1830             (void) DrawSetStrokePatternURL(WmfDrawingWand,pattern_id);
1831           else
1832             (void) DrawSetFillPatternURL(WmfDrawingWand,pattern_id);
1833           ++ddata->pattern_id;
1834         }
1835         break;
1836       }
1837     case BS_PATTERN /* 3 */:
1838       /* WMF_BRUSH_COLOR ignored, WMF_BRUSH_HATCH provides handle to
1839          bitmap */
1840       {
1841         printf("util_set_brush: BS_PATTERN not supported\n");
1842         break;
1843       }
1844     case BS_INDEXED /* 4 */:
1845       {
1846         printf("util_set_brush: BS_INDEXED not supported\n");
1847         break;
1848       }
1849     case BS_DIBPATTERN /* 5 */:
1850       {
1851         wmfBMP
1852           *brush_bmp = WMF_BRUSH_BITMAP(brush);
1853
1854         if (brush_bmp && brush_bmp->data != 0)
1855           {
1856             CompositeOperator
1857               mode;
1858
1859             const Image
1860               *image;
1861
1862             ExceptionInfo
1863               exception;
1864
1865             MagickWand
1866               *magick_wand;
1867
1868             GetExceptionInfo(&exception);
1869
1870             image = (Image*)brush_bmp->data;
1871
1872             mode = CopyCompositeOp;  /* Default is copy */
1873             switch (WMF_DC_ROP(dc))
1874               {
1875                 /* Binary raster ops */
1876               case R2_BLACK:
1877                 printf("util_set_brush: R2_BLACK ROP2 mode not supported!\n");
1878                 break;
1879               case R2_NOTMERGEPEN:
1880                 printf("util_set_brush: R2_NOTMERGEPEN ROP2 mode not supported!\n");
1881                 break;
1882               case R2_MASKNOTPEN:
1883                 printf("util_set_brush R2_MASKNOTPEN ROP2 mode not supported!\n");
1884                 break;
1885               case R2_NOTCOPYPEN:
1886                 printf("util_set_brush: R2_NOTCOPYPEN ROP2 mode not supported!\n");
1887                 break;
1888               case R2_MASKPENNOT:
1889                 printf("util_set_brush: R2_MASKPENNOT ROP2 mode not supported!\n");
1890                 break;
1891               case R2_NOT:
1892                 printf("util_set_brush: R2_NOT ROP2 mode not supported!\n");
1893                 break;
1894               case R2_XORPEN:
1895                 printf("util_set_brush: R2_XORPEN ROP2 mode not supported!\n");
1896                 break;
1897               case R2_NOTMASKPEN:
1898                 printf("util_set_brush: R2_NOTMASKPEN ROP2 mode not supported!\n");
1899                 break;
1900               case R2_MASKPEN:
1901                 printf("util_set_brush: R2_MASKPEN ROP2 mode not supported!\n");
1902                 break;
1903               case R2_NOTXORPEN:
1904                 printf("util_set_brush: R2_NOTXORPEN ROP2 mode not supported!\n");
1905                 break;
1906               case R2_NOP:
1907                 printf("util_set_brush: R2_NOP ROP2 mode not supported!\n");
1908                 break;
1909               case R2_MERGENOTPEN:
1910                 printf("util_set_brush: R2_MERGENOTPEN ROP2 mode not supported!\n");
1911                 break;
1912               case R2_COPYPEN:
1913                 mode = CopyCompositeOp;
1914                 break;
1915               case R2_MERGEPENNOT:
1916                 printf("util_set_brush: R2_MERGEPENNOT ROP2 mode not supported!\n");
1917                 break;
1918               case R2_MERGEPEN:
1919                 printf("util_set_brush: R2_MERGEPEN ROP2 mode not supported!\n");
1920                 break;
1921               case R2_WHITE:
1922                 printf("util_set_brush: R2_WHITE ROP2 mode not supported!\n");
1923                 break;
1924               default:
1925                 {
1926                   printf("util_set_brush: unexpected ROP2 enumeration %u!\n",
1927                          (unsigned int)WMF_DC_ROP(dc));
1928                 }
1929               }
1930
1931             DrawPushDefs(WmfDrawingWand);
1932             draw_pattern_push(API, ddata->pattern_id, brush_bmp->width,
1933               brush_bmp->height);
1934             magick_wand=NewMagickWandFromImage(image);
1935             (void) DrawComposite(WmfDrawingWand,mode, 0, 0, brush_bmp->width,
1936               brush_bmp->height, magick_wand);
1937             magick_wand=DestroyMagickWand(magick_wand);
1938             (void) DrawPopPattern(WmfDrawingWand);
1939             DrawPopDefs(WmfDrawingWand);
1940
1941             {
1942               char
1943                 pattern_id[30];
1944
1945               (void) FormatLocaleString(pattern_id,MaxTextExtent,"#brush_%lu",
1946                 ddata->pattern_id);
1947               if ( brush_apply == BrushApplyStroke )
1948                 (void) DrawSetStrokePatternURL(WmfDrawingWand,pattern_id);
1949               else
1950                 (void) DrawSetFillPatternURL(WmfDrawingWand,pattern_id);
1951               ++ddata->pattern_id;
1952             }
1953           }
1954         else
1955           printf("util_set_brush: no BMP image data!\n");
1956
1957         break;
1958       }
1959     case BS_DIBPATTERNPT /* 6 */:
1960       /* WMF_BRUSH_COLOR ignored, WMF_BRUSH_HATCH provides pointer to
1961          DIB */
1962       {
1963         printf("util_set_brush: BS_DIBPATTERNPT not supported\n");
1964         break;
1965       }
1966     case BS_PATTERN8X8 /* 7 */:
1967       {
1968         printf("util_set_brush: BS_PATTERN8X8 not supported\n");
1969         break;
1970       }
1971     case BS_DIBPATTERN8X8 /* 8 */:
1972       {
1973         printf("util_set_brush: BS_DIBPATTERN8X8 not supported\n");
1974         break;
1975       }
1976     default:
1977       {
1978       }
1979     }
1980 }
1981
1982 static inline double MagickMax(const double x,const double y)
1983 {
1984   if (x > y)
1985     return(x);
1986   return(y);
1987 }
1988
1989 static void util_set_pen(wmfAPI * API, wmfDC * dc)
1990 {
1991   wmf_magick_t
1992     *ddata = WMF_MAGICK_GetData(API);
1993
1994   wmfPen
1995     *pen = 0;
1996
1997   double
1998     pen_width,
1999     pixel_width;
2000
2001   unsigned int
2002     pen_style,
2003     pen_type;
2004
2005   pen = WMF_DC_PEN(dc);
2006
2007   pen_width = (WMF_PEN_WIDTH(pen) + WMF_PEN_HEIGHT(pen)) / 2;
2008
2009   /* Pixel width is inverse of pixel scale */
2010   pixel_width = (((double) 1 / (ddata->scale_x)) +
2011                  ((double) 1 / (ddata->scale_y))) / 2;
2012
2013   /* Don't allow pen_width to be much less than pixel_width in order
2014      to avoid dissapearing or spider-web lines */
2015   pen_width = MagickMax(pen_width, pixel_width*0.8);
2016
2017   pen_style = (unsigned int) WMF_PEN_STYLE(pen);
2018   pen_type = (unsigned int) WMF_PEN_TYPE(pen);
2019   (void) pen_type;
2020
2021   /* Pen style specified? */
2022   if (pen_style == PS_NULL)
2023     {
2024       draw_stroke_color_string(WmfDrawingWand,"none");
2025       return;
2026     }
2027
2028   DrawSetStrokeAntialias(WmfDrawingWand, MagickTrue );
2029   DrawSetStrokeWidth(WmfDrawingWand, (unsigned long) MagickMax(0.0, pen_width));
2030
2031   {
2032     LineCap
2033       linecap;
2034
2035     switch ((unsigned int) WMF_PEN_ENDCAP(pen))
2036       {
2037       case PS_ENDCAP_SQUARE:
2038         linecap = SquareCap;
2039         break;
2040       case PS_ENDCAP_ROUND:
2041         linecap = RoundCap;
2042         break;
2043       case PS_ENDCAP_FLAT:
2044       default:
2045         linecap = ButtCap;
2046         break;
2047       }
2048     DrawSetStrokeLineCap(WmfDrawingWand, linecap);
2049   }
2050
2051   {
2052     LineJoin
2053       linejoin;
2054
2055     switch ((unsigned int) WMF_PEN_JOIN(pen))
2056       {
2057       case PS_JOIN_BEVEL:
2058         linejoin = BevelJoin;
2059         break;
2060       case PS_JOIN_ROUND:
2061         linejoin = RoundJoin;
2062         break;
2063       case PS_JOIN_MITER:
2064       default:
2065         linejoin = MiterJoin;
2066         break;
2067       }
2068     DrawSetStrokeLineJoin(WmfDrawingWand,linejoin);
2069   }
2070
2071   {
2072     double
2073       dasharray[7];
2074
2075     switch (pen_style)
2076       {
2077       case PS_DASH:    /* -------  */
2078         {
2079           /* Pattern 18,7 */
2080           dasharray[0] = pixel_width * 18;
2081           dasharray[1] = pixel_width * 7;
2082           dasharray[2] = 0;
2083
2084           DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
2085           (void) DrawSetStrokeDashArray(WmfDrawingWand,2,dasharray);
2086           break;
2087         }
2088       case PS_ALTERNATE:
2089       case PS_DOT:    /* .......  */
2090         {
2091           /* Pattern 3,3 */
2092           dasharray[0] = pixel_width * 3;
2093           dasharray[1] = pixel_width * 3;
2094           dasharray[2] = 0;
2095
2096           DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
2097           (void) DrawSetStrokeDashArray(WmfDrawingWand,2,dasharray);
2098           break;
2099         }
2100       case PS_DASHDOT:    /* _._._._  */
2101         {
2102           /* Pattern 9,6,3,6 */
2103           dasharray[0] = pixel_width * 9;
2104           dasharray[1] = pixel_width * 6;
2105           dasharray[2] = pixel_width * 3;
2106           dasharray[3] = pixel_width * 6;
2107           dasharray[4] = 0;
2108
2109           DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
2110           (void) DrawSetStrokeDashArray(WmfDrawingWand,4,dasharray);
2111           break;
2112         }
2113       case PS_DASHDOTDOT:  /* _.._.._  */
2114         {
2115           /* Pattern 9,3,3,3,3,3 */
2116           dasharray[0] = pixel_width * 9;
2117           dasharray[1] = pixel_width * 3;
2118           dasharray[2] = pixel_width * 3;
2119           dasharray[3] = pixel_width * 3;
2120           dasharray[4] = pixel_width * 3;
2121           dasharray[5] = pixel_width * 3;
2122           dasharray[6] = 0;
2123
2124           DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
2125           (void) DrawSetStrokeDashArray(WmfDrawingWand,6,dasharray);
2126           break;
2127         }
2128       case PS_INSIDEFRAME:  /* There is nothing to do in this case... */
2129       case PS_SOLID:
2130       default:
2131         {
2132           (void) DrawSetStrokeDashArray(WmfDrawingWand,0,(double *)NULL);
2133           break;
2134         }
2135       }
2136   }
2137
2138   draw_stroke_color_rgb(API,WMF_PEN_COLOR(pen));
2139 }
2140
2141 /* Estimate font pointsize based on Windows font parameters */
2142 static double util_pointsize( wmfAPI* API, wmfFont* font, char* str, double font_height, ExceptionInfo *exception)
2143 {
2144   wmf_magick_t
2145     *ddata = WMF_MAGICK_GetData(API);
2146
2147   Image
2148     *image = ddata->image;
2149
2150   TypeMetric
2151     metrics;
2152
2153   DrawInfo
2154     *draw_info;
2155
2156   double
2157     pointsize = 0;
2158
2159   draw_info=ddata->draw_info;
2160   if (draw_info == (const DrawInfo *) NULL)
2161     return 0;
2162
2163   draw_info->font=WMF_FONT_PSNAME(font);
2164   draw_info->pointsize=font_height;
2165   draw_info->text=str;
2166
2167   if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
2168     {
2169
2170       if (strlen(str) == 1)
2171         {
2172           pointsize = (font_height *
2173                        ( font_height / (metrics.ascent + fabs(metrics.descent))));
2174           draw_info->pointsize = pointsize;
2175           if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
2176             pointsize *= (font_height / ( metrics.ascent + fabs(metrics.descent)));
2177         }
2178       else
2179         {
2180           pointsize = (font_height * (font_height / (metrics.height)));
2181           draw_info->pointsize = pointsize;
2182           if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
2183             pointsize *= (font_height / metrics.height);
2184
2185         }
2186 #if 0
2187       draw_info.pointsize = pointsize;
2188       if (GetTypeMetrics(image, &draw_info, &metrics, exception) != MagickFalse)
2189         pointsize *= (font_height / (metrics.ascent + fabs(metrics.descent)));
2190       pointsize *= 1.114286; /* Magic number computed through trial and error */
2191 #endif
2192     }
2193
2194   draw_info->font=NULL;
2195   draw_info->text=NULL;
2196 #if 0
2197   printf("String    = %s\n", str);
2198   printf("Font      = %s\n", WMF_FONT_PSNAME(font));
2199   printf("lfHeight  = %g\n", font_height);
2200   printf("bounds    = %g,%g %g,%g\n", metrics.bounds.x1, metrics.bounds.y1,
2201          metrics.bounds.x2,metrics.bounds.y2);
2202   printf("ascent    = %g\n", metrics.ascent);
2203   printf("descent   = %g\n", metrics.descent);
2204   printf("height    = %g\n", metrics.height);
2205   printf("Pointsize = %g\n", pointsize);
2206 #endif
2207
2208   return floor(pointsize);
2209 }
2210
2211 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
2212 /* Estimate weight based on font name */
2213 /*
2214 static int util_font_weight( const char* font )
2215 {
2216   int
2217     weight;
2218
2219   weight = 400;
2220   if ((strstr(font,"Normal") || strstr(font,"Regular")))
2221     weight = 400;
2222   else if ( strstr(font,"Bold") )
2223     {
2224       weight = 700;
2225       if ((strstr(font,"Semi") || strstr(font,"Demi")))
2226         weight = 600;
2227       if ( (strstr(font,"Extra") || strstr(font,"Ultra")))
2228         weight = 800;
2229     }
2230   else if ( strstr(font,"Light") )
2231     {
2232       weight = 300;
2233       if ( (strstr(font,"Extra") || strstr(font,"Ultra")))
2234         weight = 200;
2235     }
2236   else if ((strstr(font,"Heavy") || strstr(font,"Black")))
2237     weight = 900;
2238   else if ( strstr(font,"Thin") )
2239     weight = 100;
2240   return weight;
2241 }
2242 */
2243
2244 /*
2245  * Returns width of string in points, assuming (unstretched) font size of 1pt
2246  * (similar to wmf_ipa_font_stringwidth)
2247  *
2248  * This extremely odd at best, particularly since player/meta.h has access
2249  * to the corrected font_height (as drawtext.font_height) when it invokes the
2250  * stringwidth callback.  It should be possible to compute the real stringwidth!
2251  */
2252 static float lite_font_stringwidth( wmfAPI* API, wmfFont* font, char* str)
2253 {
2254 #if 0
2255   wmf_magick_t
2256     *ddata = WMF_MAGICK_GetData(API);
2257
2258   Image
2259     *image = ddata->image;
2260
2261   DrawInfo
2262     *draw_info;
2263
2264   ExceptionInfo
2265     *exception;
2266
2267   TypeMetric
2268     metrics;
2269
2270   float
2271     stringwidth = 0;
2272
2273   double
2274     orig_x_resolution,
2275     orig_y_resolution;
2276
2277   ResolutionType
2278     orig_resolution_units;
2279
2280   orig_x_resolution = image->resolution.x;
2281   orig_y_resolution = image->resolution.y;
2282   orig_resolution_units = image->units;
2283
2284   draw_info=ddata->draw_info;
2285   if (draw_info == (const DrawInfo *) NULL)
2286     return 0;
2287
2288   draw_info->font=WMF_FONT_PSNAME(font);
2289   draw_info->pointsize=12;
2290   draw_info->text=str;
2291
2292   image->resolution.x = 72;
2293   image->resolution.y = 72;
2294   image->units = PixelsPerInchResolution;
2295
2296   exception=ddata->exception;
2297   if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
2298     stringwidth = ((metrics.width * 72)/(image->resolution.x * draw_info->pointsize)); /* *0.916348; */
2299
2300   draw_info->font=NULL;
2301   draw_info->text=NULL;
2302
2303 #if 0
2304   printf("\nlite_font_stringwidth\n");
2305   printf("string                  = \"%s\"\n", str);
2306   printf("WMF_FONT_NAME           = \"%s\"\n", WMF_FONT_NAME(font));
2307   printf("WMF_FONT_PSNAME         = \"%s\"\n", WMF_FONT_PSNAME(font));
2308   printf("stringwidth             = %g\n", stringwidth);
2309   /* printf("WMF_FONT_HEIGHT         = %i\n", (int)WMF_FONT_HEIGHT(font)); */
2310   /* printf("WMF_FONT_WIDTH          = %i\n", (int)WMF_FONT_WIDTH(font)); */
2311   fflush(stdout);
2312 #endif
2313
2314   image->resolution.x = orig_x_resolution;
2315   image->resolution.y = orig_y_resolution;
2316   image->units = orig_resolution_units;
2317
2318   return stringwidth;
2319 #else
2320   (void) API;
2321   (void) font;
2322   (void) str;
2323
2324   return 0;
2325 #endif
2326 }
2327
2328 /* Map font (similar to wmf_ipa_font_map) */
2329
2330 /* Mappings to Postscript fonts: family, normal, italic, bold, bolditalic */
2331 static wmfFontMap WMFFontMap[] = {
2332   { (char *) "Courier",            (char *) "Courier",
2333     (char *) "Courier-Oblique",    (char *) "Courier-Bold",
2334     (char *) "Courier-BoldOblique"   },
2335   { (char *) "Helvetica",          (char *) "Helvetica",
2336     (char *) "Helvetica-Oblique",  (char *) "Helvetica-Bold",
2337     (char *) "Helvetica-BoldOblique" },
2338   { (char *) "Modern",             (char *) "Courier",
2339     (char *) "Courier-Oblique",    (char *) "Courier-Bold",
2340     (char *) "Courier-BoldOblique"   },
2341   { (char *) "Monotype Corsiva",   (char *) "Courier",
2342     (char *) "Courier-Oblique",    (char *) "Courier-Bold",
2343     (char *) "Courier-BoldOblique"   },
2344   { (char *) "News Gothic",        (char *) "Helvetica",
2345     (char *) "Helvetica-Oblique",  (char *) "Helvetica-Bold",
2346     (char *) "Helvetica-BoldOblique" },
2347   { (char *) "Symbol",             (char *) "Symbol",
2348     (char *) "Symbol",             (char *) "Symbol",
2349     (char *) "Symbol"                },
2350   { (char *) "System",             (char *) "Courier",
2351     (char *) "Courier-Oblique",    (char *) "Courier-Bold",
2352     (char *) "Courier-BoldOblique"   },
2353   { (char *) "Times",              (char *) "Times-Roman",
2354     (char *) "Times-Italic",       (char *) "Times-Bold",
2355     (char *) "Times-BoldItalic"      },
2356   { (char *) NULL,                 (char *) NULL,
2357     (char *) NULL,                 (char *) NULL,
2358     (char *) NULL                   }
2359 };
2360
2361
2362 /* Mapping between base name and Ghostscript family name */
2363 static wmfMapping SubFontMap[] =
2364 {
2365   { (char *) "Arial", (char *) "Helvetica", FT_ENCODING_NONE },
2366   { (char *) "Courier", (char *) "Courier", FT_ENCODING_NONE },
2367   { (char *) "Fixed", (char *) "Courier", FT_ENCODING_NONE },
2368   { (char *) "Helvetica", (char *) "Helvetica", FT_ENCODING_NONE },
2369   { (char *) "Sans", (char *) "Helvetica", FT_ENCODING_NONE },
2370   { (char *) "Sym", (char *) "Symbol", FT_ENCODING_NONE },
2371   { (char *) "Terminal", (char *) "Courier", FT_ENCODING_NONE },
2372   { (char *) "Times", (char *) "Times", FT_ENCODING_NONE },
2373   { (char *) "Wingdings", (char *) "Symbol", FT_ENCODING_NONE },
2374   { (char *)  NULL, (char *) NULL, FT_ENCODING_NONE }
2375 };
2376
2377 static void lite_font_map( wmfAPI* API, wmfFont* font)
2378 {
2379   wmfFontData
2380     *font_data;
2381
2382   wmf_magick_font_t
2383     *magick_font;
2384
2385   wmf_magick_t
2386     *ddata = WMF_MAGICK_GetData(API);
2387
2388   ExceptionInfo
2389     *exception;
2390
2391   const TypeInfo
2392     *type_info,
2393     *type_info_base;
2394
2395   const char
2396     *wmf_font_name;
2397
2398   if (font == 0)
2399     return;
2400
2401   font_data = (wmfFontData*)API->font_data;
2402   font->user_data = font_data->user_data;
2403   magick_font = (wmf_magick_font_t*)font->user_data;
2404   wmf_font_name = WMF_FONT_NAME(font);
2405
2406   if (magick_font->ps_name != (char *) NULL)
2407     magick_font->ps_name=DestroyString(magick_font->ps_name);
2408
2409   exception=ddata->exception;
2410   type_info_base=GetTypeInfo("*",exception);
2411   if (type_info_base == 0)
2412      return;
2413
2414   /* Certain short-hand font names are not the proper Windows names
2415      and should be promoted to the proper names */
2416   if (LocaleCompare(wmf_font_name,"Times") == 0)
2417     wmf_font_name = "Times New Roman";
2418   else if (LocaleCompare(wmf_font_name,"Courier") == 0)
2419     wmf_font_name = "Courier New";
2420
2421   /* Look for a family-based best-match */
2422   if (!magick_font->ps_name)
2423     {
2424       int
2425         target_weight;
2426
2427       if (WMF_FONT_WEIGHT(font) == 0)
2428         target_weight = 400;
2429       else
2430         target_weight = WMF_FONT_WEIGHT(font);
2431       type_info=GetTypeInfoByFamily(wmf_font_name,AnyStyle,AnyStretch,
2432         target_weight,exception);
2433       if (type_info == (const TypeInfo *) NULL)
2434         type_info=GetTypeInfoByFamily(wmf_font_name,AnyStyle,AnyStretch,0,
2435           exception);
2436       if (type_info != (const TypeInfo *) NULL)
2437         CloneString(&magick_font->ps_name,type_info->name);
2438     }
2439
2440   /* Now let's try simple substitution mappings from WMFFontMap */
2441   if (!magick_font->ps_name)
2442     {
2443       char
2444         target[MaxTextExtent];
2445
2446       int
2447         target_weight = 400,
2448         want_italic = MagickFalse,
2449         want_bold = MagickFalse,
2450         i;
2451
2452       if ( WMF_FONT_WEIGHT(font) != 0 )
2453         target_weight = WMF_FONT_WEIGHT(font);
2454
2455       if ( (target_weight > 550) || ((strstr(wmf_font_name,"Bold") ||
2456                                      strstr(wmf_font_name,"Heavy") ||
2457                                      strstr(wmf_font_name,"Black"))) )
2458         want_bold = MagickTrue;
2459
2460       if ( (WMF_FONT_ITALIC(font)) || ((strstr(wmf_font_name,"Italic") ||
2461                                        strstr(wmf_font_name,"Oblique"))) )
2462         want_italic = MagickTrue;
2463
2464       (void) CopyMagickString(target,"Times",MaxTextExtent);
2465       for( i=0; SubFontMap[i].name != NULL; i++ )
2466         {
2467           if (LocaleCompare(wmf_font_name, SubFontMap[i].name) == 0)
2468             {
2469               (void) CopyMagickString(target,SubFontMap[i].mapping,
2470                 MaxTextExtent);
2471               break;
2472             }
2473         }
2474
2475       for( i=0; WMFFontMap[i].name != NULL; i++ )
2476         {
2477           if (LocaleNCompare(WMFFontMap[i].name,target,strlen(WMFFontMap[i].name)) == 0)
2478             {
2479               if (want_bold && want_italic)
2480                 CloneString(&magick_font->ps_name,WMFFontMap[i].bolditalic);
2481               else if (want_italic)
2482                 CloneString(&magick_font->ps_name,WMFFontMap[i].italic);
2483               else if (want_bold)
2484                 CloneString(&magick_font->ps_name,WMFFontMap[i].bold);
2485               else
2486                 CloneString(&magick_font->ps_name,WMFFontMap[i].normal);
2487             }
2488         }
2489     }
2490
2491 #if 0
2492   printf("\nlite_font_map\n");
2493   printf("WMF_FONT_NAME           = \"%s\"\n", WMF_FONT_NAME(font));
2494   printf("WMF_FONT_WEIGHT         = %i\n",  WMF_FONT_WEIGHT(font));
2495   printf("WMF_FONT_PSNAME         = \"%s\"\n", WMF_FONT_PSNAME(font));
2496   fflush(stdout);
2497 #endif
2498
2499 }
2500
2501 /* Initialize API font structures */
2502 static void lite_font_init( wmfAPI* API, wmfAPI_Options* options)
2503 {
2504   wmfFontData
2505     *font_data;
2506
2507   (void) options;
2508   API->fonts = 0;
2509
2510   /* Allocate wmfFontData data structure */
2511   API->font_data = wmf_malloc(API,sizeof(wmfFontData));
2512   if (ERR (API))
2513     return;
2514
2515   font_data = (wmfFontData*)API->font_data;
2516
2517   /* Assign function to map font (type wmfMap) */
2518   font_data->map = lite_font_map;
2519
2520   /* Assign function to return string width in points (type wmfStringWidth) */
2521   font_data->stringwidth = lite_font_stringwidth;
2522
2523   /* Assign user data, not used by libwmflite (type void*) */
2524   font_data->user_data = wmf_malloc(API,sizeof(wmf_magick_font_t));
2525   if (ERR(API))
2526     return;
2527   ((wmf_magick_font_t*)font_data->user_data)->ps_name = 0;
2528   ((wmf_magick_font_t*)font_data->user_data)->pointsize = 0;
2529 }
2530
2531 #endif /* MAGICKCORE_WMFLITE_DELEGATE */
2532
2533 /* BLOB read byte */
2534 static int ipa_blob_read(void* wand)
2535 {
2536   return ReadBlobByte((Image*)wand);
2537 }
2538
2539 /* BLOB seek */
2540 static int ipa_blob_seek(void* wand,long position)
2541 {
2542   return (int)SeekBlob((Image*)wand,(MagickOffsetType) position,SEEK_SET);
2543 }
2544
2545 /* BLOB tell */
2546 static long ipa_blob_tell(void* wand)
2547 {
2548   return (long)TellBlob((Image*)wand);
2549 }
2550
2551 static Image *ReadWMFImage(const ImageInfo *image_info,ExceptionInfo *exception)
2552 {
2553   double
2554     bounding_height,
2555     bounding_width,
2556     image_height,
2557     image_height_inch,
2558     image_width,
2559     image_width_inch,
2560     resolution_y,
2561     resolution_x,
2562     units_per_inch;
2563
2564   float
2565     wmf_width,
2566     wmf_height;
2567
2568   Image
2569     *image;
2570
2571   unsigned long
2572     wmf_options_flags = 0;
2573
2574   wmf_error_t
2575     wmf_error;
2576
2577   wmf_magick_t
2578     *ddata = 0;
2579
2580   wmfAPI
2581     *API = 0;
2582
2583   wmfAPI_Options
2584     wmf_api_options;
2585
2586   wmfD_Rect
2587     bbox;
2588
2589   image=AcquireImage(image_info,exception);
2590   if (OpenBlob(image_info,image,ReadBinaryBlobMode,exception) == MagickFalse)
2591     {
2592       if (image->debug != MagickFalse)
2593         {
2594           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2595             "  OpenBlob failed");
2596           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2597             "leave ReadWMFImage()");
2598         }
2599       image=DestroyImageList(image);
2600       return((Image *) NULL);
2601     }
2602
2603   /*
2604    * Create WMF API
2605    *
2606    */
2607
2608   /* Register callbacks */
2609   wmf_options_flags |= WMF_OPT_FUNCTION;
2610   (void) ResetMagickMemory(&wmf_api_options, 0, sizeof(wmf_api_options));
2611   wmf_api_options.function = ipa_functions;
2612
2613   /* Ignore non-fatal errors */
2614   wmf_options_flags |= WMF_OPT_IGNORE_NONFATAL;
2615
2616   wmf_error = wmf_api_create(&API, wmf_options_flags, &wmf_api_options);
2617   if (wmf_error != wmf_E_None)
2618     {
2619       if (API)
2620         wmf_api_destroy(API);
2621       if (image->debug != MagickFalse)
2622         {
2623           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2624             "  wmf_api_create failed");
2625           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2626             "leave ReadWMFImage()");
2627         }
2628       ThrowReaderException(DelegateError,"UnableToInitializeWMFLibrary");
2629     }
2630
2631   /* Register progress monitor */
2632   wmf_status_function(API,image,magick_progress_callback);
2633
2634   ddata=WMF_MAGICK_GetData(API);
2635   ddata->image=image;
2636   ddata->image_info=image_info;
2637   ddata->draw_info=CloneDrawInfo(image_info,(const DrawInfo *) NULL);
2638   ddata->exception=exception;
2639   ddata->draw_info->font=(char *)
2640     RelinquishMagickMemory(ddata->draw_info->font);
2641   ddata->draw_info->text=(char *)
2642     RelinquishMagickMemory(ddata->draw_info->text);
2643
2644 #if defined(MAGICKCORE_WMFLITE_DELEGATE)
2645   /* Must initialize font subystem for WMFlite interface */
2646   lite_font_init (API,&wmf_api_options); /* similar to wmf_ipa_font_init in src/font.c */
2647   /* wmf_arg_fontdirs (API,options); */ /* similar to wmf_arg_fontdirs in src/wmf.c */
2648
2649 #endif
2650
2651   /*
2652    * Open BLOB input via libwmf API
2653    *
2654    */
2655   wmf_error = wmf_bbuf_input(API,ipa_blob_read,ipa_blob_seek,
2656     ipa_blob_tell,(void*)image);
2657   if (wmf_error != wmf_E_None)
2658     {
2659       wmf_api_destroy(API);
2660       if (image->debug != MagickFalse)
2661         {
2662           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2663             "  wmf_bbuf_input failed");
2664           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2665             "leave ReadWMFImage()");
2666         }
2667       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
2668         image->filename);
2669       image=DestroyImageList(image);
2670       return((Image *) NULL);
2671     }
2672
2673   /*
2674    * Scan WMF file
2675    *
2676    */
2677   if (image->debug != MagickFalse)
2678     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2679       "  Scanning WMF to obtain bounding box");
2680   wmf_error=wmf_scan(API, 0, &bbox);
2681   if (wmf_error != wmf_E_None)
2682     {
2683       wmf_api_destroy(API);
2684       if (image->debug != MagickFalse)
2685         {
2686           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2687             "  wmf_scan failed with wmf_error %d", wmf_error);
2688           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2689             "leave ReadWMFImage()");
2690         }
2691       ThrowReaderException(DelegateError,"FailedToScanFile");
2692     }
2693
2694   /*
2695    * Compute dimensions and scale factors
2696    *
2697    */
2698
2699   ddata->bbox=bbox;
2700
2701   /* User specified resolution */
2702   resolution_y=DefaultResolution;
2703   if (image->resolution.y != 0.0)
2704     {
2705       resolution_y = image->resolution.y;
2706       if (image->units == PixelsPerCentimeterResolution)
2707         resolution_y *= CENTIMETERS_PER_INCH;
2708     }
2709   resolution_x=DefaultResolution;
2710   if (image->resolution.x != 0.0)
2711     {
2712       resolution_x = image->resolution.x;
2713       if (image->units == PixelsPerCentimeterResolution)
2714         resolution_x *= CENTIMETERS_PER_INCH;
2715     }
2716
2717   /* Obtain output size expressed in metafile units */
2718   wmf_error=wmf_size(API,&wmf_width,&wmf_height);
2719   if (wmf_error != wmf_E_None)
2720     {
2721       wmf_api_destroy(API);
2722       if (image->debug != MagickFalse)
2723         {
2724           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2725             "  wmf_size failed with wmf_error %d", wmf_error);
2726           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2727             "leave ReadWMFImage()");
2728         }
2729       ThrowReaderException(DelegateError,"FailedToComputeOutputSize");
2730     }
2731
2732   /* Obtain (or guess) metafile units */
2733   if ((API)->File->placeable)
2734     units_per_inch=(API)->File->pmh->Inch;
2735   else if ( (wmf_width*wmf_height) < 1024*1024)
2736     units_per_inch=POINTS_PER_INCH;  /* MM_TEXT */
2737   else
2738     units_per_inch=TWIPS_PER_INCH;  /* MM_TWIPS */
2739
2740   /* Calculate image width and height based on specified DPI
2741      resolution */
2742   image_width_inch  = (double) wmf_width / units_per_inch;
2743   image_height_inch = (double) wmf_height / units_per_inch;
2744   image_width       = image_width_inch * resolution_x;
2745   image_height      = image_height_inch * resolution_y;
2746
2747   /* Compute bounding box scale factors and origin translations
2748    *
2749    * This all just a hack since libwmf does not currently seem to
2750    * provide the mapping between LOGICAL coordinates and DEVICE
2751    * coordinates. This mapping is necessary in order to know
2752    * where to place the logical bounding box within the image.
2753    *
2754    */
2755
2756   bounding_width  = bbox.BR.x - bbox.TL.x;
2757   bounding_height = bbox.BR.y - bbox.TL.y;
2758
2759   ddata->scale_x = image_width/bounding_width;
2760   ddata->translate_x = 0-bbox.TL.x;
2761   ddata->rotate = 0;
2762
2763   /* Heuristic: guess that if the vertical coordinates mostly span
2764      negative values, then the image must be inverted. */
2765   if ( fabs(bbox.BR.y) > fabs(bbox.TL.y) )
2766     {
2767       /* Normal (Origin at top left of image) */
2768       ddata->scale_y = (image_height/bounding_height);
2769       ddata->translate_y = 0-bbox.TL.y;
2770     }
2771   else
2772     {
2773       /* Inverted (Origin at bottom left of image) */
2774       ddata->scale_y = (-image_height/bounding_height);
2775       ddata->translate_y = 0-bbox.BR.y;
2776     }
2777
2778   if (image->debug != MagickFalse)
2779     {
2780       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2781          "  Placeable metafile:          %s",
2782          (API)->File->placeable ? "Yes" : "No");
2783
2784       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2785         "  Size in metafile units:      %gx%g",wmf_width,wmf_height);
2786       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2787         "  Metafile units/inch:         %g",units_per_inch);
2788       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2789         "  Size in inches:              %gx%g",
2790         image_width_inch,image_height_inch);
2791       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2792         "  Bounding Box:                %g,%g %g,%g",
2793         bbox.TL.x, bbox.TL.y, bbox.BR.x, bbox.BR.y);
2794       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2795         "  Bounding width x height:     %gx%g",bounding_width,
2796         bounding_height);
2797       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2798         "  Output resolution:           %gx%g",resolution_x,resolution_y);
2799       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2800         "  Image size:                  %gx%g",image_width,image_height);
2801       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2802         "  Bounding box scale factor:   %g,%g",ddata->scale_x,
2803         ddata->scale_y);
2804       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2805         "  Translation:                 %g,%g",
2806         ddata->translate_x, ddata->translate_y);
2807     }
2808
2809 #if 0
2810 #if 0
2811   {
2812     typedef struct _wmfPlayer_t wmfPlayer_t;
2813     struct _wmfPlayer_t
2814     {
2815       wmfPen   default_pen;
2816       wmfBrush default_brush;
2817       wmfFont  default_font;
2818
2819       wmfDC* dc; /* current dc */
2820     };
2821
2822     wmfDC
2823       *dc;
2824
2825 #define WMF_ELICIT_DC(API) (((wmfPlayer_t*)((API)->player_data))->dc)
2826
2827     dc = WMF_ELICIT_DC(API);
2828
2829     printf("dc->Window.Ox     = %d\n", dc->Window.Ox);
2830     printf("dc->Window.Oy     = %d\n", dc->Window.Oy);
2831     printf("dc->Window.width  = %d\n", dc->Window.width);
2832     printf("dc->Window.height = %d\n", dc->Window.height);
2833     printf("dc->pixel_width   = %g\n", dc->pixel_width);
2834     printf("dc->pixel_height  = %g\n", dc->pixel_height);
2835 #if defined(MAGICKCORE_WMFLITE_DELEGATE)  /* Only in libwmf 0.3 */
2836     printf("dc->Ox            = %.d\n", dc->Ox);
2837     printf("dc->Oy            = %.d\n", dc->Oy);
2838     printf("dc->width         = %.d\n", dc->width);
2839     printf("dc->height        = %.d\n", dc->height);
2840 #endif
2841
2842   }
2843 #endif
2844
2845 #endif
2846
2847   /*
2848    * Create canvas image
2849    *
2850    */
2851   image->rows=(unsigned long) ceil(image_height);
2852   image->columns=(unsigned long) ceil(image_width);
2853
2854   if (image_info->ping != MagickFalse)
2855     {
2856       wmf_api_destroy(API);
2857       (void) CloseBlob(image);
2858       if (image->debug != MagickFalse)
2859         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2860           "leave ReadWMFImage()");
2861       return(GetFirstImageInList(image));
2862     }
2863   if (image->debug != MagickFalse)
2864     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2865        "  Creating canvas image with size %lux%lu",(unsigned long) image->rows,
2866        (unsigned long) image->columns);
2867
2868   /*
2869    * Set solid background color
2870    */
2871   {
2872     image->background_color = image_info->background_color;
2873     if (image->background_color.alpha != OpaqueAlpha)
2874       image->alpha_trait = MagickTrue;
2875     (void) SetImageBackgroundColor(image,exception);
2876   }
2877   /*
2878    * Play file to generate Vector drawing commands
2879    *
2880    */
2881
2882   if (image->debug != MagickFalse)
2883     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2884       "  Playing WMF to prepare vectors");
2885
2886   wmf_error = wmf_play(API, 0, &bbox);
2887   if (wmf_error != wmf_E_None)
2888     {
2889       wmf_api_destroy(API);
2890       if (image->debug != MagickFalse)
2891         {
2892           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2893             "  Playing WMF failed with wmf_error %d", wmf_error);
2894           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2895             "leave ReadWMFImage()");
2896         }
2897       ThrowReaderException(DelegateError,"FailedToRenderFile");
2898     }
2899
2900   /*
2901    * Scribble on canvas image
2902    *
2903    */
2904
2905   if (image->debug != MagickFalse)
2906     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2907       "  Rendering WMF vectors");
2908   DrawRender(ddata->draw_wand);
2909
2910   if (image->debug != MagickFalse)
2911     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"leave ReadWMFImage()");
2912
2913   /* Cleanup allocated data */
2914   wmf_api_destroy(API);
2915   (void) CloseBlob(image);
2916
2917   /* Return image */
2918   return image;
2919 }
2920 #endif
2921 \f
2922 /*
2923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2924 %                                                                             %
2925 %                                                                             %
2926 %                                                                             %
2927 %   R e g i s t e r W M F I m a g e                                           %
2928 %                                                                             %
2929 %                                                                             %
2930 %                                                                             %
2931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2932 %
2933 %  RegisterWMFImage() adds attributes for the WMF image format to
2934 %  the list of supported formats.  The attributes include the image format
2935 %  tag, a method to read and/or write the format, whether the format
2936 %  supports the saving of more than one frame to the same file or blob,
2937 %  whether the format supports native in-memory I/O, and a brief
2938 %  description of the format.
2939 %
2940 %  The format of the RegisterWMFImage method is:
2941 %
2942 %      size_t RegisterWMFImage(void)
2943 %
2944 */
2945 ModuleExport size_t RegisterWMFImage(void)
2946 {
2947   MagickInfo
2948     *entry;
2949
2950   entry = SetMagickInfo("WMZ");
2951 #if defined(MAGICKCORE_WMF_DELEGATE) || defined(MAGICKCORE_WMFLITE_DELEGATE)
2952   entry->decoder=ReadWMFImage;
2953 #endif
2954   entry->description=ConstantString("Compressed Windows Meta File");
2955   entry->module=ConstantString("WMZ");
2956   entry->seekable_stream=MagickTrue;
2957   (void) RegisterMagickInfo(entry);
2958   entry=SetMagickInfo("WMF");
2959 #if defined(MAGICKCORE_WMF_DELEGATE) || defined(MAGICKCORE_WMFLITE_DELEGATE)
2960   entry->decoder=ReadWMFImage;
2961 #endif
2962   entry->description=ConstantString("Windows Meta File");
2963   entry->module=ConstantString("WMF");
2964   (void) RegisterMagickInfo(entry);
2965   return(MagickImageCoderSignature);
2966 }
2967 \f
2968 /*
2969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970 %                                                                             %
2971 %                                                                             %
2972 %                                                                             %
2973 %   U n r e g i s t e r W M F I m a g e                                       %
2974 %                                                                             %
2975 %                                                                             %
2976 %                                                                             %
2977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2978 %
2979 %  UnregisterWMFImage() removes format registrations made by the
2980 %  WMF module from the list of supported formats.
2981 %
2982 %  The format of the UnregisterWMFImage method is:
2983 %
2984 %      UnregisterWMFImage(void)
2985 %
2986 */
2987 ModuleExport void UnregisterWMFImage(void)
2988 {
2989   (void) UnregisterMagickInfo("WMZ");
2990   (void) UnregisterMagickInfo("WMF");
2991 }