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