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