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