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