Home | History | Annotate | Download | only in coders
      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