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