1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % EEEEE M M FFFFF % 7 % E MM MM F % 8 % EEE M M M FFF % 9 % E M M F % 10 % EEEEE M M F % 11 % % 12 % % 13 % Read Windows Enahanced Metafile Format % 14 % % 15 % Software Design % 16 % Bill Radcliffe % 17 % 2001 % 18 % Dirk Lemstra % 19 % January 2014 % 20 % % 21 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 22 % dedicated to making software imaging solutions freely available. % 23 % % 24 % You may not use this file except in compliance with the License. You may % 25 % obtain a copy of the License at % 26 % % 27 % http://www.imagemagick.org/script/license.php % 28 % % 29 % Unless required by applicable law or agreed to in writing, software % 30 % distributed under the License is distributed on an "AS IS" BASIS, % 31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 32 % See the License for the specific language governing permissions and % 33 % limitations under the License. % 34 % % 35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 */ 37 38 /* 40 * Include declarations. 41 */ 42 43 #include "MagickCore/studio.h" 44 #if defined(MAGICKCORE_WINGDI32_DELEGATE) 45 # if !defined(_MSC_VER) 46 # if defined(__CYGWIN__) 47 # include <windows.h> 48 # else 49 # include <wingdi.h> 50 # endif 51 # else 52 #pragma warning(disable: 4457) 53 #pragma warning(disable: 4458) 54 # include <gdiplus.h> 55 #pragma warning(default: 4457) 56 #pragma warning(default: 4458) 57 # pragma comment(lib, "gdiplus.lib") 58 # endif 59 #endif 60 #include "MagickCore/blob.h" 61 #include "MagickCore/blob-private.h" 62 #include "MagickCore/cache.h" 63 #include "MagickCore/exception.h" 64 #include "MagickCore/exception-private.h" 65 #include "MagickCore/geometry.h" 66 #include "MagickCore/image.h" 67 #include "MagickCore/image-private.h" 68 #include "MagickCore/list.h" 69 #include "MagickCore/magick.h" 70 #include "MagickCore/memory_.h" 71 #include "MagickCore/pixel.h" 72 #include "MagickCore/pixel-accessor.h" 73 #include "MagickCore/quantum-private.h" 74 #include "MagickCore/static.h" 75 #include "MagickCore/string_.h" 76 #include "MagickCore/module.h" 77 78 /* 80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 81 % % 82 % % 83 % % 84 % I s E F M % 85 % % 86 % % 87 % % 88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 89 % 90 % IsEMF() returns MagickTrue if the image format type, identified by the 91 % magick string, is a Microsoft Windows Enhanced MetaFile (EMF) file. 92 % 93 % The format of the ReadEMFImage method is: 94 % 95 % MagickBooleanType IsEMF(const unsigned char *magick,const size_t length) 96 % 97 % A description of each parameter follows: 98 % 99 % o magick: compare image format pattern against these bytes. 100 % 101 % o length: Specifies the length of the magick string. 102 % 103 */ 104 static MagickBooleanType IsEMF(const unsigned char *magick,const size_t length) 105 { 106 if (length < 48) 107 return(MagickFalse); 108 if (memcmp(magick+40,"\040\105\115\106\000\000\001\000",8) == 0) 109 return(MagickTrue); 110 return(MagickFalse); 111 } 112 113 /* 115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 116 % % 117 % % 118 % % 119 % I s W M F % 120 % % 121 % % 122 % % 123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 124 % 125 % IsWMF() returns MagickTrue if the image format type, identified by the 126 % magick string, is a Windows MetaFile (WMF) file. 127 % 128 % The format of the ReadEMFImage method is: 129 % 130 % MagickBooleanType IsEMF(const unsigned char *magick,const size_t length) 131 % 132 % A description of each parameter follows: 133 % 134 % o magick: compare image format pattern against these bytes. 135 % 136 % o length: Specifies the length of the magick string. 137 % 138 */ 139 static MagickBooleanType IsWMF(const unsigned char *magick,const size_t length) 140 { 141 if (length < 4) 142 return(MagickFalse); 143 if (memcmp(magick,"\327\315\306\232",4) == 0) 144 return(MagickTrue); 145 if (memcmp(magick,"\001\000\011\000",4) == 0) 146 return(MagickTrue); 147 return(MagickFalse); 148 } 149 150 /* 152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 153 % % 154 % % 155 % % 156 % R e a d E M F I m a g e % 157 % % 158 % % 159 % % 160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 161 % 162 % ReadEMFImage() reads an Microsoft Windows Enhanced MetaFile (EMF) or 163 % Windows MetaFile (WMF) file using the Windows API and returns it. It 164 % allocates the memory necessary for the new Image structure and returns a 165 % pointer to the new image. 166 % 167 % The format of the ReadEMFImage method is: 168 % 169 % Image *ReadEMFImage(const ImageInfo *image_info, 170 % ExceptionInfo *exception) 171 % 172 % A description of each parameter follows: 173 % 174 % o image_info: the image info.. 175 % 176 % o exception: return any errors or warnings in this structure. 177 % 178 */ 179 180 #if defined(MAGICKCORE_WINGDI32_DELEGATE) 181 # if !defined(_MSC_VER) 182 # if defined(MAGICKCORE_HAVE__WFOPEN) 183 static size_t UTF8ToUTF16(const unsigned char *utf8,wchar_t *utf16) 184 { 185 register const unsigned char 186 *p; 187 188 if (utf16 != (wchar_t *) NULL) 189 { 190 register wchar_t 191 *q; 192 193 wchar_t 194 c; 195 196 /* 197 Convert UTF-8 to UTF-16. 198 */ 199 q=utf16; 200 for (p=utf8; *p != '\0'; p++) 201 { 202 if ((*p & 0x80) == 0) 203 *q=(*p); 204 else 205 if ((*p & 0xE0) == 0xC0) 206 { 207 c=(*p); 208 *q=(c & 0x1F) << 6; 209 p++; 210 if ((*p & 0xC0) != 0x80) 211 return(0); 212 *q|=(*p & 0x3F); 213 } 214 else 215 if ((*p & 0xF0) == 0xE0) 216 { 217 c=(*p); 218 *q=c << 12; 219 p++; 220 if ((*p & 0xC0) != 0x80) 221 return(0); 222 c=(*p); 223 *q|=(c & 0x3F) << 6; 224 p++; 225 if ((*p & 0xC0) != 0x80) 226 return(0); 227 *q|=(*p & 0x3F); 228 } 229 else 230 return(0); 231 q++; 232 } 233 *q++='\0'; 234 return(q-utf16); 235 } 236 /* 237 Compute UTF-16 string length. 238 */ 239 for (p=utf8; *p != '\0'; p++) 240 { 241 if ((*p & 0x80) == 0) 242 ; 243 else 244 if ((*p & 0xE0) == 0xC0) 245 { 246 p++; 247 if ((*p & 0xC0) != 0x80) 248 return(0); 249 } 250 else 251 if ((*p & 0xF0) == 0xE0) 252 { 253 p++; 254 if ((*p & 0xC0) != 0x80) 255 return(0); 256 p++; 257 if ((*p & 0xC0) != 0x80) 258 return(0); 259 } 260 else 261 return(0); 262 } 263 return(p-utf8); 264 } 265 266 static wchar_t *ConvertUTF8ToUTF16(const unsigned char *source) 267 { 268 size_t 269 length; 270 271 wchar_t 272 *utf16; 273 274 length=UTF8ToUTF16(source,(wchar_t *) NULL); 275 if (length == 0) 276 { 277 register ssize_t 278 i; 279 280 /* 281 Not UTF-8, just copy. 282 */ 283 length=strlen((char *) source); 284 utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16)); 285 if (utf16 == (wchar_t *) NULL) 286 return((wchar_t *) NULL); 287 for (i=0; i <= (ssize_t) length; i++) 288 utf16[i]=source[i]; 289 return(utf16); 290 } 291 utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16)); 292 if (utf16 == (wchar_t *) NULL) 293 return((wchar_t *) NULL); 294 length=UTF8ToUTF16(source,utf16); 295 return(utf16); 296 } 297 # endif /* MAGICKCORE_HAVE__WFOPEN */ 298 299 static HENHMETAFILE ReadEnhMetaFile(const char *path,ssize_t *width, 300 ssize_t *height) 301 { 302 #pragma pack( push, 2 ) 303 typedef struct 304 { 305 DWORD dwKey; 306 WORD hmf; 307 SMALL_RECT bbox; 308 WORD wInch; 309 DWORD dwReserved; 310 WORD wCheckSum; 311 } APMHEADER, *PAPMHEADER; 312 #pragma pack( pop ) 313 314 DWORD 315 dwSize; 316 317 ENHMETAHEADER 318 emfh; 319 320 HANDLE 321 hFile; 322 323 HDC 324 hDC; 325 326 HENHMETAFILE 327 hTemp; 328 329 LPBYTE 330 pBits; 331 332 METAFILEPICT 333 mp; 334 335 HMETAFILE 336 hOld; 337 338 *width=512; 339 *height=512; 340 hTemp=GetEnhMetaFile(path); 341 #if defined(MAGICKCORE_HAVE__WFOPEN) 342 if (hTemp == (HENHMETAFILE) NULL) 343 { 344 wchar_t 345 *unicode_path; 346 347 unicode_path=ConvertUTF8ToUTF16((const unsigned char *) path); 348 if (unicode_path != (wchar_t *) NULL) 349 { 350 hTemp=GetEnhMetaFileW(unicode_path); 351 unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path); 352 } 353 } 354 #endif 355 if (hTemp != (HENHMETAFILE) NULL) 356 { 357 /* 358 Enhanced metafile. 359 */ 360 GetEnhMetaFileHeader(hTemp,sizeof(ENHMETAHEADER),&emfh); 361 *width=emfh.rclFrame.right-emfh.rclFrame.left; 362 *height=emfh.rclFrame.bottom-emfh.rclFrame.top; 363 return(hTemp); 364 } 365 hOld=GetMetaFile(path); 366 if (hOld != (HMETAFILE) NULL) 367 { 368 /* 369 16bit windows metafile. 370 */ 371 dwSize=GetMetaFileBitsEx(hOld,0,NULL); 372 if (dwSize == 0) 373 { 374 DeleteMetaFile(hOld); 375 return((HENHMETAFILE) NULL); 376 } 377 pBits=(LPBYTE) AcquireQuantumMemory(dwSize,sizeof(*pBits)); 378 if (pBits == (LPBYTE) NULL) 379 { 380 DeleteMetaFile(hOld); 381 return((HENHMETAFILE) NULL); 382 } 383 if (GetMetaFileBitsEx(hOld,dwSize,pBits) == 0) 384 { 385 pBits=(BYTE *) DestroyString((char *) pBits); 386 DeleteMetaFile(hOld); 387 return((HENHMETAFILE) NULL); 388 } 389 /* 390 Make an enhanced metafile from the windows metafile. 391 */ 392 mp.mm=MM_ANISOTROPIC; 393 mp.xExt=1000; 394 mp.yExt=1000; 395 mp.hMF=NULL; 396 hDC=GetDC(NULL); 397 hTemp=SetWinMetaFileBits(dwSize,pBits,hDC,&mp); 398 ReleaseDC(NULL,hDC); 399 DeleteMetaFile(hOld); 400 pBits=(BYTE *) DestroyString((char *) pBits); 401 GetEnhMetaFileHeader(hTemp,sizeof(ENHMETAHEADER),&emfh); 402 *width=emfh.rclFrame.right-emfh.rclFrame.left; 403 *height=emfh.rclFrame.bottom-emfh.rclFrame.top; 404 return(hTemp); 405 } 406 /* 407 Aldus Placeable metafile. 408 */ 409 hFile=CreateFile(path,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 410 NULL); 411 if (hFile == INVALID_HANDLE_VALUE) 412 return(NULL); 413 dwSize=GetFileSize(hFile,NULL); 414 pBits=(LPBYTE) AcquireQuantumMemory(dwSize,sizeof(*pBits)); 415 ReadFile(hFile,pBits,dwSize,&dwSize,NULL); 416 CloseHandle(hFile); 417 if (((PAPMHEADER) pBits)->dwKey != 0x9ac6cdd7l) 418 { 419 pBits=(BYTE *) DestroyString((char *) pBits); 420 return((HENHMETAFILE) NULL); 421 } 422 /* 423 Make an enhanced metafile from the placable metafile. 424 */ 425 mp.mm=MM_ANISOTROPIC; 426 mp.xExt=((PAPMHEADER) pBits)->bbox.Right-((PAPMHEADER) pBits)->bbox.Left; 427 *width=mp.xExt; 428 mp.xExt=(mp.xExt*2540l)/(DWORD) (((PAPMHEADER) pBits)->wInch); 429 mp.yExt=((PAPMHEADER)pBits)->bbox.Bottom-((PAPMHEADER) pBits)->bbox.Top; 430 *height=mp.yExt; 431 mp.yExt=(mp.yExt*2540l)/(DWORD) (((PAPMHEADER) pBits)->wInch); 432 mp.hMF=NULL; 433 hDC=GetDC(NULL); 434 hTemp=SetWinMetaFileBits(dwSize,&(pBits[sizeof(APMHEADER)]),hDC,&mp); 435 ReleaseDC(NULL,hDC); 436 pBits=(BYTE *) DestroyString((char *) pBits); 437 return(hTemp); 438 } 439 440 #define CENTIMETERS_INCH 2.54 441 442 static Image *ReadEMFImage(const ImageInfo *image_info,ExceptionInfo *exception) 443 { 444 BITMAPINFO 445 DIBinfo; 446 447 HBITMAP 448 hBitmap, 449 hOldBitmap; 450 451 HDC 452 hDC; 453 454 HENHMETAFILE 455 hemf; 456 457 Image 458 *image; 459 460 MagickBooleanType 461 status; 462 463 RECT 464 rect; 465 466 register ssize_t 467 x; 468 469 register Quantum 470 *q; 471 472 RGBQUAD 473 *pBits, 474 *ppBits; 475 476 ssize_t 477 height, 478 width, 479 y; 480 481 image=AcquireImage(image_info,exception); 482 hemf=ReadEnhMetaFile(image_info->filename,&width,&height); 483 if (hemf == (HENHMETAFILE) NULL) 484 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 485 if ((image->columns == 0) || (image->rows == 0)) 486 { 487 double 488 y_resolution, 489 x_resolution; 490 491 y_resolution=DefaultResolution; 492 x_resolution=DefaultResolution; 493 if (image->resolution.y > 0) 494 { 495 y_resolution=image->resolution.y; 496 if (image->units == PixelsPerCentimeterResolution) 497 y_resolution*=CENTIMETERS_INCH; 498 } 499 if (image->resolution.x > 0) 500 { 501 x_resolution=image->resolution.x; 502 if (image->units == PixelsPerCentimeterResolution) 503 x_resolution*=CENTIMETERS_INCH; 504 } 505 image->rows=(size_t) ((height/1000.0/CENTIMETERS_INCH)*y_resolution+0.5); 506 image->columns=(size_t) ((width/1000.0/CENTIMETERS_INCH)* 507 x_resolution+0.5); 508 } 509 if (image_info->size != (char *) NULL) 510 { 511 image->columns=width; 512 image->rows=height; 513 (void) GetGeometry(image_info->size,(ssize_t *) NULL,(ssize_t *) NULL, 514 &image->columns,&image->rows); 515 } 516 status=SetImageExtent(image,image->columns,image->rows,exception); 517 if (status == MagickFalse) 518 return(DestroyImageList(image)); 519 if (image_info->page != (char *) NULL) 520 { 521 char 522 *geometry; 523 524 register char 525 *p; 526 527 MagickStatusType 528 flags; 529 530 ssize_t 531 sans; 532 533 geometry=GetPageGeometry(image_info->page); 534 p=strchr(geometry,'>'); 535 if (p == (char *) NULL) 536 { 537 flags=ParseMetaGeometry(geometry,&sans,&sans,&image->columns, 538 &image->rows); 539 if (image->resolution.x != 0.0) 540 image->columns=(size_t) floor((image->columns*image->resolution.x)+ 541 0.5); 542 if (image->resolution.y != 0.0) 543 image->rows=(size_t) floor((image->rows*image->resolution.y)+0.5); 544 } 545 else 546 { 547 *p='\0'; 548 flags=ParseMetaGeometry(geometry,&sans,&sans,&image->columns, 549 &image->rows); 550 if (image->resolution.x != 0.0) 551 image->columns=(size_t) floor(((image->columns*image->resolution.x)/ 552 DefaultResolution)+0.5); 553 if (image->resolution.y != 0.0) 554 image->rows=(size_t) floor(((image->rows*image->resolution.y)/ 555 DefaultResolution)+0.5); 556 } 557 (void) flags; 558 geometry=DestroyString(geometry); 559 } 560 hDC=GetDC(NULL); 561 if (hDC == (HDC) NULL) 562 { 563 DeleteEnhMetaFile(hemf); 564 ThrowReaderException(ResourceLimitError,"UnableToCreateADC"); 565 } 566 /* 567 Initialize the bitmap header info. 568 */ 569 (void) ResetMagickMemory(&DIBinfo,0,sizeof(BITMAPINFO)); 570 DIBinfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); 571 DIBinfo.bmiHeader.biWidth=(LONG) image->columns; 572 DIBinfo.bmiHeader.biHeight=(-1)*(LONG) image->rows; 573 DIBinfo.bmiHeader.biPlanes=1; 574 DIBinfo.bmiHeader.biBitCount=32; 575 DIBinfo.bmiHeader.biCompression=BI_RGB; 576 hBitmap=CreateDIBSection(hDC,&DIBinfo,DIB_RGB_COLORS,(void **) &ppBits,NULL, 577 0); 578 ReleaseDC(NULL,hDC); 579 if (hBitmap == (HBITMAP) NULL) 580 { 581 DeleteEnhMetaFile(hemf); 582 ThrowReaderException(ResourceLimitError,"UnableToCreateBitmap"); 583 } 584 hDC=CreateCompatibleDC(NULL); 585 if (hDC == (HDC) NULL) 586 { 587 DeleteEnhMetaFile(hemf); 588 DeleteObject(hBitmap); 589 ThrowReaderException(ResourceLimitError,"UnableToCreateADC"); 590 } 591 hOldBitmap=(HBITMAP) SelectObject(hDC,hBitmap); 592 if (hOldBitmap == (HBITMAP) NULL) 593 { 594 DeleteEnhMetaFile(hemf); 595 DeleteDC(hDC); 596 DeleteObject(hBitmap); 597 ThrowReaderException(ResourceLimitError,"UnableToCreateBitmap"); 598 } 599 /* 600 Initialize the bitmap to the image background color. 601 */ 602 pBits=ppBits; 603 for (y=0; y < (ssize_t) image->rows; y++) 604 { 605 for (x=0; x < (ssize_t) image->columns; x++) 606 { 607 pBits->rgbRed=ScaleQuantumToChar(image->background_color.red); 608 pBits->rgbGreen=ScaleQuantumToChar(image->background_color.green); 609 pBits->rgbBlue=ScaleQuantumToChar(image->background_color.blue); 610 pBits++; 611 } 612 } 613 rect.top=0; 614 rect.left=0; 615 rect.right=(LONG) image->columns; 616 rect.bottom=(LONG) image->rows; 617 /* 618 Convert metafile pixels. 619 */ 620 PlayEnhMetaFile(hDC,hemf,&rect); 621 pBits=ppBits; 622 for (y=0; y < (ssize_t) image->rows; y++) 623 { 624 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 625 if (q == (Quantum *) NULL) 626 break; 627 for (x=0; x < (ssize_t) image->columns; x++) 628 { 629 SetPixelRed(image,ScaleCharToQuantum(pBits->rgbRed),q); 630 SetPixelGreen(image,ScaleCharToQuantum(pBits->rgbGreen),q); 631 SetPixelBlue(image,ScaleCharToQuantum(pBits->rgbBlue),q); 632 SetPixelAlpha(image,OpaqueAlpha,q); 633 pBits++; 634 q+=GetPixelChannels(image); 635 } 636 if (SyncAuthenticPixels(image,exception) == MagickFalse) 637 break; 638 } 639 DeleteEnhMetaFile(hemf); 640 SelectObject(hDC,hOldBitmap); 641 DeleteDC(hDC); 642 DeleteObject(hBitmap); 643 return(GetFirstImageInList(image)); 644 } 645 # else 646 647 static inline void EMFSetDimensions(Image * image,Gdiplus::Image *source) 648 { 649 if ((image->resolution.x <= 0.0) || (image->resolution.y <= 0.0)) 650 return; 651 652 image->columns=(size_t) floor((Gdiplus::REAL) source->GetWidth()/ 653 source->GetHorizontalResolution()*image->resolution.x+0.5); 654 image->rows=(size_t)floor((Gdiplus::REAL) source->GetHeight()/ 655 source->GetVerticalResolution()*image->resolution.y+0.5); 656 } 657 658 static Image *ReadEMFImage(const ImageInfo *image_info, 659 ExceptionInfo *exception) 660 { 661 Gdiplus::Bitmap 662 *bitmap; 663 664 Gdiplus::BitmapData 665 bitmap_data; 666 667 Gdiplus::GdiplusStartupInput 668 startup_input; 669 670 Gdiplus::Graphics 671 *graphics; 672 673 Gdiplus::Image 674 *source; 675 676 Gdiplus::Rect 677 rect; 678 679 GeometryInfo 680 geometry_info; 681 682 Image 683 *image; 684 685 MagickStatusType 686 flags; 687 688 register Quantum 689 *q; 690 691 register ssize_t 692 x; 693 694 ssize_t 695 y; 696 697 ULONG_PTR 698 token; 699 700 unsigned char 701 *p; 702 703 wchar_t 704 fileName[MagickPathExtent]; 705 706 assert(image_info != (const ImageInfo *) NULL); 707 assert(image_info->signature == MagickCoreSignature); 708 if (image_info->debug != MagickFalse) 709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 710 image_info->filename); 711 assert(exception != (ExceptionInfo *) NULL); 712 713 image=AcquireImage(image_info,exception); 714 if (Gdiplus::GdiplusStartup(&token,&startup_input,NULL) != 715 Gdiplus::Status::Ok) 716 ThrowReaderException(CoderError, "GdiplusStartupFailed"); 717 MultiByteToWideChar(CP_UTF8,0,image->filename,-1,fileName,MagickPathExtent); 718 source=Gdiplus::Image::FromFile(fileName); 719 if (source == (Gdiplus::Image *) NULL) 720 { 721 Gdiplus::GdiplusShutdown(token); 722 ThrowReaderException(FileOpenError,"UnableToOpenFile"); 723 } 724 725 image->resolution.x=source->GetHorizontalResolution(); 726 image->resolution.y=source->GetVerticalResolution(); 727 image->columns=(size_t) source->GetWidth(); 728 image->rows=(size_t) source->GetHeight(); 729 if (image_info->size != (char *) NULL) 730 { 731 (void) GetGeometry(image_info->size,(ssize_t *) NULL,(ssize_t *) NULL, 732 &image->columns,&image->rows); 733 image->resolution.x=source->GetHorizontalResolution()*image->columns/ 734 source->GetWidth(); 735 image->resolution.y=source->GetVerticalResolution()*image->rows/ 736 source->GetHeight(); 737 if (image->resolution.x == 0) 738 image->resolution.x=image->resolution.y; 739 else if (image->resolution.y == 0) 740 image->resolution.y=image->resolution.x; 741 else 742 image->resolution.x=image->resolution.y=MagickMin( 743 image->resolution.x,image->resolution.y); 744 EMFSetDimensions(image,source); 745 } 746 else if (image_info->density != (char *) NULL) 747 { 748 flags=ParseGeometry(image_info->density,&geometry_info); 749 image->resolution.x=geometry_info.rho; 750 image->resolution.y=geometry_info.sigma; 751 if ((flags & SigmaValue) == 0) 752 image->resolution.y=image->resolution.x; 753 EMFSetDimensions(image,source); 754 } 755 if (SetImageExtent(image,image->columns,image->rows,exception) == MagickFalse) 756 { 757 delete source; 758 Gdiplus::GdiplusShutdown(token); 759 return(DestroyImageList(image)); 760 } 761 image->alpha_trait=BlendPixelTrait; 762 if (image->ping != MagickFalse) 763 { 764 delete source; 765 Gdiplus::GdiplusShutdown(token); 766 return(image); 767 } 768 769 bitmap=new Gdiplus::Bitmap((INT) image->columns,(INT) image->rows, 770 PixelFormat32bppARGB); 771 graphics=Gdiplus::Graphics::FromImage(bitmap); 772 graphics->SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic); 773 graphics->SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); 774 graphics->SetTextRenderingHint(Gdiplus::TextRenderingHintClearTypeGridFit); 775 graphics->Clear(Gdiplus::Color((BYTE) ScaleQuantumToChar( 776 image->background_color.alpha),(BYTE) ScaleQuantumToChar( 777 image->background_color.red),(BYTE) ScaleQuantumToChar( 778 image->background_color.green),(BYTE) ScaleQuantumToChar( 779 image->background_color.blue))); 780 graphics->DrawImage(source,0,0,(INT) image->columns,(INT) image->rows); 781 delete graphics; 782 delete source; 783 784 rect=Gdiplus::Rect(0,0,(INT) image->columns,(INT) image->rows); 785 if (bitmap->LockBits(&rect,Gdiplus::ImageLockModeRead,PixelFormat32bppARGB, 786 &bitmap_data) != Gdiplus::Ok) 787 { 788 delete bitmap; 789 Gdiplus::GdiplusShutdown(token); 790 ThrowReaderException(FileOpenError,"UnableToReadImageData"); 791 } 792 793 for (y=0; y < (ssize_t) image->rows; y++) 794 { 795 p=(unsigned char *) bitmap_data.Scan0+(y*abs(bitmap_data.Stride)); 796 if (bitmap_data.Stride < 0) 797 q=GetAuthenticPixels(image,0,image->rows-y-1,image->columns,1,exception); 798 else 799 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 800 if (q == (Quantum *) NULL) 801 break; 802 803 for (x=0; x < (ssize_t) image->columns; x++) 804 { 805 SetPixelBlue(image,ScaleCharToQuantum(*p++),q); 806 SetPixelGreen(image,ScaleCharToQuantum(*p++),q); 807 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 808 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q); 809 q+=GetPixelChannels(image); 810 } 811 812 if (SyncAuthenticPixels(image,exception) == MagickFalse) 813 break; 814 } 815 816 bitmap->UnlockBits(&bitmap_data); 817 delete bitmap; 818 Gdiplus::GdiplusShutdown(token); 819 return(image); 820 } 821 # endif /* _MSC_VER */ 822 #endif /* MAGICKCORE_EMF_DELEGATE */ 823 824 /* 826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 827 % % 828 % % 829 % % 830 % R e g i s t e r E M F I m a g e % 831 % % 832 % % 833 % % 834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 835 % 836 % RegisterEMFImage() adds attributes for the EMF image format to 837 % the list of supported formats. The attributes include the image format 838 % tag, a method to read and/or write the format, whether the format 839 % supports the saving of more than one frame to the same file or blob, 840 % whether the format supports native in-memory I/O, and a brief 841 % description of the format. 842 % 843 % The format of the RegisterEMFImage method is: 844 % 845 % size_t RegisterEMFImage(void) 846 % 847 */ 848 ModuleExport size_t RegisterEMFImage(void) 849 { 850 MagickInfo 851 *entry; 852 853 entry=AcquireMagickInfo("EMF","EMF","Windows Enhanced Meta File"); 854 #if defined(MAGICKCORE_WINGDI32_DELEGATE) 855 entry->decoder=ReadEMFImage; 856 #endif 857 entry->magick=(IsImageFormatHandler *) IsEMF; 858 entry->flags^=CoderBlobSupportFlag; 859 (void) RegisterMagickInfo(entry); 860 entry=AcquireMagickInfo("EMF","WMF","Windows Meta File"); 861 #if defined(MAGICKCORE_WINGDI32_DELEGATE) 862 entry->decoder=ReadEMFImage; 863 #endif 864 entry->magick=(IsImageFormatHandler *) IsWMF; 865 entry->flags^=CoderBlobSupportFlag; 866 (void) RegisterMagickInfo(entry); 867 return(MagickImageCoderSignature); 868 } 869 870 /* 872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 873 % % 874 % % 875 % % 876 % U n r e g i s t e r E M F I m a g e % 877 % % 878 % % 879 % % 880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 881 % 882 % UnregisterEMFImage() removes format registrations made by the 883 % EMF module from the list of supported formats. 884 % 885 % The format of the UnregisterEMFImage method is: 886 % 887 % UnregisterEMFImage(void) 888 % 889 */ 890 ModuleExport void UnregisterEMFImage(void) 891 { 892 (void) UnregisterMagickInfo("EMF"); 893 (void) UnregisterMagickInfo("WMF"); 894 } 895