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