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