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