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