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