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