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