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