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