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