]> granicus.if.org Git - imagemagick/blob - coders/xwd.c
(no commit message)
[imagemagick] / coders / xwd.c
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 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2010 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 %    http://www.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 \f
39 /*
40   Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/cache.h"
46 #include "magick/color-private.h"
47 #include "magick/colormap.h"
48 #include "magick/colormap-private.h"
49 #include "magick/colorspace.h"
50 #include "magick/exception.h"
51 #include "magick/exception-private.h"
52 #include "magick/image.h"
53 #include "magick/image-private.h"
54 #include "magick/list.h"
55 #include "magick/magick.h"
56 #include "magick/memory_.h"
57 #include "magick/monitor.h"
58 #include "magick/monitor-private.h"
59 #include "magick/property.h"
60 #include "magick/quantum-private.h"
61 #include "magick/static.h"
62 #include "magick/string_.h"
63 #include "magick/module.h"
64 #if defined(MAGICKCORE_X11_DELEGATE)
65 #include "magick/xwindow-private.h"
66 #if !defined(vms)
67 #include <X11/XWDFile.h>
68 #else
69 #include "XWDFile.h"
70 #endif
71 #endif
72 \f
73 /*
74   Forward declarations.
75 */
76 #if defined(MAGICKCORE_X11_DELEGATE)
77 static MagickBooleanType
78   WriteXWDImage(const ImageInfo *,Image *);
79 #endif
80 \f
81 /*
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83 %                                                                             %
84 %                                                                             %
85 %                                                                             %
86 %   I s X W D                                                                 %
87 %                                                                             %
88 %                                                                             %
89 %                                                                             %
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 %
92 %  IsXWD() returns MagickTrue if the image format type, identified by the
93 %  magick string, is XWD.
94 %
95 %  The format of the IsXWD method is:
96 %
97 %      MagickBooleanType IsXWD(const unsigned char *magick,const size_t length)
98 %
99 %  A description of each parameter follows:
100 %
101 %    o magick: compare image format pattern against these bytes.
102 %
103 %    o length: Specifies the length of the magick string.
104 %
105 */
106 static MagickBooleanType IsXWD(const unsigned char *magick,const size_t length)
107 {
108   if (length < 8)
109     return(MagickFalse);
110   if (memcmp(magick+1,"\000\000",2) == 0)
111     {
112       if (memcmp(magick+4,"\007\000\000",3) == 0)
113         return(MagickTrue);
114       if (memcmp(magick+5,"\000\000\007",3) == 0)
115         return(MagickTrue);
116     }
117   return(MagickFalse);
118 }
119 \f
120 #if defined(MAGICKCORE_X11_DELEGATE)
121 /*
122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123 %                                                                             %
124 %                                                                             %
125 %                                                                             %
126 %   R e a d X W D I m a g e                                                   %
127 %                                                                             %
128 %                                                                             %
129 %                                                                             %
130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131 %
132 %  ReadXWDImage() reads an X Window System window dump image file and
133 %  returns it.  It allocates the memory necessary for the new Image structure
134 %  and returns a pointer to the new image.
135 %
136 %  The format of the ReadXWDImage method is:
137 %
138 %      Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
139 %
140 %  A description of each parameter follows:
141 %
142 %    o image_info: the image info.
143 %
144 %    o exception: return any errors or warnings in this structure.
145 %
146 */
147
148 static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
149 {
150 #define CheckOverflowException(length,width,height) \
151   (((height) != 0) && ((length)/((size_t) height) != ((size_t) width)))
152
153   char
154     *comment;
155
156   Image
157     *image;
158
159   IndexPacket
160     index;
161
162   int
163     x_status;
164
165   ssize_t
166     y;
167
168   MagickBooleanType
169     authentic_colormap;
170
171   MagickStatusType
172     status;
173
174   register IndexPacket
175     *indexes;
176
177   register ssize_t
178     x;
179
180   register PixelPacket
181     *q;
182
183   register ssize_t
184     i;
185
186   register size_t
187     pixel;
188
189   size_t
190     length;
191
192   ssize_t
193     count;
194
195   size_t
196     lsb_first;
197
198   XColor
199     *colors;
200
201   XImage
202     *ximage;
203
204   XWDFileHeader
205     header;
206
207   /*
208     Open image file.
209   */
210   assert(image_info != (const ImageInfo *) NULL);
211   assert(image_info->signature == MagickSignature);
212   if (image_info->debug != MagickFalse)
213     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
214       image_info->filename);
215   assert(exception != (ExceptionInfo *) NULL);
216   assert(exception->signature == MagickSignature);
217   image=AcquireImage(image_info);
218   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
219   if (status == MagickFalse)
220     {
221       image=DestroyImageList(image);
222       return((Image *) NULL);
223     }
224   /*
225      Read in header information.
226   */
227   count=ReadBlob(image,sz_XWDheader,(unsigned char *) &header);
228   if (count == 0)
229     ThrowReaderException(CorruptImageError,"UnableToReadImageHeader");
230   image->columns=header.pixmap_width;
231   image->rows=header.pixmap_height;
232   image->depth=8;
233   /*
234     Ensure the header byte-order is most-significant byte first.
235   */
236   lsb_first=1;
237   if ((int) (*(char *) &lsb_first) != 0)
238     MSBOrderLong((unsigned char *) &header,sz_XWDheader);
239   /*
240     Check to see if the dump file is in the proper format.
241   */
242   if (header.file_version != XWD_FILE_VERSION)
243     ThrowReaderException(CorruptImageError,"FileFormatVersionMismatch");
244   if (header.header_size < sz_XWDheader)
245     ThrowReaderException(CorruptImageError,"CorruptImage");
246   length=(size_t) header.header_size-sz_XWDheader;
247   comment=(char *) AcquireQuantumMemory(length+1,sizeof(*comment));
248   if (comment == (char *) NULL)
249     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
250   count=ReadBlob(image,length,(unsigned char *) comment);
251   comment[length]='\0';
252   (void) SetImageProperty(image,"comment",comment);
253   comment=DestroyString(comment);
254   if (count != (ssize_t) length)
255     ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
256   /*
257     Initialize the X image.
258   */
259   ximage=(XImage *) AcquireMagickMemory(sizeof(*ximage));
260   if (ximage == (XImage *) NULL)
261     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
262   ximage->depth=(int) header.pixmap_depth;
263   ximage->format=(int) header.pixmap_format;
264   ximage->xoffset=(int) header.xoffset;
265   ximage->data=(char *) NULL;
266   ximage->width=(int) header.pixmap_width;
267   ximage->height=(int) header.pixmap_height;
268   ximage->bitmap_pad=(int) header.bitmap_pad;
269   ximage->bytes_per_line=(int) header.bytes_per_line;
270   ximage->byte_order=(int) header.byte_order;
271   ximage->bitmap_unit=(int) header.bitmap_unit;
272   ximage->bitmap_bit_order=(int) header.bitmap_bit_order;
273   ximage->bits_per_pixel=(int) header.bits_per_pixel;
274   ximage->red_mask=header.red_mask;
275   ximage->green_mask=header.green_mask;
276   ximage->blue_mask=header.blue_mask;
277   if ((ximage->depth < 0) || (ximage->width < 0) || (ximage->height < 0) ||
278       (ximage->bitmap_pad < 0) || (ximage->bytes_per_line < 0))
279     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
280   if ((ximage->bits_per_pixel > 32) || (ximage->bitmap_unit > 32))
281     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
282   x_status=XInitImage(ximage);
283   if (x_status == 0)
284     ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
285   /*
286     Read colormap.
287   */
288   authentic_colormap=MagickFalse;
289   colors=(XColor *) NULL;
290   if (header.ncolors != 0)
291     {
292       XWDColor
293         color;
294
295       length=(size_t) header.ncolors;
296       colors=(XColor *) AcquireQuantumMemory(length,sizeof(*colors));
297       if (colors == (XColor *) NULL)
298         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
299       for (i=0; i < (ssize_t) header.ncolors; i++)
300       {
301         count=ReadBlob(image,sz_XWDColor,(unsigned char *) &color);
302         if (count == 0)
303           ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
304         colors[i].pixel=color.pixel;
305         colors[i].red=color.red;
306         colors[i].green=color.green;
307         colors[i].blue=color.blue;
308         colors[i].flags=(char) color.flags;
309         if (color.flags != 0)
310          authentic_colormap=MagickTrue;
311       }
312       /*
313         Ensure the header byte-order is most-significant byte first.
314       */
315       lsb_first=1;
316       if ((int) (*(char *) &lsb_first) != 0)
317         for (i=0; i < (ssize_t) header.ncolors; i++)
318         {
319           MSBOrderLong((unsigned char *) &colors[i].pixel,
320             sizeof(colors[i].pixel));
321           MSBOrderShort((unsigned char *) &colors[i].red,3*
322             sizeof(colors[i].red));
323         }
324     }
325   /*
326     Allocate the pixel buffer.
327   */
328   length=(size_t) ximage->bytes_per_line*ximage->height;
329   if (CheckOverflowException(length,ximage->bytes_per_line,ximage->height))
330     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
331   if (ximage->format != ZPixmap)
332     {
333       size_t
334         extent;
335
336       extent=length;
337       length*=ximage->depth;
338       if (CheckOverflowException(length,extent,ximage->depth))
339         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
340     }
341   ximage->data=(char *) AcquireQuantumMemory(length,sizeof(*ximage->data));
342   if (ximage->data == (char *) NULL)
343     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
344   count=ReadBlob(image,length,(unsigned char *) ximage->data);
345   if (count == 0)
346     ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
347   /*
348     Convert image to MIFF format.
349   */
350   image->columns=(size_t) ximage->width;
351   image->rows=(size_t) ximage->height;
352   if ((colors == (XColor *) NULL) || (ximage->red_mask != 0) ||
353       (ximage->green_mask != 0) || (ximage->blue_mask != 0))
354     image->storage_class=DirectClass;
355   else
356     image->storage_class=PseudoClass;
357   image->colors=header.ncolors;
358   if (image_info->ping == MagickFalse)
359     switch (image->storage_class)
360     {
361       case DirectClass:
362       default:
363       {
364         register size_t
365           color;
366
367         size_t
368           blue_mask,
369           blue_shift,
370           green_mask,
371           green_shift,
372           red_mask,
373           red_shift;
374
375         /*
376           Determine shift and mask for red, green, and blue.
377         */
378         red_mask=ximage->red_mask;
379         red_shift=0;
380         while ((red_mask != 0) && ((red_mask & 0x01) == 0))
381         {
382           red_mask>>=1;
383           red_shift++;
384         }
385         green_mask=ximage->green_mask;
386         green_shift=0;
387         while ((green_mask != 0) && ((green_mask & 0x01) == 0))
388         {
389           green_mask>>=1;
390           green_shift++;
391         }
392         blue_mask=ximage->blue_mask;
393         blue_shift=0;
394         while ((blue_mask != 0) && ((blue_mask & 0x01) == 0))
395         {
396           blue_mask>>=1;
397           blue_shift++;
398         }
399         /*
400           Convert X image to DirectClass packets.
401         */
402         if ((image->colors != 0) && (authentic_colormap != MagickFalse))
403           for (y=0; y < (ssize_t) image->rows; y++)
404           {
405             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
406             if (q == (PixelPacket *) NULL)
407               break;
408             for (x=0; x < (ssize_t) image->columns; x++)
409             {
410               pixel=XGetPixel(ximage,(int) x,(int) y);
411               index=(IndexPacket) ((pixel >> red_shift) & red_mask);
412               q->red=ScaleShortToQuantum(colors[(ssize_t) index].red);
413               index=(IndexPacket) ((pixel >> green_shift) & green_mask);
414               q->green=ScaleShortToQuantum(colors[(ssize_t) index].green);
415               index=(IndexPacket) ((pixel >> blue_shift) & blue_mask);
416               q->blue=ScaleShortToQuantum(colors[(ssize_t) index].blue);
417               q++;
418             }
419             if (SyncAuthenticPixels(image,exception) == MagickFalse)
420               break;
421             status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
422                 image->rows);
423             if (status == MagickFalse)
424               break;
425           }
426         else
427           for (y=0; y < (ssize_t) image->rows; y++)
428           {
429             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
430             if (q == (PixelPacket *) NULL)
431               break;
432             for (x=0; x < (ssize_t) image->columns; x++)
433             {
434               pixel=XGetPixel(ximage,(int) x,(int) y);
435               color=(pixel >> red_shift) & red_mask;
436               color=(color*65535UL)/red_mask;
437               q->red=ScaleShortToQuantum((unsigned short) color);
438               color=(pixel >> green_shift) & green_mask;
439               color=(color*65535UL)/green_mask;
440               q->green=ScaleShortToQuantum((unsigned short) color);
441               color=(pixel >> blue_shift) & blue_mask;
442               color=(color*65535UL)/blue_mask;
443               q->blue=ScaleShortToQuantum((unsigned short) color);
444               q++;
445             }
446             if (SyncAuthenticPixels(image,exception) == MagickFalse)
447               break;
448             status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
449                 image->rows);
450             if (status == MagickFalse)
451               break;
452           }
453         break;
454       }
455       case PseudoClass:
456       {
457         /*
458           Convert X image to PseudoClass packets.
459         */
460         if (AcquireImageColormap(image,image->colors) == MagickFalse)
461           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
462         for (i=0; i < (ssize_t) image->colors; i++)
463         {
464           image->colormap[i].red=ScaleShortToQuantum(colors[i].red);
465           image->colormap[i].green=ScaleShortToQuantum(colors[i].green);
466           image->colormap[i].blue=ScaleShortToQuantum(colors[i].blue);
467         }
468         for (y=0; y < (ssize_t) image->rows; y++)
469         {
470           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
471           if (q == (PixelPacket *) NULL)
472             break;
473           indexes=GetAuthenticIndexQueue(image);
474           for (x=0; x < (ssize_t) image->columns; x++)
475           {
476             index=ConstrainColormapIndex(image,XGetPixel(ximage,(int) x,
477               (int) y));
478             indexes[x]=index;
479             *q++=image->colormap[(ssize_t) index];
480           }
481           if (SyncAuthenticPixels(image,exception) == MagickFalse)
482             break;
483           status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
484                 image->rows);
485           if (status == MagickFalse)
486             break;
487         }
488         break;
489       }
490     }
491   /*
492     Free image and colormap.
493   */
494   if (header.ncolors != 0)
495     colors=(XColor *) RelinquishMagickMemory(colors);
496   ximage->data=DestroyString(ximage->data);
497   ximage=(XImage *) RelinquishMagickMemory(ximage);
498   if (EOFBlob(image) != MagickFalse)
499     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
500       image->filename);
501   (void) CloseBlob(image);
502   return(GetFirstImageInList(image));
503 }
504 #endif
505 \f
506 /*
507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508 %                                                                             %
509 %                                                                             %
510 %                                                                             %
511 %   R e g i s t e r X W D I m a g e                                           %
512 %                                                                             %
513 %                                                                             %
514 %                                                                             %
515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
516 %
517 %  RegisterXWDImage() adds properties for the XWD image format to
518 %  the list of supported formats.  The properties include the image format
519 %  tag, a method to read and/or write the format, whether the format
520 %  supports the saving of more than one frame to the same file or blob,
521 %  whether the format supports native in-memory I/O, and a brief
522 %  description of the format.
523 %
524 %  The format of the RegisterXWDImage method is:
525 %
526 %      size_t RegisterXWDImage(void)
527 %
528 */
529 ModuleExport size_t RegisterXWDImage(void)
530 {
531   MagickInfo
532     *entry;
533
534   entry=SetMagickInfo("XWD");
535 #if defined(MAGICKCORE_X11_DELEGATE)
536   entry->decoder=(DecodeImageHandler *) ReadXWDImage;
537   entry->encoder=(EncodeImageHandler *) WriteXWDImage;
538 #endif
539   entry->magick=(IsImageFormatHandler *) IsXWD;
540   entry->adjoin=MagickFalse;
541   entry->description=ConstantString("X Windows system window dump (color)");
542   entry->module=ConstantString("XWD");
543   (void) RegisterMagickInfo(entry);
544   return(MagickImageCoderSignature);
545 }
546 \f
547 /*
548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549 %                                                                             %
550 %                                                                             %
551 %                                                                             %
552 %   U n r e g i s t e r X W D I m a g e                                       %
553 %                                                                             %
554 %                                                                             %
555 %                                                                             %
556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557 %
558 %  UnregisterXWDImage() removes format registrations made by the
559 %  XWD module from the list of supported formats.
560 %
561 %  The format of the UnregisterXWDImage method is:
562 %
563 %      UnregisterXWDImage(void)
564 %
565 */
566 ModuleExport void UnregisterXWDImage(void)
567 {
568   (void) UnregisterMagickInfo("XWD");
569 }
570 \f
571 #if defined(MAGICKCORE_X11_DELEGATE)
572 /*
573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
574 %                                                                             %
575 %                                                                             %
576 %                                                                             %
577 %   W r i t e X W D I m a g e                                                 %
578 %                                                                             %
579 %                                                                             %
580 %                                                                             %
581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
582 %
583 %  WriteXWDImage() writes an image to a file in X window dump
584 %  rasterfile format.
585 %
586 %  The format of the WriteXWDImage method is:
587 %
588 %      MagickBooleanType WriteXWDImage(const ImageInfo *image_info,Image *image)
589 %
590 %  A description of each parameter follows.
591 %
592 %    o image_info: the image info.
593 %
594 %    o image:  The image.
595 %
596 */
597 static MagickBooleanType WriteXWDImage(const ImageInfo *image_info,Image *image)
598 {
599   const char
600     *value;
601
602   ssize_t
603     y;
604
605   MagickBooleanType
606     status;
607
608   register const IndexPacket
609     *indexes;
610
611   register const PixelPacket
612     *p;
613
614   register ssize_t
615     x;
616
617   register ssize_t
618     i;
619
620   register unsigned char
621     *q;
622
623   size_t
624     length;
625
626   unsigned char
627     *pixels;
628
629   size_t
630     bits_per_pixel,
631     bytes_per_line,
632     lsb_first,
633     scanline_pad;
634
635   XWDFileHeader
636     xwd_info;
637
638   /*
639     Open output image file.
640   */
641   assert(image_info != (const ImageInfo *) NULL);
642   assert(image_info->signature == MagickSignature);
643   assert(image != (Image *) NULL);
644   assert(image->signature == MagickSignature);
645   if (image->debug != MagickFalse)
646     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
647   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
648   if (status == MagickFalse)
649     return(status);
650   if (image->colorspace != RGBColorspace)
651     (void) TransformImageColorspace(image,RGBColorspace);
652   /*
653     Initialize XWD file header.
654   */
655   (void) ResetMagickMemory(&xwd_info,0,sizeof(xwd_info));
656   xwd_info.header_size=(CARD32) sz_XWDheader;
657   value=GetImageProperty(image,"comment");
658   if (value != (const char *) NULL)
659     xwd_info.header_size+=(CARD32) strlen(value);
660   xwd_info.header_size++;
661   xwd_info.file_version=(CARD32) XWD_FILE_VERSION;
662   xwd_info.pixmap_format=(CARD32) ZPixmap;
663   xwd_info.pixmap_depth=(CARD32) (image->storage_class == DirectClass ? 24 : 8);
664   xwd_info.pixmap_width=(CARD32) image->columns;
665   xwd_info.pixmap_height=(CARD32) image->rows;
666   xwd_info.xoffset=(CARD32) 0;
667   xwd_info.byte_order=(CARD32) MSBFirst;
668   xwd_info.bitmap_unit=(CARD32) (image->storage_class == DirectClass ? 32 : 8);
669   xwd_info.bitmap_bit_order=(CARD32) MSBFirst;
670   xwd_info.bitmap_pad=(CARD32) (image->storage_class == DirectClass ? 32 : 8);
671   bits_per_pixel=(size_t) (image->storage_class == DirectClass ? 24 : 8);
672   xwd_info.bits_per_pixel=(CARD32) bits_per_pixel;
673   bytes_per_line=(CARD32) ((((xwd_info.bits_per_pixel*
674     xwd_info.pixmap_width)+((xwd_info.bitmap_pad)-1))/
675     (xwd_info.bitmap_pad))*((xwd_info.bitmap_pad) >> 3));
676   xwd_info.bytes_per_line=(CARD32) bytes_per_line;
677   xwd_info.visual_class=(CARD32)
678     (image->storage_class == DirectClass ? DirectColor : PseudoColor);
679   xwd_info.red_mask=(CARD32)
680     (image->storage_class == DirectClass ? 0xff0000 : 0);
681   xwd_info.green_mask=(CARD32)
682     (image->storage_class == DirectClass ? 0xff00 : 0);
683   xwd_info.blue_mask=(CARD32) (image->storage_class == DirectClass ? 0xff : 0);
684   xwd_info.bits_per_rgb=(CARD32) (image->storage_class == DirectClass ? 24 : 8);
685   xwd_info.colormap_entries=(CARD32)
686     (image->storage_class == DirectClass ? 256 : image->colors);
687   xwd_info.ncolors=(unsigned int)
688     (image->storage_class == DirectClass ? 0 : image->colors);
689   xwd_info.window_width=(CARD32) image->columns;
690   xwd_info.window_height=(CARD32) image->rows;
691   xwd_info.window_x=0;
692   xwd_info.window_y=0;
693   xwd_info.window_bdrwidth=(CARD32) 0;
694   /*
695     Write XWD header.
696   */
697   lsb_first=1;
698   if ((int) (*(char *) &lsb_first) != 0)
699     MSBOrderLong((unsigned char *) &xwd_info,sizeof(xwd_info));
700   (void) WriteBlob(image,sz_XWDheader,(unsigned char *) &xwd_info);
701   if (value != (const char *) NULL)
702     (void) WriteBlob(image,strlen(value),(unsigned char *) value);
703   (void) WriteBlob(image,1,(const unsigned char *) "\0");
704   if (image->storage_class == PseudoClass)
705     {
706       XColor
707         *colors;
708
709       XWDColor
710         color;
711
712       /*
713         Dump colormap to file.
714       */
715       (void) ResetMagickMemory(&color,0,sizeof(color));
716       colors=(XColor *) AcquireQuantumMemory((size_t) image->colors,
717         sizeof(*colors));
718       if (colors == (XColor *) NULL)
719         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
720       for (i=0; i < (ssize_t) image->colors; i++)
721       {
722         colors[i].pixel=(size_t) i;
723         colors[i].red=ScaleQuantumToShort(image->colormap[i].red);
724         colors[i].green=ScaleQuantumToShort(image->colormap[i].green);
725         colors[i].blue=ScaleQuantumToShort(image->colormap[i].blue);
726         colors[i].flags=(char) (DoRed | DoGreen | DoBlue);
727         colors[i].pad='\0';
728         if ((int) (*(char *) &lsb_first) != 0)
729           {
730             MSBOrderLong((unsigned char *) &colors[i].pixel,
731               sizeof(colors[i].pixel));
732             MSBOrderShort((unsigned char *) &colors[i].red,
733               3*sizeof(colors[i].red));
734           }
735       }
736       for (i=0; i < (ssize_t) image->colors; i++)
737       {
738         color.pixel=(CARD32) colors[i].pixel;
739         color.red=colors[i].red;
740         color.green=colors[i].green;
741         color.blue=colors[i].blue;
742         color.flags=(CARD8) colors[i].flags;
743         (void) WriteBlob(image,sz_XWDColor,(unsigned char *) &color);
744       }
745       colors=(XColor *) RelinquishMagickMemory(colors);
746     }
747   /*
748     Allocate memory for pixels.
749   */
750   length=3*bytes_per_line;
751   if (image->storage_class == PseudoClass)
752     length=bytes_per_line;
753   pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
754   if (pixels == (unsigned char *) NULL)
755     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
756   (void) ResetMagickMemory(pixels,0,length);
757   /*
758     Convert MIFF to XWD raster pixels.
759   */
760   scanline_pad=(bytes_per_line-((image->columns*bits_per_pixel) >> 3));
761   for (y=0; y < (ssize_t) image->rows; y++)
762   {
763     p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
764     if (p == (const PixelPacket *) NULL)
765       break;
766     q=pixels;
767     if (image->storage_class == PseudoClass)
768       {
769         indexes=GetVirtualIndexQueue(image);
770         for (x=0; x < (ssize_t) image->columns; x++)
771           *q++=(unsigned char) indexes[x];
772       }
773     else
774       for (x=0; x < (ssize_t) image->columns; x++)
775       {
776         *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
777         *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
778         *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
779         p++;
780       }
781     for (x=0; x < (ssize_t) scanline_pad; x++)
782       *q++='\0';
783     (void) WriteBlob(image,(size_t) (q-pixels),pixels);
784     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
785                 image->rows);
786     if (status == MagickFalse)
787       break;
788   }
789   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
790   (void) CloseBlob(image);
791   return(MagickTrue);
792 }
793 #endif