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