• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2021 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: 4458)
52 #    include <gdiplus.h>
53 #pragma warning(default: 4458)
54 #    pragma comment(lib, "gdiplus.lib")
55 #  endif
56 #endif
57 #include "MagickCore/blob.h"
58 #include "MagickCore/blob-private.h"
59 #include "MagickCore/cache.h"
60 #include "MagickCore/exception.h"
61 #include "MagickCore/exception-private.h"
62 #include "MagickCore/geometry.h"
63 #include "MagickCore/image.h"
64 #include "MagickCore/image-private.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/magick.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/pixel.h"
69 #include "MagickCore/pixel-accessor.h"
70 #include "MagickCore/quantum-private.h"
71 #include "MagickCore/static.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/module.h"
74 #include "coders/emf.h"
75 
76 /*
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78 %                                                                             %
79 %                                                                             %
80 %                                                                             %
81 %   I s E F M                                                                 %
82 %                                                                             %
83 %                                                                             %
84 %                                                                             %
85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 %
87 %  IsEMF() returns MagickTrue if the image format type, identified by the
88 %  magick string, is a Microsoft Windows Enhanced MetaFile (EMF) file.
89 %
90 %  The format of the ReadEMFImage method is:
91 %
92 %      MagickBooleanType IsEMF(const unsigned char *magick,const size_t length)
93 %
94 %  A description of each parameter follows:
95 %
96 %    o magick: compare image format pattern against these bytes.
97 %
98 %    o length: Specifies the length of the magick string.
99 %
100 */
IsEMF(const unsigned char * magick,const size_t length)101 static MagickBooleanType IsEMF(const unsigned char *magick,const size_t length)
102 {
103   if (length < 48)
104     return(MagickFalse);
105   if (memcmp(magick+40,"\040\105\115\106\000\000\001\000",8) == 0)
106     return(MagickTrue);
107   return(MagickFalse);
108 }
109 
110 /*
111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112 %                                                                             %
113 %                                                                             %
114 %                                                                             %
115 %   I s W M F                                                                 %
116 %                                                                             %
117 %                                                                             %
118 %                                                                             %
119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 %
121 %  IsWMF() returns MagickTrue if the image format type, identified by the
122 %  magick string, is a Windows MetaFile (WMF) file.
123 %
124 %  The format of the ReadEMFImage method is:
125 %
126 %      MagickBooleanType IsEMF(const unsigned char *magick,const size_t length)
127 %
128 %  A description of each parameter follows:
129 %
130 %    o magick: compare image format pattern against these bytes.
131 %
132 %    o length: Specifies the length of the magick string.
133 %
134 */
IsWMF(const unsigned char * magick,const size_t length)135 static MagickBooleanType IsWMF(const unsigned char *magick,const size_t length)
136 {
137   if (length < 4)
138     return(MagickFalse);
139   if (memcmp(magick,"\327\315\306\232",4) == 0)
140     return(MagickTrue);
141   if (memcmp(magick,"\001\000\011\000",4) == 0)
142     return(MagickTrue);
143   return(MagickFalse);
144 }
145 
146 /*
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 %                                                                             %
149 %                                                                             %
150 %                                                                             %
151 %  R e a d E M F I m a g e                                                    %
152 %                                                                             %
153 %                                                                             %
154 %                                                                             %
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 %
157 %  ReadEMFImage() reads an Microsoft Windows Enhanced MetaFile (EMF) or
158 %  Windows MetaFile (WMF) file using the Windows API and returns it.  It
159 %  allocates the memory necessary for the new Image structure and returns a
160 %  pointer to the new image.
161 %
162 %  The format of the ReadEMFImage method is:
163 %
164 %      Image *ReadEMFImage(const ImageInfo *image_info,
165 %        ExceptionInfo *exception)
166 %
167 %  A description of each parameter follows:
168 %
169 %    o image_info: the image info..
170 %
171 %    o exception: return any errors or warnings in this structure.
172 %
173 */
174 
175 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
176 #  if !defined(_MSC_VER)
177 #    if defined(MAGICKCORE_HAVE__WFOPEN)
UTF8ToUTF16(const unsigned char * utf8,wchar_t * utf16)178 static size_t UTF8ToUTF16(const unsigned char *utf8,wchar_t *utf16)
179 {
180   const unsigned char
181     *p;
182 
183   if (utf16 != (wchar_t *) NULL)
184     {
185       wchar_t
186         *q;
187 
188       wchar_t
189         c;
190 
191       /*
192         Convert UTF-8 to UTF-16.
193       */
194       q=utf16;
195       for (p=utf8; *p != '\0'; p++)
196       {
197         if ((*p & 0x80) == 0)
198           *q=(*p);
199         else
200           if ((*p & 0xE0) == 0xC0)
201             {
202               c=(*p);
203               *q=(c & 0x1F) << 6;
204               p++;
205               if ((*p & 0xC0) != 0x80)
206                 return(0);
207               *q|=(*p & 0x3F);
208             }
209           else
210             if ((*p & 0xF0) == 0xE0)
211               {
212                 c=(*p);
213                 *q=c << 12;
214                 p++;
215                 if ((*p & 0xC0) != 0x80)
216                   return(0);
217                 c=(*p);
218                 *q|=(c & 0x3F) << 6;
219                 p++;
220                 if ((*p & 0xC0) != 0x80)
221                   return(0);
222                 *q|=(*p & 0x3F);
223               }
224             else
225               return(0);
226         q++;
227       }
228       *q++='\0';
229       return(q-utf16);
230     }
231   /*
232     Compute UTF-16 string length.
233   */
234   for (p=utf8; *p != '\0'; p++)
235   {
236     if ((*p & 0x80) == 0)
237       ;
238     else
239       if ((*p & 0xE0) == 0xC0)
240         {
241           p++;
242           if ((*p & 0xC0) != 0x80)
243             return(0);
244         }
245       else
246         if ((*p & 0xF0) == 0xE0)
247           {
248             p++;
249             if ((*p & 0xC0) != 0x80)
250               return(0);
251             p++;
252             if ((*p & 0xC0) != 0x80)
253               return(0);
254          }
255        else
256          return(0);
257   }
258   return(p-utf8);
259 }
260 
ConvertUTF8ToUTF16(const unsigned char * source)261 static wchar_t *ConvertUTF8ToUTF16(const unsigned char *source)
262 {
263   size_t
264     length;
265 
266   wchar_t
267     *utf16;
268 
269   length=UTF8ToUTF16(source,(wchar_t *) NULL);
270   if (length == 0)
271     {
272       ssize_t
273         i;
274 
275       /*
276         Not UTF-8, just copy.
277       */
278       length=strlen((char *) source);
279       utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16));
280       if (utf16 == (wchar_t *) NULL)
281         return((wchar_t *) NULL);
282       for (i=0; i <= (ssize_t) length; i++)
283         utf16[i]=source[i];
284       return(utf16);
285     }
286   utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16));
287   if (utf16 == (wchar_t *) NULL)
288     return((wchar_t *) NULL);
289   length=UTF8ToUTF16(source,utf16);
290   return(utf16);
291 }
292 #    endif /* MAGICKCORE_HAVE__WFOPEN */
293 
ReadEnhMetaFile(const char * path,ssize_t * width,ssize_t * height)294 static HENHMETAFILE ReadEnhMetaFile(const char *path,ssize_t *width,
295   ssize_t *height)
296 {
297 #pragma pack( push, 2 )
298   typedef struct
299   {
300     DWORD dwKey;
301     WORD hmf;
302     SMALL_RECT bbox;
303     WORD wInch;
304     DWORD dwReserved;
305     WORD wCheckSum;
306   } APMHEADER, *PAPMHEADER;
307 #pragma pack( pop )
308 
309   DWORD
310     dwSize;
311 
312   ENHMETAHEADER
313     emfh;
314 
315   HANDLE
316     hFile;
317 
318   HDC
319     hDC;
320 
321   HENHMETAFILE
322     hTemp;
323 
324   LPBYTE
325     pBits;
326 
327   METAFILEPICT
328     mp;
329 
330   HMETAFILE
331     hOld;
332 
333   *width=512;
334   *height=512;
335   hTemp=GetEnhMetaFile(path);
336 #if defined(MAGICKCORE_HAVE__WFOPEN)
337   if (hTemp == (HENHMETAFILE) NULL)
338     {
339       wchar_t
340         *unicode_path;
341 
342       unicode_path=ConvertUTF8ToUTF16((const unsigned char *) path);
343       if (unicode_path != (wchar_t *) NULL)
344         {
345           hTemp=GetEnhMetaFileW(unicode_path);
346           unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path);
347         }
348     }
349 #endif
350   if (hTemp != (HENHMETAFILE) NULL)
351     {
352       /*
353         Enhanced metafile.
354       */
355       GetEnhMetaFileHeader(hTemp,sizeof(ENHMETAHEADER),&emfh);
356       *width=emfh.rclFrame.right-emfh.rclFrame.left;
357       *height=emfh.rclFrame.bottom-emfh.rclFrame.top;
358       return(hTemp);
359     }
360   hOld=GetMetaFile(path);
361   if (hOld != (HMETAFILE) NULL)
362     {
363       /*
364         16bit windows metafile.
365       */
366       dwSize=GetMetaFileBitsEx(hOld,0,NULL);
367       if (dwSize == 0)
368         {
369           DeleteMetaFile(hOld);
370           return((HENHMETAFILE) NULL);
371         }
372       pBits=(LPBYTE) AcquireQuantumMemory(dwSize,sizeof(*pBits));
373       if (pBits == (LPBYTE) NULL)
374         {
375           DeleteMetaFile(hOld);
376           return((HENHMETAFILE) NULL);
377         }
378       if (GetMetaFileBitsEx(hOld,dwSize,pBits) == 0)
379         {
380           pBits=(BYTE *) DestroyString((char *) pBits);
381           DeleteMetaFile(hOld);
382           return((HENHMETAFILE) NULL);
383         }
384       /*
385         Make an enhanced metafile from the windows metafile.
386       */
387       mp.mm=MM_ANISOTROPIC;
388       mp.xExt=1000;
389       mp.yExt=1000;
390       mp.hMF=NULL;
391       hDC=GetDC(NULL);
392       hTemp=SetWinMetaFileBits(dwSize,pBits,hDC,&mp);
393       ReleaseDC(NULL,hDC);
394       DeleteMetaFile(hOld);
395       pBits=(BYTE *) DestroyString((char *) pBits);
396       GetEnhMetaFileHeader(hTemp,sizeof(ENHMETAHEADER),&emfh);
397       *width=emfh.rclFrame.right-emfh.rclFrame.left;
398       *height=emfh.rclFrame.bottom-emfh.rclFrame.top;
399       return(hTemp);
400     }
401   /*
402     Aldus Placeable metafile.
403   */
404   hFile=CreateFile(path,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,
405     NULL);
406   if (hFile == INVALID_HANDLE_VALUE)
407     return(NULL);
408   dwSize=GetFileSize(hFile,NULL);
409   pBits=(LPBYTE) AcquireQuantumMemory(dwSize,sizeof(*pBits));
410   if (pBits == (LPBYTE) NULL)
411     {
412       CloseHandle(hFile);
413       return((HENHMETAFILE) NULL);
414     }
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 
ReadEMFImage(const ImageInfo * image_info,ExceptionInfo * exception)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   ssize_t
467     x;
468 
469   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       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) memset(&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 
EMFSetDimensions(Image * image,Gdiplus::Image * source)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 
ReadEMFImage(const ImageInfo * image_info,ExceptionInfo * exception)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   Quantum
689     *q;
690 
691   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 /*
825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 %                                                                             %
827 %                                                                             %
828 %                                                                             %
829 %   R e g i s t e r E M F I m a g e                                           %
830 %                                                                             %
831 %                                                                             %
832 %                                                                             %
833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
834 %
835 %  RegisterEMFImage() adds attributes for the EMF image format to
836 %  the list of supported formats.  The attributes include the image format
837 %  tag, a method to read and/or write the format, whether the format
838 %  supports the saving of more than one frame to the same file or blob,
839 %  whether the format supports native in-memory I/O, and a brief
840 %  description of the format.
841 %
842 %  The format of the RegisterEMFImage method is:
843 %
844 %      size_t RegisterEMFImage(void)
845 %
846 */
RegisterEMFImage(void)847 ModuleExport size_t RegisterEMFImage(void)
848 {
849   MagickInfo
850     *entry;
851 
852   entry=AcquireMagickInfo("EMF","EMF","Windows Enhanced Meta File");
853 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
854   entry->decoder=ReadEMFImage;
855 #endif
856   entry->magick=(IsImageFormatHandler *) IsEMF;
857   entry->flags^=CoderBlobSupportFlag;
858   (void) RegisterMagickInfo(entry);
859   entry=AcquireMagickInfo("EMF","WMF","Windows Meta File");
860 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
861   entry->decoder=ReadEMFImage;
862 #endif
863   entry->magick=(IsImageFormatHandler *) IsWMF;
864   entry->flags^=CoderBlobSupportFlag;
865   (void) RegisterMagickInfo(entry);
866   return(MagickImageCoderSignature);
867 }
868 
869 /*
870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871 %                                                                             %
872 %                                                                             %
873 %                                                                             %
874 %   U n r e g i s t e r E M F I m a g e                                       %
875 %                                                                             %
876 %                                                                             %
877 %                                                                             %
878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879 %
880 %  UnregisterEMFImage() removes format registrations made by the
881 %  EMF module from the list of supported formats.
882 %
883 %  The format of the UnregisterEMFImage method is:
884 %
885 %      UnregisterEMFImage(void)
886 %
887 */
UnregisterEMFImage(void)888 ModuleExport void UnregisterEMFImage(void)
889 {
890   (void) UnregisterMagickInfo("EMF");
891   (void) UnregisterMagickInfo("WMF");
892 }
893