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