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