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/*
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
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*/
102static 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
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*/
136static 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
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)
179static 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
262static 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
295static 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
438static 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
643static 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
654static 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
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*/
843ModuleExport 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
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*/
884ModuleExport void UnregisterEMFImage(void)
885{
886  (void) UnregisterMagickInfo("EMF");
887  (void) UnregisterMagickInfo("WMF");
888}
889