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
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
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 */
IsEMF(const unsigned char * magick,const size_t length)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
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 */
IsWMF(const unsigned char * magick,const size_t length)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
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)
UTF8ToUTF16(const unsigned char * utf8,wchar_t * utf16)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
ConvertUTF8ToUTF16(const unsigned char * source)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
ReadEnhMetaFile(const char * path,ssize_t * width,ssize_t * height)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 ReadFile(hFile,pBits,dwSize,&dwSize,NULL);
412 CloseHandle(hFile);
413 if (((PAPMHEADER) pBits)->dwKey != 0x9ac6cdd7l)
414 {
415 pBits=(BYTE *) DestroyString((char *) pBits);
416 return((HENHMETAFILE) NULL);
417 }
418 /*
419 Make an enhanced metafile from the placable metafile.
420 */
421 mp.mm=MM_ANISOTROPIC;
422 mp.xExt=((PAPMHEADER) pBits)->bbox.Right-((PAPMHEADER) pBits)->bbox.Left;
423 *width=mp.xExt;
424 mp.xExt=(mp.xExt*2540l)/(DWORD) (((PAPMHEADER) pBits)->wInch);
425 mp.yExt=((PAPMHEADER)pBits)->bbox.Bottom-((PAPMHEADER) pBits)->bbox.Top;
426 *height=mp.yExt;
427 mp.yExt=(mp.yExt*2540l)/(DWORD) (((PAPMHEADER) pBits)->wInch);
428 mp.hMF=NULL;
429 hDC=GetDC(NULL);
430 hTemp=SetWinMetaFileBits(dwSize,&(pBits[sizeof(APMHEADER)]),hDC,&mp);
431 ReleaseDC(NULL,hDC);
432 pBits=(BYTE *) DestroyString((char *) pBits);
433 return(hTemp);
434 }
435
436 #define CENTIMETERS_INCH 2.54
437
ReadEMFImage(const ImageInfo * image_info,ExceptionInfo * exception)438 static Image *ReadEMFImage(const ImageInfo *image_info,ExceptionInfo *exception)
439 {
440 BITMAPINFO
441 DIBinfo;
442
443 HBITMAP
444 hBitmap,
445 hOldBitmap;
446
447 HDC
448 hDC;
449
450 HENHMETAFILE
451 hemf;
452
453 Image
454 *image;
455
456 MagickBooleanType
457 status;
458
459 RECT
460 rect;
461
462 register ssize_t
463 x;
464
465 register Quantum
466 *q;
467
468 RGBQUAD
469 *pBits,
470 *ppBits;
471
472 ssize_t
473 height,
474 width,
475 y;
476
477 image=AcquireImage(image_info,exception);
478 hemf=ReadEnhMetaFile(image_info->filename,&width,&height);
479 if (hemf == (HENHMETAFILE) NULL)
480 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
481 if ((image->columns == 0) || (image->rows == 0))
482 {
483 double
484 y_resolution,
485 x_resolution;
486
487 y_resolution=DefaultResolution;
488 x_resolution=DefaultResolution;
489 if (image->resolution.y > 0)
490 {
491 y_resolution=image->resolution.y;
492 if (image->units == PixelsPerCentimeterResolution)
493 y_resolution*=CENTIMETERS_INCH;
494 }
495 if (image->resolution.x > 0)
496 {
497 x_resolution=image->resolution.x;
498 if (image->units == PixelsPerCentimeterResolution)
499 x_resolution*=CENTIMETERS_INCH;
500 }
501 image->rows=(size_t) ((height/1000.0/CENTIMETERS_INCH)*y_resolution+0.5);
502 image->columns=(size_t) ((width/1000.0/CENTIMETERS_INCH)*
503 x_resolution+0.5);
504 }
505 if (image_info->size != (char *) NULL)
506 {
507 image->columns=width;
508 image->rows=height;
509 (void) GetGeometry(image_info->size,(ssize_t *) NULL,(ssize_t *) NULL,
510 &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
EMFSetDimensions(Image * image,Gdiplus::Image * source)643 static inline void EMFSetDimensions(Image * image,Gdiplus::Image *source)
644 {
645 if ((image->resolution.x <= 0.0) || (image->resolution.y <= 0.0))
646 return;
647
648 image->columns=(size_t) floor((Gdiplus::REAL) source->GetWidth()/
649 source->GetHorizontalResolution()*image->resolution.x+0.5);
650 image->rows=(size_t)floor((Gdiplus::REAL) source->GetHeight()/
651 source->GetVerticalResolution()*image->resolution.y+0.5);
652 }
653
ReadEMFImage(const ImageInfo * image_info,ExceptionInfo * exception)654 static Image *ReadEMFImage(const ImageInfo *image_info,
655 ExceptionInfo *exception)
656 {
657 Gdiplus::Bitmap
658 *bitmap;
659
660 Gdiplus::BitmapData
661 bitmap_data;
662
663 Gdiplus::GdiplusStartupInput
664 startup_input;
665
666 Gdiplus::Graphics
667 *graphics;
668
669 Gdiplus::Image
670 *source;
671
672 Gdiplus::Rect
673 rect;
674
675 GeometryInfo
676 geometry_info;
677
678 Image
679 *image;
680
681 MagickStatusType
682 flags;
683
684 register Quantum
685 *q;
686
687 register ssize_t
688 x;
689
690 ssize_t
691 y;
692
693 ULONG_PTR
694 token;
695
696 unsigned char
697 *p;
698
699 wchar_t
700 fileName[MagickPathExtent];
701
702 assert(image_info != (const ImageInfo *) NULL);
703 assert(image_info->signature == MagickCoreSignature);
704 if (image_info->debug != MagickFalse)
705 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
706 image_info->filename);
707 assert(exception != (ExceptionInfo *) NULL);
708
709 image=AcquireImage(image_info,exception);
710 if (Gdiplus::GdiplusStartup(&token,&startup_input,NULL) !=
711 Gdiplus::Status::Ok)
712 ThrowReaderException(CoderError, "GdiplusStartupFailed");
713 MultiByteToWideChar(CP_UTF8,0,image->filename,-1,fileName,MagickPathExtent);
714 source=Gdiplus::Image::FromFile(fileName);
715 if (source == (Gdiplus::Image *) NULL)
716 {
717 Gdiplus::GdiplusShutdown(token);
718 ThrowReaderException(FileOpenError,"UnableToOpenFile");
719 }
720
721 image->resolution.x=source->GetHorizontalResolution();
722 image->resolution.y=source->GetVerticalResolution();
723 image->columns=(size_t) source->GetWidth();
724 image->rows=(size_t) source->GetHeight();
725 if (image_info->size != (char *) NULL)
726 {
727 (void) GetGeometry(image_info->size,(ssize_t *) NULL,(ssize_t *) NULL,
728 &image->columns,&image->rows);
729 image->resolution.x=source->GetHorizontalResolution()*image->columns/
730 source->GetWidth();
731 image->resolution.y=source->GetVerticalResolution()*image->rows/
732 source->GetHeight();
733 if (image->resolution.x == 0)
734 image->resolution.x=image->resolution.y;
735 else if (image->resolution.y == 0)
736 image->resolution.y=image->resolution.x;
737 else
738 image->resolution.x=image->resolution.y=MagickMin(
739 image->resolution.x,image->resolution.y);
740 EMFSetDimensions(image,source);
741 }
742 else 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 EMFSetDimensions(image,source);
750 }
751 if (SetImageExtent(image,image->columns,image->rows,exception) == MagickFalse)
752 {
753 delete source;
754 Gdiplus::GdiplusShutdown(token);
755 return(DestroyImageList(image));
756 }
757 image->alpha_trait=BlendPixelTrait;
758 if (image->ping != MagickFalse)
759 {
760 delete source;
761 Gdiplus::GdiplusShutdown(token);
762 return(image);
763 }
764
765 bitmap=new Gdiplus::Bitmap((INT) image->columns,(INT) image->rows,
766 PixelFormat32bppARGB);
767 graphics=Gdiplus::Graphics::FromImage(bitmap);
768 graphics->SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
769 graphics->SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
770 graphics->SetTextRenderingHint(Gdiplus::TextRenderingHintClearTypeGridFit);
771 graphics->Clear(Gdiplus::Color((BYTE) ScaleQuantumToChar(
772 image->background_color.alpha),(BYTE) ScaleQuantumToChar(
773 image->background_color.red),(BYTE) ScaleQuantumToChar(
774 image->background_color.green),(BYTE) ScaleQuantumToChar(
775 image->background_color.blue)));
776 graphics->DrawImage(source,0,0,(INT) image->columns,(INT) image->rows);
777 delete graphics;
778 delete source;
779
780 rect=Gdiplus::Rect(0,0,(INT) image->columns,(INT) image->rows);
781 if (bitmap->LockBits(&rect,Gdiplus::ImageLockModeRead,PixelFormat32bppARGB,
782 &bitmap_data) != Gdiplus::Ok)
783 {
784 delete bitmap;
785 Gdiplus::GdiplusShutdown(token);
786 ThrowReaderException(FileOpenError,"UnableToReadImageData");
787 }
788
789 for (y=0; y < (ssize_t) image->rows; y++)
790 {
791 p=(unsigned char *) bitmap_data.Scan0+(y*abs(bitmap_data.Stride));
792 if (bitmap_data.Stride < 0)
793 q=GetAuthenticPixels(image,0,image->rows-y-1,image->columns,1,exception);
794 else
795 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
796 if (q == (Quantum *) NULL)
797 break;
798
799 for (x=0; x < (ssize_t) image->columns; x++)
800 {
801 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
802 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
803 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
804 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
805 q+=GetPixelChannels(image);
806 }
807
808 if (SyncAuthenticPixels(image,exception) == MagickFalse)
809 break;
810 }
811
812 bitmap->UnlockBits(&bitmap_data);
813 delete bitmap;
814 Gdiplus::GdiplusShutdown(token);
815 return(image);
816 }
817 # endif /* _MSC_VER */
818 #endif /* MAGICKCORE_EMF_DELEGATE */
819
820 /*
821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
822 % %
823 % %
824 % %
825 % R e g i s t e r E M F I m a g e %
826 % %
827 % %
828 % %
829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
830 %
831 % RegisterEMFImage() adds attributes for the EMF image format to
832 % the list of supported formats. The attributes include the image format
833 % tag, a method to read and/or write the format, whether the format
834 % supports the saving of more than one frame to the same file or blob,
835 % whether the format supports native in-memory I/O, and a brief
836 % description of the format.
837 %
838 % The format of the RegisterEMFImage method is:
839 %
840 % size_t RegisterEMFImage(void)
841 %
842 */
RegisterEMFImage(void)843 ModuleExport size_t RegisterEMFImage(void)
844 {
845 MagickInfo
846 *entry;
847
848 entry=AcquireMagickInfo("EMF","EMF","Windows Enhanced Meta File");
849 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
850 entry->decoder=ReadEMFImage;
851 #endif
852 entry->magick=(IsImageFormatHandler *) IsEMF;
853 entry->flags^=CoderBlobSupportFlag;
854 (void) RegisterMagickInfo(entry);
855 entry=AcquireMagickInfo("EMF","WMF","Windows Meta File");
856 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
857 entry->decoder=ReadEMFImage;
858 #endif
859 entry->magick=(IsImageFormatHandler *) IsWMF;
860 entry->flags^=CoderBlobSupportFlag;
861 (void) RegisterMagickInfo(entry);
862 return(MagickImageCoderSignature);
863 }
864
865 /*
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 % %
868 % %
869 % %
870 % U n r e g i s t e r E M F I m a g e %
871 % %
872 % %
873 % %
874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875 %
876 % UnregisterEMFImage() removes format registrations made by the
877 % EMF module from the list of supported formats.
878 %
879 % The format of the UnregisterEMFImage method is:
880 %
881 % UnregisterEMFImage(void)
882 %
883 */
UnregisterEMFImage(void)884 ModuleExport void UnregisterEMFImage(void)
885 {
886 (void) UnregisterMagickInfo("EMF");
887 (void) UnregisterMagickInfo("WMF");
888 }
889