]> granicus.if.org Git - imagemagick/blob - coders/emf.c
Fixed dds:cluster-fit option.
[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-2014 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,
435   ExceptionInfo *exception)
436 {
437   BITMAPINFO
438     DIBinfo;
439
440   HBITMAP
441     hBitmap,
442     hOldBitmap;
443
444   HDC
445     hDC;
446
447   HENHMETAFILE
448     hemf;
449
450   Image
451     *image;
452
453   RECT
454     rect;
455
456   register ssize_t
457     x;
458
459   register Quantum
460     *q;
461
462   RGBQUAD
463     *pBits,
464     *ppBits;
465
466   ssize_t
467     height,
468     width,
469     y;
470
471   image=AcquireImage(image_info,exception);
472   hemf=ReadEnhMetaFile(image_info->filename,&width,&height);
473   if (hemf == (HENHMETAFILE) NULL)
474     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
475   if ((image->columns == 0) || (image->rows == 0))
476     {
477       double
478         y_resolution,
479         x_resolution;
480
481       y_resolution=DefaultResolution;
482       x_resolution=DefaultResolution;
483       if (image->resolution.y > 0)
484         {
485           y_resolution=image->resolution.y;
486           if (image->units == PixelsPerCentimeterResolution)
487             y_resolution*=CENTIMETERS_INCH;
488         }
489       if (image->resolution.x > 0)
490         {
491           x_resolution=image->resolution.x;
492           if (image->units == PixelsPerCentimeterResolution)
493             x_resolution*=CENTIMETERS_INCH;
494         }
495       image->rows=(size_t) ((height/1000.0/CENTIMETERS_INCH)*y_resolution+0.5);
496       image->columns=(size_t) ((width/1000.0/CENTIMETERS_INCH)*
497         x_resolution+0.5);
498     }
499   if (image_info->size != (char *) NULL)
500     {
501       ssize_t
502         x;
503
504       image->columns=width;
505       image->rows=height;
506       x=0;
507       y=0;
508       (void) GetGeometry(image_info->size,&x,&y,&image->columns,&image->rows);
509     }
510   if (image_info->page != (char *) NULL)
511     {
512       char
513         *geometry;
514
515       register char
516         *p;
517
518       MagickStatusType
519         flags;
520
521       ssize_t
522         sans;
523
524       geometry=GetPageGeometry(image_info->page);
525       p=strchr(geometry,'>');
526       if (p == (char *) NULL)
527         {
528           flags=ParseMetaGeometry(geometry,&sans,&sans,&image->columns,
529             &image->rows);
530           if (image->resolution.x != 0.0)
531             image->columns=(size_t) floor((image->columns*image->resolution.x)+
532               0.5);
533           if (image->resolution.y != 0.0)
534             image->rows=(size_t) floor((image->rows*image->resolution.y)+0.5);
535         }
536       else
537         {
538           *p='\0';
539           flags=ParseMetaGeometry(geometry,&sans,&sans,&image->columns,
540             &image->rows);
541           if (image->resolution.x != 0.0)
542             image->columns=(size_t) floor(((image->columns*image->resolution.x)/
543               DefaultResolution)+0.5);
544           if (image->resolution.y != 0.0)
545             image->rows=(size_t) floor(((image->rows*image->resolution.y)/
546               DefaultResolution)+0.5);
547         }
548       (void) flags;
549       geometry=DestroyString(geometry);
550     }
551   hDC=GetDC(NULL);
552   if (hDC == (HDC) NULL)
553     {
554       DeleteEnhMetaFile(hemf);
555       ThrowReaderException(ResourceLimitError,"UnableToCreateADC");
556     }
557   /*
558     Initialize the bitmap header info.
559   */
560   (void) ResetMagickMemory(&DIBinfo,0,sizeof(BITMAPINFO));
561   DIBinfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
562   DIBinfo.bmiHeader.biWidth=(LONG) image->columns;
563   DIBinfo.bmiHeader.biHeight=(-1)*(LONG) image->rows;
564   DIBinfo.bmiHeader.biPlanes=1;
565   DIBinfo.bmiHeader.biBitCount=32;
566   DIBinfo.bmiHeader.biCompression=BI_RGB;
567   hBitmap=CreateDIBSection(hDC,&DIBinfo,DIB_RGB_COLORS,(void **) &ppBits,NULL,
568     0);
569   ReleaseDC(NULL,hDC);
570   if (hBitmap == (HBITMAP) NULL)
571     {
572       DeleteEnhMetaFile(hemf);
573       ThrowReaderException(ResourceLimitError,"UnableToCreateBitmap");
574     }
575   hDC=CreateCompatibleDC(NULL);
576   if (hDC == (HDC) NULL)
577     {
578       DeleteEnhMetaFile(hemf);
579       DeleteObject(hBitmap);
580       ThrowReaderException(ResourceLimitError,"UnableToCreateADC");
581     }
582   hOldBitmap=(HBITMAP) SelectObject(hDC,hBitmap);
583   if (hOldBitmap == (HBITMAP) NULL)
584     {
585       DeleteEnhMetaFile(hemf);
586       DeleteDC(hDC);
587       DeleteObject(hBitmap);
588       ThrowReaderException(ResourceLimitError,"UnableToCreateBitmap");
589     }
590   /*
591     Initialize the bitmap to the image background color.
592   */
593   pBits=ppBits;
594   for (y=0; y < (ssize_t) image->rows; y++)
595   {
596     for (x=0; x < (ssize_t) image->columns; x++)
597     {
598       pBits->rgbRed=ScaleQuantumToChar(image->background_color.red);
599       pBits->rgbGreen=ScaleQuantumToChar(image->background_color.green);
600       pBits->rgbBlue=ScaleQuantumToChar(image->background_color.blue);
601       pBits++;
602     }
603   }
604   rect.top=0;
605   rect.left=0;
606   rect.right=(LONG) image->columns;
607   rect.bottom=(LONG) image->rows;
608   /*
609     Convert metafile pixels.
610   */
611   PlayEnhMetaFile(hDC,hemf,&rect);
612   pBits=ppBits;
613   for (y=0; y < (ssize_t) image->rows; y++)
614   {
615     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
616     if (q == (Quantum *) NULL)
617       break;
618     for (x=0; x < (ssize_t) image->columns; x++)
619     {
620       SetPixelRed(image,ScaleCharToQuantum(pBits->rgbRed),q);
621       SetPixelGreen(image,ScaleCharToQuantum(pBits->rgbGreen),q);
622       SetPixelBlue(image,ScaleCharToQuantum(pBits->rgbBlue),q);
623       SetPixelAlpha(image,OpaqueAlpha,q);
624       pBits++;
625       q+=GetPixelChannels(image);
626     }
627     if (SyncAuthenticPixels(image,exception) == MagickFalse)
628       break;
629   }
630   DeleteEnhMetaFile(hemf);
631   SelectObject(hDC,hOldBitmap);
632   DeleteDC(hDC);
633   DeleteObject(hBitmap);
634   return(GetFirstImageInList(image));
635 }
636 #  else
637 static Image *ReadEMFImage(const ImageInfo *image_info,
638   ExceptionInfo *exception)
639 {
640   Gdiplus::Bitmap
641     *bitmap;
642
643   Gdiplus::BitmapData
644      bitmap_data;
645
646   Gdiplus::GdiplusStartupInput
647     startup_input;
648
649   Gdiplus::Graphics
650     *graphics;
651
652   Gdiplus::Image
653     *source;
654
655   Gdiplus::Rect
656     rect;
657
658   GeometryInfo
659     geometry_info;
660
661   Image
662     *image;
663
664   MagickStatusType
665     flags;
666
667   register Quantum
668     *q;
669
670   register ssize_t
671     x;
672
673   ssize_t
674     y;
675
676   ULONG_PTR
677     token;
678
679   unsigned char
680     *p;
681
682   wchar_t
683     fileName[MaxTextExtent];
684
685   assert(image_info != (const ImageInfo *) NULL);
686   assert(image_info->signature == MagickSignature);
687   if (image_info->debug != MagickFalse)
688     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
689       image_info->filename);
690   assert(exception != (ExceptionInfo *) NULL);
691
692   image=AcquireImage(image_info,exception);
693   if (Gdiplus::GdiplusStartup(&token,&startup_input,NULL) != 
694     Gdiplus::Status::Ok)
695     ThrowReaderException(CoderError, "GdiplusStartupFailed");
696   MultiByteToWideChar(CP_UTF8,0,image->filename,-1,fileName,MaxTextExtent);
697   source=Gdiplus::Image::FromFile(fileName);
698   if (source == (Gdiplus::Image *) NULL)
699     {
700       Gdiplus::GdiplusShutdown(token);
701       ThrowReaderException(FileOpenError,"UnableToOpenFile");
702     }
703
704   image->resolution.x=source->GetHorizontalResolution();
705   image->resolution.y=source->GetVerticalResolution();
706   image->columns=(size_t) source->GetWidth();
707   image->rows=(size_t) source->GetHeight();
708   if (image_info->density != (char *) NULL)
709     {
710       flags=ParseGeometry(image_info->density,&geometry_info);
711       image->resolution.x=geometry_info.rho;
712       image->resolution.y=geometry_info.sigma;
713       if ((flags & SigmaValue) == 0)
714         image->resolution.y=image->resolution.x;
715       if ((image->resolution.x > 0.0) && (image->resolution.y > 0.0))
716         {
717           image->columns=(size_t) floor((Gdiplus::REAL) source->GetWidth() /
718             source->GetHorizontalResolution() * image->resolution.x + 0.5);
719           image->rows=(size_t)floor((Gdiplus::REAL) source->GetHeight() /
720             source->GetVerticalResolution() * image->resolution.y + 0.5);
721         }
722     }
723
724   bitmap=new Gdiplus::Bitmap((INT) image->columns,(INT) image->rows,
725     PixelFormat32bppARGB);
726   graphics=Gdiplus::Graphics::FromImage(bitmap);
727   graphics->SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
728   graphics->SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
729   graphics->SetTextRenderingHint(Gdiplus::TextRenderingHintClearTypeGridFit);
730   graphics->Clear(Gdiplus::Color((BYTE) ScaleQuantumToChar(
731     image->background_color.alpha),(BYTE) ScaleQuantumToChar(
732     image->background_color.red),(BYTE) ScaleQuantumToChar(
733     image->background_color.green),(BYTE) ScaleQuantumToChar(
734     image->background_color.blue)));
735   graphics->DrawImage(source,0,0,(INT) image->columns,(INT) image->rows);
736   delete graphics;
737   delete source;
738
739   rect=Gdiplus::Rect(0,0,(INT) image->columns,(INT) image->rows);
740   if (bitmap->LockBits(&rect,Gdiplus::ImageLockModeRead,PixelFormat32bppARGB,
741     &bitmap_data) != Gdiplus::Ok)
742   {
743     delete bitmap;
744     Gdiplus::GdiplusShutdown(token);
745     ThrowReaderException(FileOpenError,"UnableToReadImageData");
746   }
747
748   image->alpha_trait=BlendPixelTrait;
749   for (y=0; y < (ssize_t) image->rows; y++)
750   {
751     p=(unsigned char *) bitmap_data.Scan0+(y*abs(bitmap_data.Stride));
752     if (bitmap_data.Stride < 0)
753       q=GetAuthenticPixels(image,0,image->rows-y-1,image->columns,1,exception);
754     else
755       q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
756     if (q == (Quantum *) NULL)
757       break;
758
759     for (x=0; x < (ssize_t) image->columns; x++)
760     {
761       SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
762       SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
763       SetPixelRed(image,ScaleCharToQuantum(*p++),q);
764       SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
765       q+=GetPixelChannels(image);
766     }
767
768     if (SyncAuthenticPixels(image,exception) == MagickFalse)
769       break;
770   }
771
772   bitmap->UnlockBits(&bitmap_data);
773   delete bitmap;
774   Gdiplus::GdiplusShutdown(token);
775   return(image);
776 }
777 #  endif /* _MSC_VER */
778 #endif /* MAGICKCORE_EMF_DELEGATE */
779 \f
780 /*
781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782 %                                                                             %
783 %                                                                             %
784 %                                                                             %
785 %   R e g i s t e r E M F I m a g e                                           %
786 %                                                                             %
787 %                                                                             %
788 %                                                                             %
789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 %
791 %  RegisterEMFImage() adds attributes for the EMF image format to
792 %  the list of supported formats.  The attributes include the image format
793 %  tag, a method to read and/or write the format, whether the format
794 %  supports the saving of more than one frame to the same file or blob,
795 %  whether the format supports native in-memory I/O, and a brief
796 %  description of the format.
797 %
798 %  The format of the RegisterEMFImage method is:
799 %
800 %      size_t RegisterEMFImage(void)
801 %
802 */
803 ModuleExport size_t RegisterEMFImage(void)
804 {
805   MagickInfo
806     *entry;
807
808   entry=SetMagickInfo("EMF");
809 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
810   entry->decoder=ReadEMFImage;
811 #endif
812   entry->description=ConstantString(
813     "Windows Enhanced Meta File");
814   entry->magick=(IsImageFormatHandler *) IsEMF;
815   entry->blob_support=MagickFalse;
816   entry->module=ConstantString("WMF");
817   (void) RegisterMagickInfo(entry);
818   entry=SetMagickInfo("WMF");
819 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
820   entry->decoder=ReadEMFImage;
821 #endif
822   entry->description=ConstantString("Windows Meta File");
823   entry->magick=(IsImageFormatHandler *) IsWMF;
824   entry->blob_support=MagickFalse;
825   entry->module=ConstantString("WMF");
826   (void) RegisterMagickInfo(entry);
827   return(MagickImageCoderSignature);
828 }
829 \f
830 /*
831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
832 %                                                                             %
833 %                                                                             %
834 %                                                                             %
835 %   U n r e g i s t e r E M F I m a g e                                       %
836 %                                                                             %
837 %                                                                             %
838 %                                                                             %
839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
840 %
841 %  UnregisterEMFImage() removes format registrations made by the
842 %  EMF module from the list of supported formats.
843 %
844 %  The format of the UnregisterEMFImage method is:
845 %
846 %      UnregisterEMFImage(void)
847 %
848 */
849 ModuleExport void UnregisterEMFImage(void)
850 {
851   (void) UnregisterMagickInfo("EMF");
852   (void) UnregisterMagickInfo("WMF");
853 }