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