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