Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            SSSSS  U   U  N   N                              %
      7 %                            SS     U   U  NN  N                              %
      8 %                             SSS   U   U  N N N                              %
      9 %                               SS  U   U  N  NN                              %
     10 %                            SSSSS   UUU   N   N                              %
     11 %                                                                             %
     12 %                                                                             %
     13 %                    Read/Write Sun Rasterfile Image 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/attribute.h"
     45 #include "MagickCore/blob.h"
     46 #include "MagickCore/blob-private.h"
     47 #include "MagickCore/cache.h"
     48 #include "MagickCore/color.h"
     49 #include "MagickCore/color-private.h"
     50 #include "MagickCore/colormap.h"
     51 #include "MagickCore/colormap-private.h"
     52 #include "MagickCore/colorspace.h"
     53 #include "MagickCore/colorspace-private.h"
     54 #include "MagickCore/exception.h"
     55 #include "MagickCore/exception-private.h"
     56 #include "MagickCore/image.h"
     57 #include "MagickCore/image-private.h"
     58 #include "MagickCore/list.h"
     59 #include "MagickCore/magick.h"
     60 #include "MagickCore/memory_.h"
     61 #include "MagickCore/memory-private.h"
     62 #include "MagickCore/monitor.h"
     63 #include "MagickCore/monitor-private.h"
     64 #include "MagickCore/pixel-accessor.h"
     65 #include "MagickCore/quantum-private.h"
     66 #include "MagickCore/static.h"
     67 #include "MagickCore/string_.h"
     68 #include "MagickCore/module.h"
     69 
     70 /*
     72   Forward declarations.
     73 */
     74 static MagickBooleanType
     75   WriteSUNImage(const ImageInfo *,Image *,ExceptionInfo *);
     76 
     77 /*
     79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     80 %                                                                             %
     81 %                                                                             %
     82 %                                                                             %
     83 %   I s S U N                                                                 %
     84 %                                                                             %
     85 %                                                                             %
     86 %                                                                             %
     87 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     88 %
     89 %  IsSUN() returns MagickTrue if the image format type, identified by the
     90 %  magick string, is SUN.
     91 %
     92 %  The format of the IsSUN method is:
     93 %
     94 %      MagickBooleanType IsSUN(const unsigned char *magick,const size_t length)
     95 %
     96 %  A description of each parameter follows:
     97 %
     98 %    o magick: compare image format pattern against these bytes.
     99 %
    100 %    o length: Specifies the length of the magick string.
    101 %
    102 */
    103 static MagickBooleanType IsSUN(const unsigned char *magick,const size_t length)
    104 {
    105   if (length < 4)
    106     return(MagickFalse);
    107   if (memcmp(magick,"\131\246\152\225",4) == 0)
    108     return(MagickTrue);
    109   return(MagickFalse);
    110 }
    111 
    112 /*
    114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    115 %                                                                             %
    116 %                                                                             %
    117 %                                                                             %
    118 %   D e c o d e I m a g e                                                     %
    119 %                                                                             %
    120 %                                                                             %
    121 %                                                                             %
    122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    123 %
    124 %  DecodeImage unpacks the packed image pixels into  runlength-encoded pixel
    125 %  packets.
    126 %
    127 %  The format of the DecodeImage method is:
    128 %
    129 %      MagickBooleanType DecodeImage(const unsigned char *compressed_pixels,
    130 %        const size_t length,unsigned char *pixels)
    131 %
    132 %  A description of each parameter follows:
    133 %
    134 %    o compressed_pixels:  The address of a byte (8 bits) array of compressed
    135 %      pixel data.
    136 %
    137 %    o length:  An integer value that is the total number of bytes of the
    138 %      source image (as just read by ReadBlob)
    139 %
    140 %    o pixels:  The address of a byte (8 bits) array of pixel data created by
    141 %      the uncompression process.  The number of bytes in this array
    142 %      must be at least equal to the number columns times the number of rows
    143 %      of the source pixels.
    144 %
    145 */
    146 static MagickBooleanType DecodeImage(const unsigned char *compressed_pixels,
    147   const size_t length,unsigned char *pixels,size_t extent)
    148 {
    149   register const unsigned char
    150     *p;
    151 
    152   register unsigned char
    153     *q;
    154 
    155   ssize_t
    156     count;
    157 
    158   unsigned char
    159     byte;
    160 
    161   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
    162   assert(compressed_pixels != (unsigned char *) NULL);
    163   assert(pixels != (unsigned char *) NULL);
    164   p=compressed_pixels;
    165   q=pixels;
    166   while (((size_t) (p-compressed_pixels) < length) &&
    167          ((size_t) (q-pixels) < extent))
    168   {
    169     byte=(*p++);
    170     if (byte != 128U)
    171       *q++=byte;
    172     else
    173       {
    174         /*
    175           Runlength-encoded packet: <count><byte>.
    176         */
    177         if (((size_t) (p-compressed_pixels) >= length))
    178           break;
    179         count=(*p++);
    180         if (count > 0)
    181           {
    182             if (((size_t) (p-compressed_pixels) >= length))
    183               break;
    184             byte=(*p++);
    185           }
    186         while ((count >= 0) && ((size_t) (q-pixels) < extent))
    187         {
    188           *q++=byte;
    189           count--;
    190         }
    191      }
    192   }
    193   return(((size_t) (q-pixels) == extent) ? MagickTrue : MagickFalse);
    194 }
    195 
    196 /*
    198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    199 %                                                                             %
    200 %                                                                             %
    201 %                                                                             %
    202 %   R e a d S U N I m a g e                                                   %
    203 %                                                                             %
    204 %                                                                             %
    205 %                                                                             %
    206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    207 %
    208 %  ReadSUNImage() reads a SUN image file and returns it.  It allocates
    209 %  the memory necessary for the new Image structure and returns a pointer to
    210 %  the new image.
    211 %
    212 %  The format of the ReadSUNImage method is:
    213 %
    214 %      Image *ReadSUNImage(const ImageInfo *image_info,ExceptionInfo *exception)
    215 %
    216 %  A description of each parameter follows:
    217 %
    218 %    o image_info: the image info.
    219 %
    220 %    o exception: return any errors or warnings in this structure.
    221 %
    222 */
    223 static Image *ReadSUNImage(const ImageInfo *image_info,ExceptionInfo *exception)
    224 {
    225 #define RMT_EQUAL_RGB  1
    226 #define RMT_NONE  0
    227 #define RMT_RAW  2
    228 #define RT_STANDARD  1
    229 #define RT_ENCODED  2
    230 #define RT_FORMAT_RGB  3
    231 
    232   typedef struct _SUNInfo
    233   {
    234     unsigned int
    235       magic,
    236       width,
    237       height,
    238       depth,
    239       length,
    240       type,
    241       maptype,
    242       maplength;
    243   } SUNInfo;
    244 
    245   Image
    246     *image;
    247 
    248   int
    249     bit;
    250 
    251   MagickBooleanType
    252     status;
    253 
    254   MagickSizeType
    255     number_pixels;
    256 
    257   register Quantum
    258     *q;
    259 
    260   register ssize_t
    261     i,
    262     x;
    263 
    264   register unsigned char
    265     *p;
    266 
    267   size_t
    268     bytes_per_line,
    269     extent,
    270     height,
    271     pixels_length,
    272     quantum;
    273 
    274   ssize_t
    275     count,
    276     y;
    277 
    278   SUNInfo
    279     sun_info;
    280 
    281   unsigned char
    282     *sun_data,
    283     *sun_pixels;
    284 
    285   /*
    286     Open image file.
    287   */
    288   assert(image_info != (const ImageInfo *) NULL);
    289   assert(image_info->signature == MagickCoreSignature);
    290   if (image_info->debug != MagickFalse)
    291     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    292       image_info->filename);
    293   assert(exception != (ExceptionInfo *) NULL);
    294   assert(exception->signature == MagickCoreSignature);
    295   image=AcquireImage(image_info,exception);
    296   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    297   if (status == MagickFalse)
    298     {
    299       image=DestroyImageList(image);
    300       return((Image *) NULL);
    301     }
    302   /*
    303     Read SUN raster header.
    304   */
    305   (void) memset(&sun_info,0,sizeof(sun_info));
    306   sun_info.magic=ReadBlobMSBLong(image);
    307   do
    308   {
    309     /*
    310       Verify SUN identifier.
    311     */
    312     if (sun_info.magic != 0x59a66a95)
    313       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    314     sun_info.width=ReadBlobMSBLong(image);
    315     sun_info.height=ReadBlobMSBLong(image);
    316     sun_info.depth=ReadBlobMSBLong(image);
    317     sun_info.length=ReadBlobMSBLong(image);
    318     sun_info.type=ReadBlobMSBLong(image);
    319     sun_info.maptype=ReadBlobMSBLong(image);
    320     sun_info.maplength=ReadBlobMSBLong(image);
    321     if (sun_info.maplength > GetBlobSize(image))
    322       ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    323     extent=sun_info.height*sun_info.width;
    324     if ((sun_info.height != 0) && (sun_info.width != extent/sun_info.height))
    325       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    326     if ((sun_info.type != RT_STANDARD) && (sun_info.type != RT_ENCODED) &&
    327         (sun_info.type != RT_FORMAT_RGB))
    328       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    329     if ((sun_info.maptype == RMT_NONE) && (sun_info.maplength != 0))
    330       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    331     if ((sun_info.depth != 1) && (sun_info.depth != 8) &&
    332         (sun_info.depth != 24) && (sun_info.depth != 32))
    333       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    334     if ((sun_info.maptype != RMT_NONE) && (sun_info.maptype != RMT_EQUAL_RGB) &&
    335         (sun_info.maptype != RMT_RAW))
    336       ThrowReaderException(CoderError,"ColormapTypeNotSupported");
    337     image->columns=sun_info.width;
    338     image->rows=sun_info.height;
    339     image->depth=sun_info.depth <= 8 ? sun_info.depth :
    340       MAGICKCORE_QUANTUM_DEPTH;
    341     if (sun_info.depth < 24)
    342       {
    343         size_t
    344           one;
    345 
    346         image->colors=sun_info.maplength;
    347         one=1;
    348         if (sun_info.maptype == RMT_NONE)
    349           image->colors=one << sun_info.depth;
    350         if (sun_info.maptype == RMT_EQUAL_RGB)
    351           image->colors=sun_info.maplength/3;
    352         if (image->colors == 0)
    353           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    354         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
    355           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    356       }
    357     switch (sun_info.maptype)
    358     {
    359       case RMT_NONE:
    360         break;
    361       case RMT_EQUAL_RGB:
    362       {
    363         unsigned char
    364           *sun_colormap;
    365 
    366         /*
    367           Read SUN raster colormap.
    368         */
    369         sun_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
    370           sizeof(*sun_colormap));
    371         if (sun_colormap == (unsigned char *) NULL)
    372           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    373         count=ReadBlob(image,image->colors,sun_colormap);
    374         if (count != (ssize_t) image->colors)
    375           {
    376             sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap);
    377             ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
    378           }
    379         for (i=0; i < (ssize_t) image->colors; i++)
    380           image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(
    381             sun_colormap[i]);
    382         count=ReadBlob(image,image->colors,sun_colormap);
    383         if (count != (ssize_t) image->colors)
    384           {
    385             sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap);
    386             ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
    387           }
    388         for (i=0; i < (ssize_t) image->colors; i++)
    389           image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(
    390             sun_colormap[i]);
    391         count=ReadBlob(image,image->colors,sun_colormap);
    392         if (count != (ssize_t) image->colors)
    393           {
    394             sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap);
    395             ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
    396           }
    397         for (i=0; i < (ssize_t) image->colors; i++)
    398           image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(
    399             sun_colormap[i]);
    400         sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap);
    401         break;
    402       }
    403       case RMT_RAW:
    404       {
    405         unsigned char
    406           *sun_colormap;
    407 
    408         /*
    409           Read SUN raster colormap.
    410         */
    411         sun_colormap=(unsigned char *) AcquireQuantumMemory(sun_info.maplength,
    412           sizeof(*sun_colormap));
    413         if (sun_colormap == (unsigned char *) NULL)
    414           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    415         count=ReadBlob(image,sun_info.maplength,sun_colormap);
    416         sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap);
    417         if (count != (ssize_t) sun_info.maplength)
    418           ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
    419         break;
    420       }
    421       default:
    422         ThrowReaderException(CoderError,"ColormapTypeNotSupported");
    423     }
    424     image->alpha_trait=sun_info.depth == 32 ? BlendPixelTrait :
    425       UndefinedPixelTrait;
    426     image->columns=sun_info.width;
    427     image->rows=sun_info.height;
    428     if (image_info->ping != MagickFalse)
    429       {
    430         (void) CloseBlob(image);
    431         return(GetFirstImageInList(image));
    432       }
    433     status=SetImageExtent(image,image->columns,image->rows,exception);
    434     if (status == MagickFalse)
    435       return(DestroyImageList(image));
    436     if (sun_info.length == 0)
    437       ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
    438     number_pixels=(MagickSizeType) (image->columns*image->rows);
    439     if ((sun_info.type != RT_ENCODED) &&
    440         ((number_pixels*sun_info.depth) > (8UL*sun_info.length)))
    441       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    442     if (HeapOverflowSanityCheck(sun_info.width,sun_info.depth) != MagickFalse)
    443       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    444     bytes_per_line=sun_info.width*sun_info.depth;
    445     if (sun_info.length > GetBlobSize(image))
    446       ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    447     sun_data=(unsigned char *) AcquireQuantumMemory(sun_info.length,
    448       sizeof(*sun_data));
    449     if (sun_data == (unsigned char *) NULL)
    450       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    451     count=(ssize_t) ReadBlob(image,sun_info.length,sun_data);
    452     if (count != (ssize_t) sun_info.length)
    453       {
    454         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
    455         ThrowReaderException(CorruptImageError,"UnableToReadImageData");
    456       }
    457     height=sun_info.height;
    458     if ((height == 0) || (sun_info.width == 0) || (sun_info.depth == 0) ||
    459         ((bytes_per_line/sun_info.depth) != sun_info.width))
    460       {
    461         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
    462         ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
    463       }
    464     quantum=sun_info.depth == 1 ? 15 : 7;
    465     bytes_per_line+=quantum;
    466     bytes_per_line<<=1;
    467     if ((bytes_per_line >> 1) != (sun_info.width*sun_info.depth+quantum))
    468       {
    469         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
    470         ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
    471       }
    472     bytes_per_line>>=4;
    473     if (HeapOverflowSanityCheck(height,bytes_per_line) != MagickFalse)
    474       {
    475         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
    476         ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
    477       }
    478     pixels_length=height*bytes_per_line;
    479     sun_pixels=(unsigned char *) AcquireQuantumMemory(pixels_length+image->rows,
    480       sizeof(*sun_pixels));
    481     if (sun_pixels == (unsigned char *) NULL)
    482       {
    483         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
    484         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    485       }
    486     (void) memset(sun_pixels,0,(pixels_length+image->rows)*
    487       sizeof(*sun_pixels));
    488     if (sun_info.type == RT_ENCODED)
    489       {
    490         status=DecodeImage(sun_data,sun_info.length,sun_pixels,pixels_length);
    491         if (status == MagickFalse)
    492           {
    493             sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
    494             sun_pixels=(unsigned char *) RelinquishMagickMemory(sun_pixels);
    495             ThrowReaderException(CorruptImageError,"UnableToReadImageData");
    496           }
    497       }
    498     else
    499       {
    500         if (sun_info.length > pixels_length)
    501           {
    502             sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
    503             sun_pixels=(unsigned char *) RelinquishMagickMemory(sun_pixels);
    504             ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
    505           }
    506         (void) memcpy(sun_pixels,sun_data,sun_info.length);
    507       }
    508     sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
    509     /*
    510       Convert SUN raster image to pixel packets.
    511     */
    512     p=sun_pixels;
    513     if (sun_info.depth == 1)
    514       for (y=0; y < (ssize_t) image->rows; y++)
    515       {
    516         q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    517         if (q == (Quantum *) NULL)
    518           break;
    519         for (x=0; x < ((ssize_t) image->columns-7); x+=8)
    520         {
    521           for (bit=7; bit >= 0; bit--)
    522           {
    523             SetPixelIndex(image,(Quantum) ((*p) & (0x01 << bit) ? 0x00 : 0x01),
    524               q);
    525             q+=GetPixelChannels(image);
    526           }
    527           p++;
    528         }
    529         if ((image->columns % 8) != 0)
    530           {
    531             for (bit=7; bit >= (int) (8-(image->columns % 8)); bit--)
    532             {
    533               SetPixelIndex(image,(Quantum) ((*p) & (0x01 << bit) ? 0x00 :
    534                 0x01),q);
    535               q+=GetPixelChannels(image);
    536             }
    537             p++;
    538           }
    539         if ((((image->columns/8)+(image->columns % 8 ? 1 : 0)) % 2) != 0)
    540           p++;
    541         if (SyncAuthenticPixels(image,exception) == MagickFalse)
    542           break;
    543         if (image->previous == (Image *) NULL)
    544           {
    545             status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    546               image->rows);
    547             if (status == MagickFalse)
    548               break;
    549           }
    550       }
    551     else
    552       if (image->storage_class == PseudoClass)
    553         {
    554           for (y=0; y < (ssize_t) image->rows; y++)
    555           {
    556             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    557             if (q == (Quantum *) NULL)
    558               break;
    559             for (x=0; x < (ssize_t) image->columns; x++)
    560             {
    561               SetPixelIndex(image,ConstrainColormapIndex(image,*p,exception),q);
    562               p++;
    563               q+=GetPixelChannels(image);
    564             }
    565             if ((image->columns % 2) != 0)
    566               p++;
    567             if (SyncAuthenticPixels(image,exception) == MagickFalse)
    568               break;
    569             if (image->previous == (Image *) NULL)
    570               {
    571                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    572                 image->rows);
    573                 if (status == MagickFalse)
    574                   break;
    575               }
    576           }
    577         }
    578       else
    579         {
    580           size_t
    581             bytes_per_pixel;
    582 
    583           bytes_per_pixel=3;
    584           if (image->alpha_trait != UndefinedPixelTrait)
    585             bytes_per_pixel++;
    586           if (bytes_per_line == 0)
    587             bytes_per_line=bytes_per_pixel*image->columns;
    588           for (y=0; y < (ssize_t) image->rows; y++)
    589           {
    590             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    591             if (q == (Quantum *) NULL)
    592               break;
    593             for (x=0; x < (ssize_t) image->columns; x++)
    594             {
    595               if (image->alpha_trait != UndefinedPixelTrait)
    596                 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
    597               if (sun_info.type == RT_STANDARD)
    598                 {
    599                   SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
    600                   SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
    601                   SetPixelRed(image,ScaleCharToQuantum(*p++),q);
    602                 }
    603               else
    604                 {
    605                   SetPixelRed(image,ScaleCharToQuantum(*p++),q);
    606                   SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
    607                   SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
    608                 }
    609               if (image->colors != 0)
    610                 {
    611                   SetPixelRed(image,ClampToQuantum(image->colormap[(ssize_t)
    612                     GetPixelRed(image,q)].red),q);
    613                   SetPixelGreen(image,ClampToQuantum(image->colormap[(ssize_t)
    614                     GetPixelGreen(image,q)].green),q);
    615                   SetPixelBlue(image,ClampToQuantum(image->colormap[(ssize_t)
    616                     GetPixelBlue(image,q)].blue),q);
    617                 }
    618               q+=GetPixelChannels(image);
    619             }
    620             if (((bytes_per_pixel*image->columns) % 2) != 0)
    621               p++;
    622             if (SyncAuthenticPixels(image,exception) == MagickFalse)
    623               break;
    624             if (image->previous == (Image *) NULL)
    625               {
    626                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    627                 image->rows);
    628                 if (status == MagickFalse)
    629                   break;
    630               }
    631           }
    632         }
    633     if (image->storage_class == PseudoClass)
    634       (void) SyncImage(image,exception);
    635     sun_pixels=(unsigned char *) RelinquishMagickMemory(sun_pixels);
    636     if (EOFBlob(image) != MagickFalse)
    637       {
    638         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    639           image->filename);
    640         break;
    641       }
    642     /*
    643       Proceed to next image.
    644     */
    645     if (image_info->number_scenes != 0)
    646       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    647         break;
    648     sun_info.magic=ReadBlobMSBLong(image);
    649     if (sun_info.magic == 0x59a66a95)
    650       {
    651         /*
    652           Allocate next image structure.
    653         */
    654         AcquireNextImage(image_info,image,exception);
    655         if (GetNextImageInList(image) == (Image *) NULL)
    656           {
    657             status=MagickFalse;
    658             break;
    659           }
    660         image=SyncNextImageInList(image);
    661         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
    662           GetBlobSize(image));
    663         if (status == MagickFalse)
    664           break;
    665       }
    666   } while (sun_info.magic == 0x59a66a95);
    667   (void) CloseBlob(image);
    668   if (status == MagickFalse)
    669     return(DestroyImageList(image));
    670   return(GetFirstImageInList(image));
    671 }
    672 
    673 /*
    675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    676 %                                                                             %
    677 %                                                                             %
    678 %                                                                             %
    679 %   R e g i s t e r S U N I m a g e                                           %
    680 %                                                                             %
    681 %                                                                             %
    682 %                                                                             %
    683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    684 %
    685 %  RegisterSUNImage() adds attributes for the SUN image format to
    686 %  the list of supported formats.  The attributes include the image format
    687 %  tag, a method to read and/or write the format, whether the format
    688 %  supports the saving of more than one frame to the same file or blob,
    689 %  whether the format supports native in-memory I/O, and a brief
    690 %  description of the format.
    691 %
    692 %  The format of the RegisterSUNImage method is:
    693 %
    694 %      size_t RegisterSUNImage(void)
    695 %
    696 */
    697 ModuleExport size_t RegisterSUNImage(void)
    698 {
    699   MagickInfo
    700     *entry;
    701 
    702   entry=AcquireMagickInfo("SUN","RAS","SUN Rasterfile");
    703   entry->decoder=(DecodeImageHandler *) ReadSUNImage;
    704   entry->encoder=(EncodeImageHandler *) WriteSUNImage;
    705   entry->magick=(IsImageFormatHandler *) IsSUN;
    706   entry->flags|=CoderDecoderSeekableStreamFlag;
    707   (void) RegisterMagickInfo(entry);
    708   entry=AcquireMagickInfo("SUN","SUN","SUN Rasterfile");
    709   entry->decoder=(DecodeImageHandler *) ReadSUNImage;
    710   entry->encoder=(EncodeImageHandler *) WriteSUNImage;
    711   entry->flags|=CoderDecoderSeekableStreamFlag;
    712   (void) RegisterMagickInfo(entry);
    713   return(MagickImageCoderSignature);
    714 }
    715 
    716 /*
    718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    719 %                                                                             %
    720 %                                                                             %
    721 %                                                                             %
    722 %   U n r e g i s t e r S U N I m a g e                                       %
    723 %                                                                             %
    724 %                                                                             %
    725 %                                                                             %
    726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    727 %
    728 %  UnregisterSUNImage() removes format registrations made by the
    729 %  SUN module from the list of supported formats.
    730 %
    731 %  The format of the UnregisterSUNImage method is:
    732 %
    733 %      UnregisterSUNImage(void)
    734 %
    735 */
    736 ModuleExport void UnregisterSUNImage(void)
    737 {
    738   (void) UnregisterMagickInfo("RAS");
    739   (void) UnregisterMagickInfo("SUN");
    740 }
    741 
    742 /*
    744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    745 %                                                                             %
    746 %                                                                             %
    747 %                                                                             %
    748 %   W r i t e S U N I m a g e                                                 %
    749 %                                                                             %
    750 %                                                                             %
    751 %                                                                             %
    752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    753 %
    754 %  WriteSUNImage() writes an image in the SUN rasterfile format.
    755 %
    756 %  The format of the WriteSUNImage method is:
    757 %
    758 %      MagickBooleanType WriteSUNImage(const ImageInfo *image_info,
    759 %        Image *image,ExceptionInfo *exception)
    760 %
    761 %  A description of each parameter follows.
    762 %
    763 %    o image_info: the image info.
    764 %
    765 %    o image:  The image.
    766 %
    767 %    o exception: return any errors or warnings in this structure.
    768 %
    769 */
    770 static MagickBooleanType WriteSUNImage(const ImageInfo *image_info,Image *image,
    771   ExceptionInfo *exception)
    772 {
    773 #define RMT_EQUAL_RGB  1
    774 #define RMT_NONE  0
    775 #define RMT_RAW  2
    776 #define RT_STANDARD  1
    777 #define RT_FORMAT_RGB  3
    778 
    779   typedef struct _SUNInfo
    780   {
    781     unsigned int
    782       magic,
    783       width,
    784       height,
    785       depth,
    786       length,
    787       type,
    788       maptype,
    789       maplength;
    790   } SUNInfo;
    791 
    792   MagickBooleanType
    793     status;
    794 
    795   MagickOffsetType
    796     scene;
    797 
    798   MagickSizeType
    799     number_pixels;
    800 
    801   register const Quantum
    802     *p;
    803 
    804   register ssize_t
    805     i,
    806     x;
    807 
    808   size_t
    809     imageListLength;
    810 
    811   ssize_t
    812     y;
    813 
    814   SUNInfo
    815     sun_info;
    816 
    817   /*
    818     Open output image file.
    819   */
    820   assert(image_info != (const ImageInfo *) NULL);
    821   assert(image_info->signature == MagickCoreSignature);
    822   assert(image != (Image *) NULL);
    823   assert(image->signature == MagickCoreSignature);
    824   if (image->debug != MagickFalse)
    825     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    826   assert(exception != (ExceptionInfo *) NULL);
    827   assert(exception->signature == MagickCoreSignature);
    828   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    829   if (status == MagickFalse)
    830     return(status);
    831   scene=0;
    832   imageListLength=GetImageListLength(image);
    833   do
    834   {
    835     /*
    836       Initialize SUN raster file header.
    837     */
    838     (void) TransformImageColorspace(image,sRGBColorspace,exception);
    839     sun_info.magic=0x59a66a95;
    840     if ((image->columns != (unsigned int) image->columns) ||
    841         (image->rows != (unsigned int) image->rows))
    842       ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
    843     sun_info.width=(unsigned int) image->columns;
    844     sun_info.height=(unsigned int) image->rows;
    845     sun_info.type=(unsigned int)
    846       (image->storage_class == DirectClass ? RT_FORMAT_RGB : RT_STANDARD);
    847     sun_info.maptype=RMT_NONE;
    848     sun_info.maplength=0;
    849     number_pixels=(MagickSizeType) image->columns*image->rows;
    850     if ((4*number_pixels) != (size_t) (4*number_pixels))
    851       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    852     if (image->storage_class == DirectClass)
    853       {
    854         /*
    855           Full color SUN raster.
    856         */
    857         sun_info.depth=(unsigned int) image->alpha_trait !=
    858           UndefinedPixelTrait ? 32U : 24U;
    859         sun_info.length=(unsigned int) ((image->alpha_trait !=
    860           UndefinedPixelTrait ? 4 : 3)*number_pixels);
    861         sun_info.length+=sun_info.length & 0x01 ? (unsigned int) image->rows :
    862           0;
    863       }
    864     else
    865       if (SetImageMonochrome(image,exception) != MagickFalse)
    866         {
    867           /*
    868             Monochrome SUN raster.
    869           */
    870           sun_info.depth=1;
    871           sun_info.length=(unsigned int) (((image->columns+7) >> 3)*
    872             image->rows);
    873           sun_info.length+=(unsigned int) (((image->columns/8)+(image->columns %
    874             8 ? 1 : 0)) % 2 ? image->rows : 0);
    875         }
    876       else
    877         {
    878           /*
    879             Colormapped SUN raster.
    880           */
    881           sun_info.depth=8;
    882           sun_info.length=(unsigned int) number_pixels;
    883           sun_info.length+=(unsigned int) (image->columns & 0x01 ? image->rows :
    884             0);
    885           sun_info.maptype=RMT_EQUAL_RGB;
    886           sun_info.maplength=(unsigned int) (3*image->colors);
    887         }
    888     /*
    889       Write SUN header.
    890     */
    891     (void) WriteBlobMSBLong(image,sun_info.magic);
    892     (void) WriteBlobMSBLong(image,sun_info.width);
    893     (void) WriteBlobMSBLong(image,sun_info.height);
    894     (void) WriteBlobMSBLong(image,sun_info.depth);
    895     (void) WriteBlobMSBLong(image,sun_info.length);
    896     (void) WriteBlobMSBLong(image,sun_info.type);
    897     (void) WriteBlobMSBLong(image,sun_info.maptype);
    898     (void) WriteBlobMSBLong(image,sun_info.maplength);
    899     /*
    900       Convert MIFF to SUN raster pixels.
    901     */
    902     x=0;
    903     y=0;
    904     if (image->storage_class == DirectClass)
    905       {
    906         register unsigned char
    907           *q;
    908 
    909         size_t
    910           bytes_per_pixel,
    911           length;
    912 
    913         unsigned char
    914           *pixels;
    915 
    916         /*
    917           Allocate memory for pixels.
    918         */
    919         bytes_per_pixel=3;
    920         if (image->alpha_trait != UndefinedPixelTrait)
    921           bytes_per_pixel++;
    922         length=image->columns;
    923         pixels=(unsigned char *) AcquireQuantumMemory(length,4*sizeof(*pixels));
    924         if (pixels == (unsigned char *) NULL)
    925           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    926         /*
    927           Convert DirectClass packet to SUN RGB pixel.
    928         */
    929         for (y=0; y < (ssize_t) image->rows; y++)
    930         {
    931           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    932           if (p == (const Quantum *) NULL)
    933             break;
    934           q=pixels;
    935           for (x=0; x < (ssize_t) image->columns; x++)
    936           {
    937             if (image->alpha_trait != UndefinedPixelTrait)
    938               *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
    939             *q++=ScaleQuantumToChar(GetPixelRed(image,p));
    940             *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
    941             *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
    942             p+=GetPixelChannels(image);
    943           }
    944           if (((bytes_per_pixel*image->columns) & 0x01) != 0)
    945             *q++='\0';  /* pad scanline */
    946           (void) WriteBlob(image,(size_t) (q-pixels),pixels);
    947           if (image->previous == (Image *) NULL)
    948             {
    949               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    950                 image->rows);
    951               if (status == MagickFalse)
    952                 break;
    953             }
    954         }
    955         pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    956       }
    957     else
    958       if (SetImageMonochrome(image,exception) != MagickFalse)
    959         {
    960           register unsigned char
    961             bit,
    962             byte;
    963 
    964           /*
    965             Convert PseudoClass image to a SUN monochrome image.
    966           */
    967           (void) SetImageType(image,BilevelType,exception);
    968           for (y=0; y < (ssize_t) image->rows; y++)
    969           {
    970             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    971             if (p == (const Quantum *) NULL)
    972               break;
    973             bit=0;
    974             byte=0;
    975             for (x=0; x < (ssize_t) image->columns; x++)
    976             {
    977               byte<<=1;
    978               if (GetPixelLuma(image,p) < (QuantumRange/2.0))
    979                 byte|=0x01;
    980               bit++;
    981               if (bit == 8)
    982                 {
    983                   (void) WriteBlobByte(image,byte);
    984                   bit=0;
    985                   byte=0;
    986                 }
    987               p+=GetPixelChannels(image);
    988             }
    989             if (bit != 0)
    990               (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit)));
    991             if ((((image->columns/8)+
    992                 (image->columns % 8 ? 1 : 0)) % 2) != 0)
    993               (void) WriteBlobByte(image,0);  /* pad scanline */
    994             if (image->previous == (Image *) NULL)
    995               {
    996                 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    997                 image->rows);
    998                 if (status == MagickFalse)
    999                   break;
   1000               }
   1001           }
   1002         }
   1003       else
   1004         {
   1005           /*
   1006             Dump colormap to file.
   1007           */
   1008           for (i=0; i < (ssize_t) image->colors; i++)
   1009             (void) WriteBlobByte(image,ScaleQuantumToChar(
   1010               ClampToQuantum(image->colormap[i].red)));
   1011           for (i=0; i < (ssize_t) image->colors; i++)
   1012             (void) WriteBlobByte(image,ScaleQuantumToChar(
   1013               ClampToQuantum(image->colormap[i].green)));
   1014           for (i=0; i < (ssize_t) image->colors; i++)
   1015             (void) WriteBlobByte(image,ScaleQuantumToChar(
   1016               ClampToQuantum(image->colormap[i].blue)));
   1017           /*
   1018             Convert PseudoClass packet to SUN colormapped pixel.
   1019           */
   1020           for (y=0; y < (ssize_t) image->rows; y++)
   1021           {
   1022             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   1023             if (p == (const Quantum *) NULL)
   1024               break;
   1025             for (x=0; x < (ssize_t) image->columns; x++)
   1026             {
   1027               (void) WriteBlobByte(image,(unsigned char)
   1028                 GetPixelIndex(image,p));
   1029               p+=GetPixelChannels(image);
   1030             }
   1031             if (image->columns & 0x01)
   1032               (void) WriteBlobByte(image,0);  /* pad scanline */
   1033             if (image->previous == (Image *) NULL)
   1034               {
   1035                 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
   1036                   image->rows);
   1037                 if (status == MagickFalse)
   1038                   break;
   1039               }
   1040           }
   1041         }
   1042     if (GetNextImageInList(image) == (Image *) NULL)
   1043       break;
   1044     image=SyncNextImageInList(image);
   1045     status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
   1046     if (status == MagickFalse)
   1047       break;
   1048   } while (image_info->adjoin != MagickFalse);
   1049   (void) CloseBlob(image);
   1050   return(MagickTrue);
   1051 }
   1052