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