]> granicus.if.org Git - imagemagick/blob - coders/emf.c
(no commit message)
[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 %                                                                             %
19 %  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
20 %  dedicated to making software imaging solutions freely available.           %
21 %                                                                             %
22 %  You may not use this file except in compliance with the License.  You may  %
23 %  obtain a copy of the License at                                            %
24 %                                                                             %
25 %    http://www.imagemagick.org/script/license.php                            %
26 %                                                                             %
27 %  Unless required by applicable law or agreed to in writing, software        %
28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30 %  See the License for the specific language governing permissions and        %
31 %  limitations under the License.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 */
35 \f
36 /*
37  * Include declarations.
38  */
39
40 #include "MagickCore/studio.h"
41 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
42 #  if defined(__CYGWIN__)
43 #    include <windows.h>
44 #  else
45 #    include <wingdi.h>
46 #  endif
47 #endif
48 \f
49 #include "MagickCore/blob.h"
50 #include "MagickCore/blob-private.h"
51 #include "MagickCore/cache.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/image.h"
56 #include "MagickCore/image-private.h"
57 #include "MagickCore/list.h"
58 #include "MagickCore/magick.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/pixel.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/quantum-private.h"
63 #include "MagickCore/static.h"
64 #include "MagickCore/string_.h"
65 #include "MagickCore/module.h"
66 \f
67 /*
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 %                                                                             %
70 %                                                                             %
71 %                                                                             %
72 %   I s E F M                                                                 %
73 %                                                                             %
74 %                                                                             %
75 %                                                                             %
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %
78 %  IsEMF() returns MagickTrue if the image format type, identified by the
79 %  magick string, is a Microsoft Windows Enhanced MetaFile (EMF) file.
80 %
81 %  The format of the ReadEMFImage method is:
82 %
83 %      MagickBooleanType IsEMF(const unsigned char *magick,const size_t length)
84 %
85 %  A description of each parameter follows:
86 %
87 %    o magick: compare image format pattern against these bytes.
88 %
89 %    o length: Specifies the length of the magick string.
90 %
91 */
92 static MagickBooleanType IsEMF(const unsigned char *magick,const size_t length)
93 {
94   if (length < 48)
95     return(MagickFalse);
96   if (memcmp(magick+40,"\040\105\115\106\000\000\001\000",8) == 0)
97     return(MagickTrue);
98   return(MagickFalse);
99 }
100 \f
101 /*
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 %                                                                             %
104 %                                                                             %
105 %                                                                             %
106 %   I s W M F                                                                 %
107 %                                                                             %
108 %                                                                             %
109 %                                                                             %
110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111 %
112 %  IsWMF() returns MagickTrue if the image format type, identified by the
113 %  magick string, is a Windows MetaFile (WMF) file.
114 %
115 %  The format of the ReadEMFImage method is:
116 %
117 %      MagickBooleanType IsEMF(const unsigned char *magick,const size_t length)
118 %
119 %  A description of each parameter follows:
120 %
121 %    o magick: compare image format pattern against these bytes.
122 %
123 %    o length: Specifies the length of the magick string.
124 %
125 */
126 static MagickBooleanType IsWMF(const unsigned char *magick,const size_t length)
127 {
128   if (length < 4)
129     return(MagickFalse);
130   if (memcmp(magick,"\327\315\306\232",4) == 0)
131     return(MagickTrue);
132   if (memcmp(magick,"\001\000\011\000",4) == 0)
133     return(MagickTrue);
134   return(MagickFalse);
135 }
136 \f
137 /*
138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 %                                                                             %
140 %                                                                             %
141 %                                                                             %
142 %  R e a d E M F I m a g e                                                    %
143 %                                                                             %
144 %                                                                             %
145 %                                                                             %
146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147 %
148 %  ReadEMFImage() reads an Microsoft Windows Enhanced MetaFile (EMF) or
149 %  Windows MetaFile (WMF) file using the Windows API and returns it.  It
150 %  allocates the memory necessary for the new Image structure and returns a
151 %  pointer to the new image.
152 %
153 %  The format of the ReadEMFImage method is:
154 %
155 %      Image *ReadEMFImage(const ImageInfo *image_info,
156 %        ExceptionInfo *exception)
157 %
158 %  A description of each parameter follows:
159 %
160 %    o image_info: the image info..
161 %
162 %    o exception: return any errors or warnings in this structure.
163 %
164 */
165
166 /*
167   This method reads either an enhanced metafile, a regular 16bit Windows
168   metafile, or an Aldus Placeable metafile and converts it into an enhanced
169   metafile.  Width and height are returned in .01mm units.
170 */
171 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
172 static HENHMETAFILE ReadEnhMetaFile(const char *path,ssize_t *width,
173   ssize_t *height)
174 {
175 #pragma pack( push, 2 )
176   typedef struct
177   {
178     DWORD dwKey;
179     WORD hmf;
180     SMALL_RECT bbox;
181     WORD wInch;
182     DWORD dwReserved;
183     WORD wCheckSum;
184   } APMHEADER, *PAPMHEADER;
185 #pragma pack( pop )
186
187   DWORD
188     dwSize;
189
190   ENHMETAHEADER
191     emfh;
192
193   HANDLE
194     hFile;
195
196   HDC
197     hDC;
198
199   HENHMETAFILE
200     hTemp;
201
202   LPBYTE
203     pBits;
204
205   METAFILEPICT
206     mp;
207
208   HMETAFILE
209     hOld;
210
211   *width=512;
212   *height=512;
213   hTemp=GetEnhMetaFile(path);
214 #if defined(MAGICKCORE_HAVE__WFOPEN)
215   if (hTemp == (HENHMETAFILE) NULL)
216     {
217       int
218         count;
219
220       wchar_t
221         *unicode_path;
222
223       count=MultiByteToWideChar(CP_ACP,0,path,-1,NULL,0);
224       unicode_path=(wchar_t *) AcquireQuantumMemory(count,
225         sizeof(*unicode_path));
226       if (unicode_path != (wchar_t *) NULL)
227         {
228           hTemp=GetEnhMetaFileW(unicode_path);
229           unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path);
230         }
231     }
232 #endif
233   if (hTemp != (HENHMETAFILE) NULL)
234     {
235       /*
236         Enhanced metafile.
237       */
238       GetEnhMetaFileHeader(hTemp,sizeof(ENHMETAHEADER),&emfh);
239       *width=emfh.rclFrame.right-emfh.rclFrame.left;
240       *height=emfh.rclFrame.bottom-emfh.rclFrame.top;
241       return(hTemp);
242     }
243   hOld=GetMetaFile(path);
244   if (hOld != (HMETAFILE) NULL)
245     {
246       /*
247         16bit windows metafile.
248       */
249       dwSize=GetMetaFileBitsEx(hOld,0,NULL);
250       if (dwSize == 0)
251         {
252           DeleteMetaFile(hOld);
253           return((HENHMETAFILE) NULL);
254         }
255       pBits=(LPBYTE) AcquireQuantumMemory(dwSize,sizeof(*pBits));
256       if (pBits == (LPBYTE) NULL)
257         {
258           DeleteMetaFile(hOld);
259           return((HENHMETAFILE) NULL);
260         }
261       if (GetMetaFileBitsEx(hOld,dwSize,pBits) == 0)
262         {
263           pBits=(BYTE *) DestroyString((char *) pBits);
264           DeleteMetaFile(hOld);
265           return((HENHMETAFILE) NULL);
266         }
267       /*
268         Make an enhanced metafile from the windows metafile.
269       */
270       mp.mm=MM_ANISOTROPIC;
271       mp.xExt=1000;
272       mp.yExt=1000;
273       mp.hMF=NULL;
274       hDC=GetDC(NULL);
275       hTemp=SetWinMetaFileBits(dwSize,pBits,hDC,&mp);
276       ReleaseDC(NULL,hDC);
277       DeleteMetaFile(hOld);
278       pBits=(BYTE *) DestroyString((char *) pBits);
279       GetEnhMetaFileHeader(hTemp,sizeof(ENHMETAHEADER),&emfh);
280       *width=emfh.rclFrame.right-emfh.rclFrame.left;
281       *height=emfh.rclFrame.bottom-emfh.rclFrame.top;
282       return(hTemp);
283     }
284   /*
285     Aldus Placeable metafile.
286   */
287   hFile=CreateFile(path,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,
288     NULL);
289   if (hFile == INVALID_HANDLE_VALUE)
290     return(NULL);
291   dwSize=GetFileSize(hFile,NULL);
292   pBits=(LPBYTE) AcquireQuantumMemory(dwSize,sizeof(*pBits));
293   ReadFile(hFile,pBits,dwSize,&dwSize,NULL);
294   CloseHandle(hFile);
295   if (((PAPMHEADER) pBits)->dwKey != 0x9ac6cdd7l)
296     {
297       pBits=(BYTE *) DestroyString((char *) pBits);
298       return((HENHMETAFILE) NULL);
299     }
300   /*
301     Make an enhanced metafile from the placable metafile.
302   */
303   mp.mm=MM_ANISOTROPIC;
304   mp.xExt=((PAPMHEADER) pBits)->bbox.Right-((PAPMHEADER) pBits)->bbox.Left;
305   *width=mp.xExt;
306   mp.xExt=(mp.xExt*2540l)/(DWORD) (((PAPMHEADER) pBits)->wInch);
307   mp.yExt=((PAPMHEADER)pBits)->bbox.Bottom-((PAPMHEADER) pBits)->bbox.Top;
308   *height=mp.yExt;
309   mp.yExt=(mp.yExt*2540l)/(DWORD) (((PAPMHEADER) pBits)->wInch);
310   mp.hMF=NULL;
311   hDC=GetDC(NULL);
312   hTemp=SetWinMetaFileBits(dwSize,&(pBits[sizeof(APMHEADER)]),hDC,&mp);
313   ReleaseDC(NULL,hDC);
314   pBits=(BYTE *) DestroyString((char *) pBits);
315   return(hTemp);
316 }
317
318 #define CENTIMETERS_INCH 2.54
319
320 static Image *ReadEMFImage(const ImageInfo *image_info,
321   ExceptionInfo *exception)
322 {
323   BITMAPINFO
324     DIBinfo;
325
326   HBITMAP
327     hBitmap,
328     hOldBitmap;
329
330   HDC
331     hDC;
332
333   HENHMETAFILE
334     hemf;
335
336   Image
337     *image;
338
339   RECT
340     rect;
341
342   register ssize_t
343     x;
344
345   register Quantum
346     *q;
347
348   RGBQUAD
349     *pBits,
350     *ppBits;
351
352   ssize_t
353     height,
354     width,
355     y;
356
357   image=AcquireImage(image_info);
358   hemf=ReadEnhMetaFile(image_info->filename,&width,&height);
359   if (hemf == (HENHMETAFILE) NULL)
360     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
361   if ((image->columns == 0) || (image->rows == 0))
362     {
363       double
364         y_resolution,
365         x_resolution;
366
367       y_resolution=DefaultResolution;
368       x_resolution=DefaultResolution;
369       if (image->y_resolution > 0)
370         {
371           y_resolution=image->y_resolution;
372           if (image->units == PixelsPerCentimeterResolution)
373             y_resolution*=CENTIMETERS_INCH;
374         }
375       if (image->x_resolution > 0)
376         {
377           x_resolution=image->x_resolution;
378           if (image->units == PixelsPerCentimeterResolution)
379             x_resolution*=CENTIMETERS_INCH;
380         }
381       image->rows=(size_t) ((height/1000.0/CENTIMETERS_INCH)*y_resolution+0.5);
382       image->columns=(size_t) ((width/1000.0/CENTIMETERS_INCH)*
383         x_resolution+0.5);
384     }
385   if (image_info->size != (char *) NULL)
386     {
387       ssize_t
388         x;
389
390       image->columns=width;
391       image->rows=height;
392       x=0;
393       y=0;
394       (void) GetGeometry(image_info->size,&x,&y,&image->columns,&image->rows);
395     }
396   if (image_info->page != (char *) NULL)
397     {
398       char
399         *geometry;
400
401       register char
402         *p;
403
404       MagickStatusType
405         flags;
406
407       ssize_t
408         sans;
409
410       geometry=GetPageGeometry(image_info->page);
411       p=strchr(geometry,'>');
412       if (p == (char *) NULL)
413         {
414           flags=ParseMetaGeometry(geometry,&sans,&sans,&image->columns,
415             &image->rows);
416           if (image->x_resolution != 0.0)
417             image->columns=(size_t) floor((image->columns*image->x_resolution)+
418               0.5);
419           if (image->y_resolution != 0.0)
420             image->rows=(size_t) floor((image->rows*image->y_resolution)+0.5);
421         }
422       else
423         {
424           *p='\0';
425           flags=ParseMetaGeometry(geometry,&sans,&sans,&image->columns,
426             &image->rows);
427           if (image->x_resolution != 0.0)
428             image->columns=(size_t) floor(((image->columns*image->x_resolution)/
429               DefaultResolution)+0.5);
430           if (image->y_resolution != 0.0)
431             image->rows=(size_t) floor(((image->rows*image->y_resolution)/
432               DefaultResolution)+0.5);
433         }
434       geometry=DestroyString(geometry);
435     }
436   hDC=GetDC(NULL);
437   if (hDC == (HDC) NULL)
438     {
439       DeleteEnhMetaFile(hemf);
440       ThrowReaderException(ResourceLimitError,"UnableToCreateADC");
441     }
442   /*
443     Initialize the bitmap header info.
444   */
445   (void) ResetMagickMemory(&DIBinfo,0,sizeof(BITMAPINFO));
446   DIBinfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
447   DIBinfo.bmiHeader.biWidth=(LONG) image->columns;
448   DIBinfo.bmiHeader.biHeight=(-1)*(LONG) image->rows;
449   DIBinfo.bmiHeader.biPlanes=1;
450   DIBinfo.bmiHeader.biBitCount=32;
451   DIBinfo.bmiHeader.biCompression=BI_RGB;
452   hBitmap=CreateDIBSection(hDC,&DIBinfo,DIB_RGB_COLORS,(void **) &ppBits,NULL,
453     0);
454   ReleaseDC(NULL,hDC);
455   if (hBitmap == (HBITMAP) NULL)
456     {
457       DeleteEnhMetaFile(hemf);
458       ThrowReaderException(ResourceLimitError,"UnableToCreateBitmap");
459     }
460   hDC=CreateCompatibleDC(NULL);
461   if (hDC == (HDC) NULL)
462     {
463       DeleteEnhMetaFile(hemf);
464       DeleteObject(hBitmap);
465       ThrowReaderException(ResourceLimitError,"UnableToCreateADC");
466     }
467   hOldBitmap=(HBITMAP) SelectObject(hDC,hBitmap);
468   if (hOldBitmap == (HBITMAP) NULL)
469     {
470       DeleteEnhMetaFile(hemf);
471       DeleteDC(hDC);
472       DeleteObject(hBitmap);
473       ThrowReaderException(ResourceLimitError,"UnableToCreateBitmap");
474     }
475   /*
476     Initialize the bitmap to the image background color.
477   */
478   pBits=ppBits;
479   for (y=0; y < (ssize_t) image->rows; y++)
480   {
481     for (x=0; x < (ssize_t) image->columns; x++)
482     {
483       pBits->rgbRed=ScaleQuantumToChar(image->background_color.red);
484       pBits->rgbGreen=ScaleQuantumToChar(image->background_color.green);
485       pBits->rgbBlue=ScaleQuantumToChar(image->background_color.blue);
486       pBits++;
487     }
488   }
489   rect.top=0;
490   rect.left=0;
491   rect.right=(LONG) image->columns;
492   rect.bottom=(LONG) image->rows;
493   /*
494     Convert metafile pixels.
495   */
496   PlayEnhMetaFile(hDC,hemf,&rect);
497   pBits=ppBits;
498   for (y=0; y < (ssize_t) image->rows; y++)
499   {
500     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
501     if (q == (const Quantum *) NULL)
502       break;
503     for (x=0; x < (ssize_t) image->columns; x++)
504     {
505       SetPixelRed(image,ScaleCharToQuantum(pBits->rgbRed),q);
506       SetPixelGreen(image,ScaleCharToQuantum(pBits->rgbGreen),q);
507       SetPixelBlue(image,ScaleCharToQuantum(pBits->rgbBlue),q);
508       SetPixelAlpha(image,OpaqueAlpha,q);
509       pBits++;
510       q+=GetPixelChannels(image);
511     }
512     if (SyncAuthenticPixels(image,exception) == MagickFalse)
513       break;
514   }
515   DeleteEnhMetaFile(hemf);
516   SelectObject(hDC,hOldBitmap);
517   DeleteDC(hDC);
518   DeleteObject(hBitmap);
519   return(GetFirstImageInList(image));
520 }
521 #endif /* MAGICKCORE_WINGDI32_DELEGATE */
522 \f
523 /*
524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525 %                                                                             %
526 %                                                                             %
527 %                                                                             %
528 %   R e g i s t e r E M F I m a g e                                           %
529 %                                                                             %
530 %                                                                             %
531 %                                                                             %
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533 %
534 %  RegisterEMFImage() adds attributes for the EMF image format to
535 %  the list of supported formats.  The attributes include the image format
536 %  tag, a method to read and/or write the format, whether the format
537 %  supports the saving of more than one frame to the same file or blob,
538 %  whether the format supports native in-memory I/O, and a brief
539 %  description of the format.
540 %
541 %  The format of the RegisterEMFImage method is:
542 %
543 %      size_t RegisterEMFImage(void)
544 %
545 */
546 ModuleExport size_t RegisterEMFImage(void)
547 {
548   MagickInfo
549     *entry;
550
551   entry=SetMagickInfo("EMF");
552 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
553   entry->decoder=ReadEMFImage;
554 #endif
555   entry->description=ConstantString(
556     "Windows WIN32 API rendered Enhanced Meta File");
557   entry->magick=(IsImageFormatHandler *) IsEMF;
558   entry->blob_support=MagickFalse;
559   entry->module=ConstantString("WMF");
560   (void) RegisterMagickInfo(entry);
561   entry=SetMagickInfo("WMFWIN32");
562 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
563   entry->decoder=ReadEMFImage;
564 #endif
565   entry->description=ConstantString("Windows WIN32 API rendered Meta File");
566   entry->magick=(IsImageFormatHandler *) IsWMF;
567   entry->blob_support=MagickFalse;
568   entry->module=ConstantString("WMFWIN32");
569   (void) RegisterMagickInfo(entry);
570   return(MagickImageCoderSignature);
571 }
572 \f
573 /*
574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575 %                                                                             %
576 %                                                                             %
577 %                                                                             %
578 %   U n r e g i s t e r E M F I m a g e                                       %
579 %                                                                             %
580 %                                                                             %
581 %                                                                             %
582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
583 %
584 %  UnregisterEMFImage() removes format registrations made by the
585 %  EMF module from the list of supported formats.
586 %
587 %  The format of the UnregisterEMFImage method is:
588 %
589 %      UnregisterEMFImage(void)
590 %
591 */
592 ModuleExport void UnregisterEMFImage(void)
593 {
594   (void) UnregisterMagickInfo("EMF");
595   (void) UnregisterMagickInfo("WMFWIN32");
596 }