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