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