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