1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            X   X  W   W  DDDD                               %
7 %                             X X   W   W  D   D                              %
8 %                              X    W   W  D   D                              %
9 %                             X X   W W W  D   D                              %
10 %                            X   X   W W   DDDD                               %
11 %                                                                             %
12 %                                                                             %
13 %                Read/Write X Windows System Window Dump Format               %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color-private.h"
48 #include "MagickCore/colormap.h"
49 #include "MagickCore/colormap-private.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/property.h"
63 #include "MagickCore/quantum-private.h"
64 #include "MagickCore/static.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/module.h"
67 #if defined(MAGICKCORE_X11_DELEGATE)
68 #include "MagickCore/xwindow-private.h"
69 #if !defined(vms)
70 #include <X11/XWDFile.h>
71 #else
72 #include "XWDFile.h"
73 #endif
74 #endif
75 
76 /*
77   Forward declarations.
78 */
79 #if defined(MAGICKCORE_X11_DELEGATE)
80 static MagickBooleanType
81   WriteXWDImage(const ImageInfo *,Image *,ExceptionInfo *);
82 #endif
83 
84 /*
85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 %                                                                             %
87 %                                                                             %
88 %                                                                             %
89 %   I s X W D                                                                 %
90 %                                                                             %
91 %                                                                             %
92 %                                                                             %
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 %
95 %  IsXWD() returns MagickTrue if the image format type, identified by the
96 %  magick string, is XWD.
97 %
98 %  The format of the IsXWD method is:
99 %
100 %      MagickBooleanType IsXWD(const unsigned char *magick,const size_t length)
101 %
102 %  A description of each parameter follows:
103 %
104 %    o magick: compare image format pattern against these bytes.
105 %
106 %    o length: Specifies the length of the magick string.
107 %
108 */
IsXWD(const unsigned char * magick,const size_t length)109 static MagickBooleanType IsXWD(const unsigned char *magick,const size_t length)
110 {
111   if (length < 8)
112     return(MagickFalse);
113   if (memcmp(magick+1,"\000\000",2) == 0)
114     {
115       if (memcmp(magick+4,"\007\000\000",3) == 0)
116         return(MagickTrue);
117       if (memcmp(magick+5,"\000\000\007",3) == 0)
118         return(MagickTrue);
119     }
120   return(MagickFalse);
121 }
122 
123 #if defined(MAGICKCORE_X11_DELEGATE)
124 /*
125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 %                                                                             %
127 %                                                                             %
128 %                                                                             %
129 %   R e a d X W D I m a g e                                                   %
130 %                                                                             %
131 %                                                                             %
132 %                                                                             %
133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134 %
135 %  ReadXWDImage() reads an X Window System window dump image file and
136 %  returns it.  It allocates the memory necessary for the new Image structure
137 %  and returns a pointer to the new image.
138 %
139 %  The format of the ReadXWDImage method is:
140 %
141 %      Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
142 %
143 %  A description of each parameter follows:
144 %
145 %    o image_info: the image info.
146 %
147 %    o exception: return any errors or warnings in this structure.
148 %
149 */
150 
ReadXWDImage(const ImageInfo * image_info,ExceptionInfo * exception)151 static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
152 {
153 #define CheckOverflowException(length,width,height) \
154   (((height) != 0) && ((length)/((size_t) height) != ((size_t) width)))
155 
156   char
157     *comment;
158 
159   Image
160     *image;
161 
162   int
163     x_status;
164 
165   MagickBooleanType
166     authentic_colormap;
167 
168   MagickStatusType
169     status;
170 
171   Quantum
172     index;
173 
174   ssize_t
175     x;
176 
177   Quantum
178     *q;
179 
180   ssize_t
181     i;
182 
183   size_t
184     pixel;
185 
186   size_t
187     length;
188 
189   ssize_t
190     count,
191     y;
192 
193   unsigned long
194     lsb_first;
195 
196   XColor
197     *colors;
198 
199   XImage
200     *ximage;
201 
202   XWDFileHeader
203     header;
204 
205   /*
206     Open image file.
207   */
208   assert(image_info != (const ImageInfo *) NULL);
209   assert(image_info->signature == MagickCoreSignature);
210   if (image_info->debug != MagickFalse)
211     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
212       image_info->filename);
213   assert(exception != (ExceptionInfo *) NULL);
214   assert(exception->signature == MagickCoreSignature);
215   image=AcquireImage(image_info,exception);
216   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
217   if (status == MagickFalse)
218     {
219       image=DestroyImageList(image);
220       return((Image *) NULL);
221     }
222   /*
223      Read in header information.
224   */
225   count=ReadBlob(image,sz_XWDheader,(unsigned char *) &header);
226   if (count != sz_XWDheader)
227     ThrowReaderException(CorruptImageError,"UnableToReadImageHeader");
228   /*
229     Ensure the header byte-order is most-significant byte first.
230   */
231   lsb_first=1;
232   if ((int) (*(char *) &lsb_first) != 0)
233     MSBOrderLong((unsigned char *) &header,sz_XWDheader);
234   /*
235     Check to see if the dump file is in the proper format.
236   */
237   if (header.file_version != XWD_FILE_VERSION)
238     ThrowReaderException(CorruptImageError,"FileFormatVersionMismatch");
239   if (header.header_size < sz_XWDheader)
240     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
241   if (header.xoffset >= header.pixmap_width)
242     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
243   switch (header.visual_class)
244   {
245     case StaticGray:
246     case GrayScale:
247     {
248       if (header.bits_per_pixel != 1)
249         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
250       break;
251     }
252     case StaticColor:
253     case PseudoColor:
254     {
255       if ((header.bits_per_pixel < 1) || (header.bits_per_pixel > 15) ||
256           (header.colormap_entries == 0))
257         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
258       break;
259     }
260     case TrueColor:
261     case DirectColor:
262     {
263       if ((header.bits_per_pixel != 16) && (header.bits_per_pixel != 24) &&
264           (header.bits_per_pixel != 32))
265         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
266       break;
267     }
268     default:
269       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
270   }
271   switch (header.pixmap_format)
272   {
273     case XYBitmap:
274     {
275       if (header.pixmap_depth != 1)
276         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
277       break;
278     }
279     case XYPixmap:
280     case ZPixmap:
281     {
282       if ((header.pixmap_depth < 1) || (header.pixmap_depth > 32))
283         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
284       switch (header.bitmap_pad)
285       {
286         case 8:
287         case 16:
288         case 32:
289           break;
290         default:
291           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
292       }
293       break;
294     }
295     default:
296       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
297   }
298   switch (header.bitmap_unit)
299   {
300     case 8:
301     case 16:
302     case 32:
303       break;
304     default:
305       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
306   }
307   switch (header.byte_order)
308   {
309     case LSBFirst:
310     case MSBFirst:
311       break;
312     default:
313       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
314   }
315   switch (header.bitmap_bit_order)
316   {
317     case LSBFirst:
318     case MSBFirst:
319       break;
320     default:
321       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
322   }
323   if (((header.bitmap_pad % 8) != 0) || (header.bitmap_pad > 32))
324     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
325   length=(size_t) (header.header_size-sz_XWDheader);
326   comment=(char *) AcquireQuantumMemory(length+1,sizeof(*comment));
327   if (comment == (char *) NULL)
328     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
329   count=ReadBlob(image,length,(unsigned char *) comment);
330   comment[length]='\0';
331   (void) SetImageProperty(image,"comment",comment,exception);
332   comment=DestroyString(comment);
333   if (count != (ssize_t) length)
334     ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
335   /*
336     Initialize the X image.
337   */
338   ximage=(XImage *) AcquireMagickMemory(sizeof(*ximage));
339   if (ximage == (XImage *) NULL)
340     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
341   ximage->depth=(int) header.pixmap_depth;
342   ximage->format=(int) header.pixmap_format;
343   ximage->xoffset=(int) header.xoffset;
344   ximage->data=(char *) NULL;
345   ximage->width=(int) header.pixmap_width;
346   ximage->height=(int) header.pixmap_height;
347   ximage->bitmap_pad=(int) header.bitmap_pad;
348   ximage->bytes_per_line=(int) header.bytes_per_line;
349   ximage->byte_order=(int) header.byte_order;
350   ximage->bitmap_unit=(int) header.bitmap_unit;
351   ximage->bitmap_bit_order=(int) header.bitmap_bit_order;
352   ximage->bits_per_pixel=(int) header.bits_per_pixel;
353   ximage->red_mask=header.red_mask;
354   ximage->green_mask=header.green_mask;
355   ximage->blue_mask=header.blue_mask;
356   if ((ximage->depth < 0) || (ximage->format < 0) || (ximage->xoffset < 0) ||
357       (ximage->width < 0) || (ximage->height < 0) || (ximage->bitmap_pad < 0) ||
358       (ximage->bytes_per_line < 0) || (ximage->byte_order < 0) ||
359       (ximage->bitmap_unit < 0) || (ximage->bitmap_bit_order < 0) ||
360       (ximage->bits_per_pixel < 0))
361     {
362       ximage=(XImage *) RelinquishMagickMemory(ximage);
363       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
364     }
365   if ((ximage->width > 65535) || (ximage->height > 65535))
366     {
367       ximage=(XImage *) RelinquishMagickMemory(ximage);
368       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
369     }
370   if ((ximage->bits_per_pixel > 32) || (ximage->bitmap_unit > 32))
371     {
372       ximage=(XImage *) RelinquishMagickMemory(ximage);
373       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
374     }
375   x_status=XInitImage(ximage);
376   if (x_status == 0)
377     {
378       ximage=(XImage *) RelinquishMagickMemory(ximage);
379       ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
380     }
381   /*
382     Read colormap.
383   */
384   authentic_colormap=MagickFalse;
385   colors=(XColor *) NULL;
386   if (header.ncolors != 0)
387     {
388       XWDColor
389         color;
390 
391       length=(size_t) header.ncolors;
392       if (length > ((~0UL)/sizeof(*colors)))
393         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
394       colors=(XColor *) AcquireQuantumMemory(length,sizeof(*colors));
395       if (colors == (XColor *) NULL)
396         {
397           ximage=(XImage *) RelinquishMagickMemory(ximage);
398           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
399         }
400       for (i=0; i < (ssize_t) header.ncolors; i++)
401       {
402         count=ReadBlob(image,sz_XWDColor,(unsigned char *) &color);
403         if (count != sz_XWDColor)
404           {
405             colors=(XColor *) RelinquishMagickMemory(colors);
406             ximage=(XImage *) RelinquishMagickMemory(ximage);
407             ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
408           }
409         colors[i].pixel=color.pixel;
410         colors[i].red=color.red;
411         colors[i].green=color.green;
412         colors[i].blue=color.blue;
413         colors[i].flags=(char) color.flags;
414         if (color.flags != 0)
415           authentic_colormap=MagickTrue;
416       }
417       /*
418         Ensure the header byte-order is most-significant byte first.
419       */
420       lsb_first=1;
421       if ((int) (*(char *) &lsb_first) != 0)
422         for (i=0; i < (ssize_t) header.ncolors; i++)
423         {
424           MSBOrderLong((unsigned char *) &colors[i].pixel,
425             sizeof(colors[i].pixel));
426           MSBOrderShort((unsigned char *) &colors[i].red,3*
427             sizeof(colors[i].red));
428         }
429     }
430   /*
431     Allocate the pixel buffer.
432   */
433   length=(size_t) ximage->bytes_per_line*ximage->height;
434   if (CheckOverflowException(length,ximage->bytes_per_line,ximage->height))
435     {
436       if (header.ncolors != 0)
437         colors=(XColor *) RelinquishMagickMemory(colors);
438       ximage=(XImage *) RelinquishMagickMemory(ximage);
439       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
440     }
441   if (ximage->format != ZPixmap)
442     {
443       size_t
444         extent;
445 
446       extent=length;
447       length*=ximage->depth;
448       if (CheckOverflowException(length,extent,ximage->depth))
449         {
450           if (header.ncolors != 0)
451             colors=(XColor *) RelinquishMagickMemory(colors);
452           ximage=(XImage *) RelinquishMagickMemory(ximage);
453           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
454         }
455     }
456   ximage->data=(char *) AcquireQuantumMemory(length,sizeof(*ximage->data));
457   if (ximage->data == (char *) NULL)
458     {
459       if (header.ncolors != 0)
460         colors=(XColor *) RelinquishMagickMemory(colors);
461       ximage=(XImage *) RelinquishMagickMemory(ximage);
462       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
463     }
464   count=ReadBlob(image,length,(unsigned char *) ximage->data);
465   if (count != (ssize_t) length)
466     {
467       if (header.ncolors != 0)
468         colors=(XColor *) RelinquishMagickMemory(colors);
469       ximage->data=DestroyString(ximage->data);
470       ximage=(XImage *) RelinquishMagickMemory(ximage);
471       ThrowReaderException(CorruptImageError,"UnableToReadImageData");
472     }
473   /*
474     Convert image to MIFF format.
475   */
476   image->columns=(size_t) ximage->width;
477   image->rows=(size_t) ximage->height;
478   image->depth=8;
479   status=SetImageExtent(image,image->columns,image->rows,exception);
480   if (status == MagickFalse)
481     {
482       if (header.ncolors != 0)
483         colors=(XColor *) RelinquishMagickMemory(colors);
484       ximage->data=DestroyString(ximage->data);
485       ximage=(XImage *) RelinquishMagickMemory(ximage);
486       return(DestroyImageList(image));
487     }
488   if ((header.ncolors == 0U) || (ximage->red_mask != 0) ||
489       (ximage->green_mask != 0) || (ximage->blue_mask != 0))
490     image->storage_class=DirectClass;
491   else
492     image->storage_class=PseudoClass;
493   image->colors=header.ncolors;
494   if (image_info->ping == MagickFalse)
495     switch (image->storage_class)
496     {
497       case DirectClass:
498       default:
499       {
500         size_t
501           color;
502 
503         size_t
504           blue_mask,
505           blue_shift,
506           green_mask,
507           green_shift,
508           red_mask,
509           red_shift;
510 
511         /*
512           Determine shift and mask for red, green, and blue.
513         */
514         red_mask=ximage->red_mask;
515         red_shift=0;
516         while ((red_mask != 0) && ((red_mask & 0x01) == 0))
517         {
518           red_mask>>=1;
519           red_shift++;
520         }
521         green_mask=ximage->green_mask;
522         green_shift=0;
523         while ((green_mask != 0) && ((green_mask & 0x01) == 0))
524         {
525           green_mask>>=1;
526           green_shift++;
527         }
528         blue_mask=ximage->blue_mask;
529         blue_shift=0;
530         while ((blue_mask != 0) && ((blue_mask & 0x01) == 0))
531         {
532           blue_mask>>=1;
533           blue_shift++;
534         }
535         /*
536           Convert X image to DirectClass packets.
537         */
538         if ((image->colors != 0) && (authentic_colormap != MagickFalse))
539           for (y=0; y < (ssize_t) image->rows; y++)
540           {
541             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
542             if (q == (Quantum *) NULL)
543               break;
544             for (x=0; x < (ssize_t) image->columns; x++)
545             {
546               pixel=XGetPixel(ximage,(int) x,(int) y);
547               index=(Quantum) ConstrainColormapIndex(image,(ssize_t) (pixel >>
548                 red_shift) & red_mask,exception);
549               SetPixelRed(image,ScaleShortToQuantum(
550                 colors[(ssize_t) index].red),q);
551               index=(Quantum) ConstrainColormapIndex(image,(ssize_t) (pixel >>
552                 green_shift) & green_mask,exception);
553               SetPixelGreen(image,ScaleShortToQuantum(
554                 colors[(ssize_t) index].green),q);
555               index=(Quantum) ConstrainColormapIndex(image,(ssize_t) (pixel >>
556                 blue_shift) & blue_mask,exception);
557               SetPixelBlue(image,ScaleShortToQuantum(
558                 colors[(ssize_t) index].blue),q);
559               q+=GetPixelChannels(image);
560             }
561             if (SyncAuthenticPixels(image,exception) == MagickFalse)
562               break;
563             status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
564               image->rows);
565             if (status == MagickFalse)
566               break;
567           }
568         else
569           for (y=0; y < (ssize_t) image->rows; y++)
570           {
571             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
572             if (q == (Quantum *) NULL)
573               break;
574             for (x=0; x < (ssize_t) image->columns; x++)
575             {
576               pixel=XGetPixel(ximage,(int) x,(int) y);
577               color=(pixel >> red_shift) & red_mask;
578               if (red_mask != 0)
579                 color=(color*65535UL)/red_mask;
580               SetPixelRed(image,ScaleShortToQuantum((unsigned short) color),q);
581               color=(pixel >> green_shift) & green_mask;
582               if (green_mask != 0)
583                 color=(color*65535UL)/green_mask;
584               SetPixelGreen(image,ScaleShortToQuantum((unsigned short) color),
585                 q);
586               color=(pixel >> blue_shift) & blue_mask;
587               if (blue_mask != 0)
588                 color=(color*65535UL)/blue_mask;
589               SetPixelBlue(image,ScaleShortToQuantum((unsigned short) color),q);
590               q+=GetPixelChannels(image);
591             }
592             if (SyncAuthenticPixels(image,exception) == MagickFalse)
593               break;
594             status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
595               image->rows);
596             if (status == MagickFalse)
597               break;
598           }
599         break;
600       }
601       case PseudoClass:
602       {
603         /*
604           Convert X image to PseudoClass packets.
605         */
606         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
607           {
608             if (header.ncolors != 0)
609               colors=(XColor *) RelinquishMagickMemory(colors);
610             ximage->data=DestroyString(ximage->data);
611             ximage=(XImage *) RelinquishMagickMemory(ximage);
612             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
613           }
614         for (i=0; i < (ssize_t) image->colors; i++)
615         {
616           image->colormap[i].red=(MagickRealType) ScaleShortToQuantum(
617             colors[i].red);
618           image->colormap[i].green=(MagickRealType) ScaleShortToQuantum(
619             colors[i].green);
620           image->colormap[i].blue=(MagickRealType) ScaleShortToQuantum(
621             colors[i].blue);
622         }
623         for (y=0; y < (ssize_t) image->rows; y++)
624         {
625           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
626           if (q == (Quantum *) NULL)
627             break;
628           for (x=0; x < (ssize_t) image->columns; x++)
629           {
630             index=(Quantum) ConstrainColormapIndex(image,(ssize_t)
631               XGetPixel(ximage,(int) x,(int) y),exception);
632             SetPixelIndex(image,index,q);
633             SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
634             q+=GetPixelChannels(image);
635           }
636           if (SyncAuthenticPixels(image,exception) == MagickFalse)
637             break;
638           status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
639             image->rows);
640           if (status == MagickFalse)
641             break;
642         }
643         break;
644       }
645     }
646   /*
647     Free image and colormap.
648   */
649   if (header.ncolors != 0)
650     colors=(XColor *) RelinquishMagickMemory(colors);
651   ximage->data=DestroyString(ximage->data);
652   ximage=(XImage *) RelinquishMagickMemory(ximage);
653   if (EOFBlob(image) != MagickFalse)
654     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
655       image->filename);
656   (void) CloseBlob(image);
657   return(GetFirstImageInList(image));
658 }
659 #endif
660 
661 /*
662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663 %                                                                             %
664 %                                                                             %
665 %                                                                             %
666 %   R e g i s t e r X W D I m a g e                                           %
667 %                                                                             %
668 %                                                                             %
669 %                                                                             %
670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671 %
672 %  RegisterXWDImage() adds properties for the XWD image format to
673 %  the list of supported formats.  The properties include the image format
674 %  tag, a method to read and/or write the format, whether the format
675 %  supports the saving of more than one frame to the same file or blob,
676 %  whether the format supports native in-memory I/O, and a brief
677 %  description of the format.
678 %
679 %  The format of the RegisterXWDImage method is:
680 %
681 %      size_t RegisterXWDImage(void)
682 %
683 */
RegisterXWDImage(void)684 ModuleExport size_t RegisterXWDImage(void)
685 {
686   MagickInfo
687     *entry;
688 
689   entry=AcquireMagickInfo("XWD","XWD","X Windows system window dump (color)");
690 #if defined(MAGICKCORE_X11_DELEGATE)
691   entry->decoder=(DecodeImageHandler *) ReadXWDImage;
692   entry->encoder=(EncodeImageHandler *) WriteXWDImage;
693 #endif
694   entry->magick=(IsImageFormatHandler *) IsXWD;
695   entry->flags^=CoderAdjoinFlag;
696   (void) RegisterMagickInfo(entry);
697   return(MagickImageCoderSignature);
698 }
699 
700 /*
701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
702 %                                                                             %
703 %                                                                             %
704 %                                                                             %
705 %   U n r e g i s t e r X W D I m a g e                                       %
706 %                                                                             %
707 %                                                                             %
708 %                                                                             %
709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710 %
711 %  UnregisterXWDImage() removes format registrations made by the
712 %  XWD module from the list of supported formats.
713 %
714 %  The format of the UnregisterXWDImage method is:
715 %
716 %      UnregisterXWDImage(void)
717 %
718 */
UnregisterXWDImage(void)719 ModuleExport void UnregisterXWDImage(void)
720 {
721   (void) UnregisterMagickInfo("XWD");
722 }
723 
724 #if defined(MAGICKCORE_X11_DELEGATE)
725 /*
726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727 %                                                                             %
728 %                                                                             %
729 %                                                                             %
730 %   W r i t e X W D I m a g e                                                 %
731 %                                                                             %
732 %                                                                             %
733 %                                                                             %
734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
735 %
736 %  WriteXWDImage() writes an image to a file in X window dump
737 %  rasterfile format.
738 %
739 %  The format of the WriteXWDImage method is:
740 %
741 %      MagickBooleanType WriteXWDImage(const ImageInfo *image_info,
742 %        Image *image,ExceptionInfo *exception)
743 %
744 %  A description of each parameter follows.
745 %
746 %    o image_info: the image info.
747 %
748 %    o image:  The image.
749 %
750 %    o exception: return any errors or warnings in this structure.
751 %
752 */
WriteXWDImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)753 static MagickBooleanType WriteXWDImage(const ImageInfo *image_info,Image *image,
754   ExceptionInfo *exception)
755 {
756   const char
757     *value;
758 
759   MagickBooleanType
760     status;
761 
762   const Quantum
763     *p;
764 
765   ssize_t
766     x;
767 
768   unsigned char
769     *q;
770 
771   size_t
772     bits_per_pixel,
773     bytes_per_line,
774     length,
775     scanline_pad;
776 
777   ssize_t
778     count,
779     y;
780 
781   unsigned char
782     *pixels;
783 
784   unsigned long
785     lsb_first;
786 
787   XWDFileHeader
788     xwd_info;
789 
790   /*
791     Open output image file.
792   */
793   assert(image_info != (const ImageInfo *) NULL);
794   assert(image_info->signature == MagickCoreSignature);
795   assert(image != (Image *) NULL);
796   assert(image->signature == MagickCoreSignature);
797   if (image->debug != MagickFalse)
798     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
799   assert(exception != (ExceptionInfo *) NULL);
800   assert(exception->signature == MagickCoreSignature);
801   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
802   if (status == MagickFalse)
803     return(status);
804   if ((image->columns != (CARD32) image->columns) ||
805       (image->rows != (CARD32) image->rows))
806     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
807   if ((image->storage_class == PseudoClass) && (image->colors > 256))
808     (void) SetImageType(image,TrueColorType,exception);
809   (void) TransformImageColorspace(image,sRGBColorspace,exception);
810   /*
811     Initialize XWD file header.
812   */
813   (void) memset(&xwd_info,0,sizeof(xwd_info));
814   xwd_info.header_size=(CARD32) sz_XWDheader;
815   value=GetImageProperty(image,"comment",exception);
816   if (value != (const char *) NULL)
817     xwd_info.header_size+=(CARD32) strlen(value);
818   xwd_info.header_size++;
819   xwd_info.file_version=(CARD32) XWD_FILE_VERSION;
820   xwd_info.pixmap_format=(CARD32) ZPixmap;
821   xwd_info.pixmap_depth=(CARD32) (image->storage_class == DirectClass ? 24 : 8);
822   xwd_info.pixmap_width=(CARD32) image->columns;
823   xwd_info.pixmap_height=(CARD32) image->rows;
824   xwd_info.xoffset=(CARD32) 0;
825   xwd_info.byte_order=(CARD32) MSBFirst;
826   xwd_info.bitmap_unit=(CARD32) (image->storage_class == DirectClass ? 32 : 8);
827   xwd_info.bitmap_bit_order=(CARD32) MSBFirst;
828   xwd_info.bitmap_pad=(CARD32) (image->storage_class == DirectClass ? 32 : 8);
829   bits_per_pixel=(size_t) (image->storage_class == DirectClass ? 24 : 8);
830   xwd_info.bits_per_pixel=(CARD32) bits_per_pixel;
831   bytes_per_line=(CARD32) ((((xwd_info.bits_per_pixel*
832     xwd_info.pixmap_width)+((xwd_info.bitmap_pad)-1))/
833     (xwd_info.bitmap_pad))*((xwd_info.bitmap_pad) >> 3));
834   xwd_info.bytes_per_line=(CARD32) bytes_per_line;
835   xwd_info.visual_class=(CARD32)
836     (image->storage_class == DirectClass ? DirectColor : PseudoColor);
837   xwd_info.red_mask=(CARD32)
838     (image->storage_class == DirectClass ? 0xff0000 : 0);
839   xwd_info.green_mask=(CARD32)
840     (image->storage_class == DirectClass ? 0xff00 : 0);
841   xwd_info.blue_mask=(CARD32) (image->storage_class == DirectClass ? 0xff : 0);
842   xwd_info.bits_per_rgb=(CARD32) (image->storage_class == DirectClass ? 24 : 8);
843   xwd_info.colormap_entries=(CARD32)
844     (image->storage_class == DirectClass ? 256 : image->colors);
845   xwd_info.ncolors=(unsigned int)
846     (image->storage_class == DirectClass ? 0 : image->colors);
847   xwd_info.window_width=(CARD32) image->columns;
848   xwd_info.window_height=(CARD32) image->rows;
849   xwd_info.window_x=0;
850   xwd_info.window_y=0;
851   xwd_info.window_bdrwidth=(CARD32) 0;
852   /*
853     Write XWD header.
854   */
855   lsb_first=1;
856   if ((int) (*(char *) &lsb_first) != 0)
857     MSBOrderLong((unsigned char *) &xwd_info,sizeof(xwd_info));
858   (void) WriteBlob(image,sz_XWDheader,(unsigned char *) &xwd_info);
859   if (value != (const char *) NULL)
860     (void) WriteBlob(image,strlen(value),(unsigned char *) value);
861   (void) WriteBlob(image,1,(const unsigned char *) "\0");
862   if (image->storage_class == PseudoClass)
863     {
864       ssize_t
865         i;
866 
867       XColor
868         *colors;
869 
870       XWDColor
871         color;
872 
873       /*
874         Dump colormap to file.
875       */
876       (void) memset(&color,0,sizeof(color));
877       colors=(XColor *) AcquireQuantumMemory((size_t) image->colors,
878         sizeof(*colors));
879       if (colors == (XColor *) NULL)
880         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
881       for (i=0; i < (ssize_t) image->colors; i++)
882       {
883         colors[i].pixel=(unsigned long) i;
884         colors[i].red=ScaleQuantumToShort(ClampToQuantum(
885           image->colormap[i].red));
886         colors[i].green=ScaleQuantumToShort(ClampToQuantum(
887           image->colormap[i].green));
888         colors[i].blue=ScaleQuantumToShort(ClampToQuantum(
889           image->colormap[i].blue));
890         colors[i].flags=(char) (DoRed | DoGreen | DoBlue);
891         colors[i].pad='\0';
892         if ((int) (*(char *) &lsb_first) != 0)
893           {
894             MSBOrderLong((unsigned char *) &colors[i].pixel,
895               sizeof(colors[i].pixel));
896             MSBOrderShort((unsigned char *) &colors[i].red,3*
897               sizeof(colors[i].red));
898           }
899       }
900       for (i=0; i < (ssize_t) image->colors; i++)
901       {
902         color.pixel=(CARD32) colors[i].pixel;
903         color.red=colors[i].red;
904         color.green=colors[i].green;
905         color.blue=colors[i].blue;
906         color.flags=(CARD8) colors[i].flags;
907         count=WriteBlob(image,sz_XWDColor,(unsigned char *) &color);
908         if (count != (ssize_t) sz_XWDColor)
909           break;
910       }
911       colors=(XColor *) RelinquishMagickMemory(colors);
912     }
913   /*
914     Allocate memory for pixels.
915   */
916   length=3*bytes_per_line;
917   if (image->storage_class == PseudoClass)
918     length=bytes_per_line;
919   pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
920   if (pixels == (unsigned char *) NULL)
921     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
922   (void) memset(pixels,0,length);
923   /*
924     Convert MIFF to XWD raster pixels.
925   */
926   scanline_pad=(bytes_per_line-((image->columns*bits_per_pixel) >> 3));
927   for (y=0; y < (ssize_t) image->rows; y++)
928   {
929     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
930     if (p == (const Quantum *) NULL)
931       break;
932     q=pixels;
933     if (image->storage_class == PseudoClass)
934       {
935         for (x=0; x < (ssize_t) image->columns; x++)
936         {
937           *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
938           p+=GetPixelChannels(image);
939         }
940       }
941     else
942       for (x=0; x < (ssize_t) image->columns; x++)
943       {
944         *q++=ScaleQuantumToChar(GetPixelRed(image,p));
945         *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
946         *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
947         p+=GetPixelChannels(image);
948       }
949     for (x=0; x < (ssize_t) scanline_pad; x++)
950       *q++='\0';
951     length=(size_t) (q-pixels);
952     count=WriteBlob(image,length,pixels);
953     if (count != (ssize_t) length)
954       break;
955     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
956       image->rows);
957     if (status == MagickFalse)
958       break;
959   }
960   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
961   (void) CloseBlob(image);
962   return(y < (ssize_t) image->rows ? MagickFalse :  MagickTrue);
963 }
964 #endif
965