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