Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            SSSSS   GGGG  IIIII                              %
      7 %                            SS     G        I                                %
      8 %                             SSS   G  GG    I                                %
      9 %                               SS  G   G    I                                %
     10 %                            SSSSS   GGG   IIIII                              %
     11 %                                                                             %
     12 %                                                                             %
     13 %                      Read/Write Irix RGB Image Format                       %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 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 
     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/colorspace.h"
     52 #include "MagickCore/colorspace-private.h"
     53 #include "MagickCore/exception.h"
     54 #include "MagickCore/exception-private.h"
     55 #include "MagickCore/image.h"
     56 #include "MagickCore/image-private.h"
     57 #include "MagickCore/list.h"
     58 #include "MagickCore/magick.h"
     59 #include "MagickCore/memory_.h"
     60 #include "MagickCore/monitor.h"
     61 #include "MagickCore/monitor-private.h"
     62 #include "MagickCore/pixel-accessor.h"
     63 #include "MagickCore/property.h"
     64 #include "MagickCore/quantum-private.h"
     65 #include "MagickCore/static.h"
     66 #include "MagickCore/string_.h"
     67 #include "MagickCore/module.h"
     68 
     69 /*
     71   Typedef declaractions.
     72 */
     73 typedef struct _SGIInfo
     74 {
     75   unsigned short
     76     magic;
     77 
     78   unsigned char
     79     storage,
     80     bytes_per_pixel;
     81 
     82   unsigned short
     83     dimension,
     84     columns,
     85     rows,
     86     depth;
     87 
     88   size_t
     89     minimum_value,
     90     maximum_value,
     91     sans;
     92 
     93   char
     94     name[80];
     95 
     96   size_t
     97     pixel_format;
     98 
     99   unsigned char
    100     filler[404];
    101 } SGIInfo;
    102 
    103 /*
    105   Forward declarations.
    106 */
    107 static MagickBooleanType
    108   WriteSGIImage(const ImageInfo *,Image *,ExceptionInfo *);
    109 /*
    110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    111 %                                                                             %
    112 %                                                                             %
    113 %                                                                             %
    114 %   I s S G I                                                                 %
    115 %                                                                             %
    116 %                                                                             %
    117 %                                                                             %
    118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    119 %
    120 %  IsSGI() returns MagickTrue if the image format type, identified by the
    121 %  magick string, is SGI.
    122 %
    123 %  The format of the IsSGI method is:
    124 %
    125 %      MagickBooleanType IsSGI(const unsigned char *magick,const size_t length)
    126 %
    127 %  A description of each parameter follows:
    128 %
    129 %    o magick: compare image format pattern against these bytes.
    130 %
    131 %    o length: Specifies the length of the magick string.
    132 %
    133 */
    134 static MagickBooleanType IsSGI(const unsigned char *magick,const size_t length)
    135 {
    136   if (length < 2)
    137     return(MagickFalse);
    138   if (memcmp(magick,"\001\332",2) == 0)
    139     return(MagickTrue);
    140   return(MagickFalse);
    141 }
    142 
    143 /*
    145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    146 %                                                                             %
    147 %                                                                             %
    148 %                                                                             %
    149 %   R e a d S G I I m a g e                                                   %
    150 %                                                                             %
    151 %                                                                             %
    152 %                                                                             %
    153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    154 %
    155 %  ReadSGIImage() reads a SGI RGB image file and returns it.  It
    156 %  allocates the memory necessary for the new Image structure and returns a
    157 %  pointer to the new image.
    158 %
    159 %  The format of the ReadSGIImage method is:
    160 %
    161 %      Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
    162 %
    163 %  A description of each parameter follows:
    164 %
    165 %    o image_info: the image info.
    166 %
    167 %    o exception: return any errors or warnings in this structure.
    168 %
    169 */
    170 
    171 static MagickBooleanType SGIDecode(const size_t bytes_per_pixel,
    172   ssize_t number_packets,unsigned char *packets,ssize_t number_pixels,
    173   unsigned char *pixels)
    174 {
    175   register unsigned char
    176     *p,
    177     *q;
    178 
    179   size_t
    180     pixel;
    181 
    182   ssize_t
    183     count;
    184 
    185   p=packets;
    186   q=pixels;
    187   if (bytes_per_pixel == 2)
    188     {
    189       for ( ; number_pixels > 0; )
    190       {
    191         if (number_packets-- == 0)
    192           return(MagickFalse);
    193         pixel=(size_t) (*p++) << 8;
    194         pixel|=(*p++);
    195         count=(ssize_t) (pixel & 0x7f);
    196         if (count == 0)
    197           break;
    198         if (count > (ssize_t) number_pixels)
    199           return(MagickFalse);
    200         number_pixels-=count;
    201         if ((pixel & 0x80) != 0)
    202           for ( ; count != 0; count--)
    203           {
    204             if (number_packets-- == 0)
    205               return(MagickFalse);
    206             *q=(*p++);
    207             *(q+1)=(*p++);
    208             q+=8;
    209           }
    210         else
    211           {
    212             pixel=(size_t) (*p++) << 8;
    213             pixel|=(*p++);
    214             for ( ; count != 0; count--)
    215             {
    216               if (number_packets-- == 0)
    217                 return(MagickFalse);
    218               *q=(unsigned char) (pixel >> 8);
    219               *(q+1)=(unsigned char) pixel;
    220               q+=8;
    221             }
    222           }
    223       }
    224       return(MagickTrue);
    225     }
    226   for ( ; number_pixels > 0; )
    227   {
    228     if (number_packets-- == 0)
    229       return(MagickFalse);
    230     pixel=(size_t) (*p++);
    231     count=(ssize_t) (pixel & 0x7f);
    232     if (count == 0)
    233       break;
    234     if (count > (ssize_t) number_pixels)
    235       return(MagickFalse);
    236     number_pixels-=count;
    237     if ((pixel & 0x80) != 0)
    238       for ( ; count != 0; count--)
    239       {
    240         if (number_packets-- == 0)
    241           return(MagickFalse);
    242         *q=(*p++);
    243         q+=4;
    244       }
    245     else
    246       {
    247         if (number_packets-- == 0)
    248           return(MagickFalse);
    249         pixel=(size_t) (*p++);
    250         for ( ; count != 0; count--)
    251         {
    252           *q=(unsigned char) pixel;
    253           q+=4;
    254         }
    255       }
    256   }
    257   return(MagickTrue);
    258 }
    259 
    260 static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
    261 {
    262   Image
    263     *image;
    264 
    265   MagickBooleanType
    266     status;
    267 
    268   MagickSizeType
    269     number_pixels;
    270 
    271   MemoryInfo
    272     *pixel_info;
    273 
    274   register Quantum
    275     *q;
    276 
    277   register ssize_t
    278     i,
    279     x;
    280 
    281   register unsigned char
    282     *p;
    283 
    284   SGIInfo
    285     iris_info;
    286 
    287   size_t
    288     bytes_per_pixel,
    289     quantum;
    290 
    291   ssize_t
    292     count,
    293     y,
    294     z;
    295 
    296   unsigned char
    297     *pixels;
    298 
    299   /*
    300     Open image file.
    301   */
    302   assert(image_info != (const ImageInfo *) NULL);
    303   assert(image_info->signature == MagickCoreSignature);
    304   if (image_info->debug != MagickFalse)
    305     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    306       image_info->filename);
    307   assert(exception != (ExceptionInfo *) NULL);
    308   assert(exception->signature == MagickCoreSignature);
    309   image=AcquireImage(image_info,exception);
    310   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    311   if (status == MagickFalse)
    312     {
    313       image=DestroyImageList(image);
    314       return((Image *) NULL);
    315     }
    316   /*
    317     Read SGI raster header.
    318   */
    319   iris_info.magic=ReadBlobMSBShort(image);
    320   do
    321   {
    322     /*
    323       Verify SGI identifier.
    324     */
    325     if (iris_info.magic != 0x01DA)
    326       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    327     iris_info.storage=(unsigned char) ReadBlobByte(image);
    328     switch (iris_info.storage)
    329     {
    330       case 0x00: image->compression=NoCompression; break;
    331       case 0x01: image->compression=RLECompression; break;
    332       default:
    333         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    334     }
    335     iris_info.bytes_per_pixel=(unsigned char) ReadBlobByte(image);
    336     if ((iris_info.bytes_per_pixel == 0) || (iris_info.bytes_per_pixel > 2))
    337       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    338     iris_info.dimension=ReadBlobMSBShort(image);
    339     iris_info.columns=ReadBlobMSBShort(image);
    340     iris_info.rows=ReadBlobMSBShort(image);
    341     iris_info.depth=ReadBlobMSBShort(image);
    342     if ((iris_info.depth == 0) || (iris_info.depth > 4))
    343       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    344     iris_info.minimum_value=ReadBlobMSBLong(image);
    345     iris_info.maximum_value=ReadBlobMSBLong(image);
    346     iris_info.sans=ReadBlobMSBLong(image);
    347     (void) ReadBlob(image,sizeof(iris_info.name),(unsigned char *)
    348       iris_info.name);
    349     iris_info.name[sizeof(iris_info.name)-1]='\0';
    350     if (*iris_info.name != '\0')
    351       (void) SetImageProperty(image,"label",iris_info.name,exception);
    352     iris_info.pixel_format=ReadBlobMSBLong(image);
    353     if (iris_info.pixel_format != 0)
    354       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    355     count=ReadBlob(image,sizeof(iris_info.filler),iris_info.filler);
    356     (void) count;
    357     image->columns=iris_info.columns;
    358     image->rows=iris_info.rows;
    359     image->depth=(size_t) MagickMin(iris_info.depth,MAGICKCORE_QUANTUM_DEPTH);
    360     if (iris_info.pixel_format == 0)
    361       image->depth=(size_t) MagickMin((size_t) 8*
    362         iris_info.bytes_per_pixel,MAGICKCORE_QUANTUM_DEPTH);
    363     if (iris_info.depth < 3)
    364       {
    365         image->storage_class=PseudoClass;
    366         image->colors=iris_info.bytes_per_pixel > 1 ? 65535 : 256;
    367       }
    368     if ((image_info->ping != MagickFalse)  && (image_info->number_scenes != 0))
    369       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    370         break;
    371     status=SetImageExtent(image,image->columns,image->rows,exception);
    372     if (status == MagickFalse)
    373       return(DestroyImageList(image));
    374     /*
    375       Allocate SGI pixels.
    376     */
    377     bytes_per_pixel=(size_t) iris_info.bytes_per_pixel;
    378     number_pixels=(MagickSizeType) iris_info.columns*iris_info.rows;
    379     if ((4*bytes_per_pixel*number_pixels) != ((MagickSizeType) (size_t)
    380         (4*bytes_per_pixel*number_pixels)))
    381       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    382     pixel_info=AcquireVirtualMemory(iris_info.columns,iris_info.rows*4*
    383       bytes_per_pixel*sizeof(*pixels));
    384     if (pixel_info == (MemoryInfo *) NULL)
    385       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    386     pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
    387     if ((int) iris_info.storage != 0x01)
    388       {
    389         unsigned char
    390           *scanline;
    391 
    392         /*
    393           Read standard image format.
    394         */
    395         scanline=(unsigned char *) AcquireQuantumMemory(iris_info.columns,
    396           bytes_per_pixel*sizeof(*scanline));
    397         if (scanline == (unsigned char *) NULL)
    398           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    399         for (z=0; z < (ssize_t) iris_info.depth; z++)
    400         {
    401           p=pixels+bytes_per_pixel*z;
    402           for (y=0; y < (ssize_t) iris_info.rows; y++)
    403           {
    404             count=ReadBlob(image,bytes_per_pixel*iris_info.columns,scanline);
    405             if (EOFBlob(image) != MagickFalse)
    406               break;
    407             if (bytes_per_pixel == 2)
    408               for (x=0; x < (ssize_t) iris_info.columns; x++)
    409               {
    410                 *p=scanline[2*x];
    411                 *(p+1)=scanline[2*x+1];
    412                 p+=8;
    413               }
    414             else
    415               for (x=0; x < (ssize_t) iris_info.columns; x++)
    416               {
    417                 *p=scanline[x];
    418                 p+=4;
    419               }
    420           }
    421         }
    422         scanline=(unsigned char *) RelinquishMagickMemory(scanline);
    423       }
    424     else
    425       {
    426         MemoryInfo
    427           *packet_info;
    428 
    429         size_t
    430           *runlength;
    431 
    432         ssize_t
    433           offset,
    434           *offsets;
    435 
    436         unsigned char
    437           *packets;
    438 
    439         unsigned int
    440           data_order;
    441 
    442         /*
    443           Read runlength-encoded image format.
    444         */
    445         offsets=(ssize_t *) AcquireQuantumMemory((size_t) iris_info.rows,
    446           iris_info.depth*sizeof(*offsets));
    447         runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
    448           iris_info.depth*sizeof(*runlength));
    449         packet_info=AcquireVirtualMemory((size_t) iris_info.columns+10UL,4UL*
    450           sizeof(*packets));
    451         if ((offsets == (ssize_t *) NULL) ||
    452             (runlength == (size_t *) NULL) ||
    453             (packet_info == (MemoryInfo *) NULL))
    454           {
    455             if (offsets == (ssize_t *) NULL)
    456               offsets=(ssize_t *) RelinquishMagickMemory(offsets);
    457             if (runlength == (size_t *) NULL)
    458               runlength=(size_t *) RelinquishMagickMemory(runlength);
    459             if (packet_info == (MemoryInfo *) NULL)
    460               packet_info=RelinquishVirtualMemory(packet_info);
    461             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    462           }
    463         packets=(unsigned char *) GetVirtualMemoryBlob(packet_info);
    464         for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
    465           offsets[i]=ReadBlobMSBSignedLong(image);
    466         for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
    467         {
    468           runlength[i]=ReadBlobMSBLong(image);
    469           if (runlength[i] > (4*(size_t) iris_info.columns+10))
    470             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    471         }
    472         /*
    473           Check data order.
    474         */
    475         offset=0;
    476         data_order=0;
    477         for (y=0; ((y < (ssize_t) iris_info.rows) && (data_order == 0)); y++)
    478           for (z=0; ((z < (ssize_t) iris_info.depth) && (data_order == 0)); z++)
    479           {
    480             if (offsets[y+z*iris_info.rows] < offset)
    481               data_order=1;
    482             offset=offsets[y+z*iris_info.rows];
    483           }
    484         offset=(ssize_t) TellBlob(image);
    485         if (data_order == 1)
    486           {
    487             for (z=0; z < (ssize_t) iris_info.depth; z++)
    488             {
    489               p=pixels;
    490               for (y=0; y < (ssize_t) iris_info.rows; y++)
    491               {
    492                 if (offset != offsets[y+z*iris_info.rows])
    493                   {
    494                     offset=offsets[y+z*iris_info.rows];
    495                     offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET);
    496                   }
    497                 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
    498                   packets);
    499                 if (EOFBlob(image) != MagickFalse)
    500                   break;
    501                 offset+=(ssize_t) runlength[y+z*iris_info.rows];
    502                 status=SGIDecode(bytes_per_pixel,(ssize_t)
    503                   (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
    504                   1L*iris_info.columns,p+bytes_per_pixel*z);
    505                 if (status == MagickFalse)
    506                   ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    507                 p+=(iris_info.columns*4*bytes_per_pixel);
    508               }
    509             }
    510           }
    511         else
    512           {
    513             MagickOffsetType
    514               position;
    515 
    516             position=TellBlob(image);
    517             p=pixels;
    518             for (y=0; y < (ssize_t) iris_info.rows; y++)
    519             {
    520               for (z=0; z < (ssize_t) iris_info.depth; z++)
    521               {
    522                 if (offset != offsets[y+z*iris_info.rows])
    523                   {
    524                     offset=offsets[y+z*iris_info.rows];
    525                     offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET);
    526                   }
    527                 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
    528                   packets);
    529                 if (EOFBlob(image) != MagickFalse)
    530                   break;
    531                 offset+=(ssize_t) runlength[y+z*iris_info.rows];
    532                 status=SGIDecode(bytes_per_pixel,(ssize_t)
    533                   (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
    534                   1L*iris_info.columns,p+bytes_per_pixel*z);
    535                 if (status == MagickFalse)
    536                   ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    537               }
    538               p+=(iris_info.columns*4*bytes_per_pixel);
    539             }
    540             offset=(ssize_t) SeekBlob(image,position,SEEK_SET);
    541           }
    542         packet_info=RelinquishVirtualMemory(packet_info);
    543         runlength=(size_t *) RelinquishMagickMemory(runlength);
    544         offsets=(ssize_t *) RelinquishMagickMemory(offsets);
    545       }
    546     /*
    547       Initialize image structure.
    548     */
    549     image->alpha_trait=iris_info.depth == 4 ? BlendPixelTrait :
    550       UndefinedPixelTrait;
    551     image->columns=iris_info.columns;
    552     image->rows=iris_info.rows;
    553     /*
    554       Convert SGI raster image to pixel packets.
    555     */
    556     if (image->storage_class == DirectClass)
    557       {
    558         /*
    559           Convert SGI image to DirectClass pixel packets.
    560         */
    561         if (bytes_per_pixel == 2)
    562           {
    563             for (y=0; y < (ssize_t) image->rows; y++)
    564             {
    565               p=pixels+(image->rows-y-1)*8*image->columns;
    566               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    567               if (q == (Quantum *) NULL)
    568                 break;
    569               for (x=0; x < (ssize_t) image->columns; x++)
    570               {
    571                 SetPixelRed(image,ScaleShortToQuantum((unsigned short)
    572                   ((*(p+0) << 8) | (*(p+1)))),q);
    573                 SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
    574                   ((*(p+2) << 8) | (*(p+3)))),q);
    575                 SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
    576                   ((*(p+4) << 8) | (*(p+5)))),q);
    577                 SetPixelAlpha(image,OpaqueAlpha,q);
    578                 if (image->alpha_trait != UndefinedPixelTrait)
    579                   SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
    580                     ((*(p+6) << 8) | (*(p+7)))),q);
    581                 p+=8;
    582                 q+=GetPixelChannels(image);
    583               }
    584               if (SyncAuthenticPixels(image,exception) == MagickFalse)
    585                 break;
    586               if (image->previous == (Image *) NULL)
    587                 {
    588                   status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
    589                     y,image->rows);
    590                   if (status == MagickFalse)
    591                     break;
    592                 }
    593             }
    594           }
    595         else
    596           for (y=0; y < (ssize_t) image->rows; y++)
    597           {
    598             p=pixels+(image->rows-y-1)*4*image->columns;
    599             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    600             if (q == (Quantum *) NULL)
    601               break;
    602             for (x=0; x < (ssize_t) image->columns; x++)
    603             {
    604               SetPixelRed(image,ScaleCharToQuantum(*p),q);
    605               SetPixelGreen(image,ScaleCharToQuantum(*(p+1)),q);
    606               SetPixelBlue(image,ScaleCharToQuantum(*(p+2)),q);
    607               SetPixelAlpha(image,OpaqueAlpha,q);
    608               if (image->alpha_trait != UndefinedPixelTrait)
    609                 SetPixelAlpha(image,ScaleCharToQuantum(*(p+3)),q);
    610               p+=4;
    611               q+=GetPixelChannels(image);
    612             }
    613             if (SyncAuthenticPixels(image,exception) == MagickFalse)
    614               break;
    615             if (image->previous == (Image *) NULL)
    616               {
    617                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    618                   image->rows);
    619                 if (status == MagickFalse)
    620                   break;
    621               }
    622           }
    623       }
    624     else
    625       {
    626         /*
    627           Create grayscale map.
    628         */
    629         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
    630           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    631         /*
    632           Convert SGI image to PseudoClass pixel packets.
    633         */
    634         if (bytes_per_pixel == 2)
    635           {
    636             for (y=0; y < (ssize_t) image->rows; y++)
    637             {
    638               p=pixels+(image->rows-y-1)*8*image->columns;
    639               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    640               if (q == (Quantum *) NULL)
    641                 break;
    642               for (x=0; x < (ssize_t) image->columns; x++)
    643               {
    644                 quantum=(*p << 8);
    645                 quantum|=(*(p+1));
    646                 SetPixelIndex(image,(Quantum) quantum,q);
    647                 p+=8;
    648                 q+=GetPixelChannels(image);
    649               }
    650               if (SyncAuthenticPixels(image,exception) == MagickFalse)
    651                 break;
    652               if (image->previous == (Image *) NULL)
    653                 {
    654                   status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
    655                     y,image->rows);
    656                   if (status == MagickFalse)
    657                     break;
    658                 }
    659             }
    660           }
    661         else
    662           for (y=0; y < (ssize_t) image->rows; y++)
    663           {
    664             p=pixels+(image->rows-y-1)*4*image->columns;
    665             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    666             if (q == (Quantum *) NULL)
    667               break;
    668             for (x=0; x < (ssize_t) image->columns; x++)
    669             {
    670               SetPixelIndex(image,*p,q);
    671               p+=4;
    672               q+=GetPixelChannels(image);
    673             }
    674             if (SyncAuthenticPixels(image,exception) == MagickFalse)
    675               break;
    676             if (image->previous == (Image *) NULL)
    677               {
    678                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    679                 image->rows);
    680                 if (status == MagickFalse)
    681                   break;
    682               }
    683           }
    684         (void) SyncImage(image,exception);
    685       }
    686     pixel_info=RelinquishVirtualMemory(pixel_info);
    687     if (EOFBlob(image) != MagickFalse)
    688       {
    689         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    690           image->filename);
    691         break;
    692       }
    693     /*
    694       Proceed to next image.
    695     */
    696     if (image_info->number_scenes != 0)
    697       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    698         break;
    699     iris_info.magic=ReadBlobMSBShort(image);
    700     if (iris_info.magic == 0x01DA)
    701       {
    702         /*
    703           Allocate next image structure.
    704         */
    705         AcquireNextImage(image_info,image,exception);
    706         if (GetNextImageInList(image) == (Image *) NULL)
    707           {
    708             image=DestroyImageList(image);
    709             return((Image *) NULL);
    710           }
    711         image=SyncNextImageInList(image);
    712         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
    713           GetBlobSize(image));
    714         if (status == MagickFalse)
    715           break;
    716       }
    717   } while (iris_info.magic == 0x01DA);
    718   (void) CloseBlob(image);
    719   return(GetFirstImageInList(image));
    720 }
    721 
    722 /*
    724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    725 %                                                                             %
    726 %                                                                             %
    727 %                                                                             %
    728 %   R e g i s t e r S G I I m a g e                                           %
    729 %                                                                             %
    730 %                                                                             %
    731 %                                                                             %
    732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    733 %
    734 %  RegisterSGIImage() adds properties for the SGI image format to
    735 %  the list of supported formats.  The properties include the image format
    736 %  tag, a method to read and/or write the format, whether the format
    737 %  supports the saving of more than one frame to the same file or blob,
    738 %  whether the format supports native in-memory I/O, and a brief
    739 %  description of the format.
    740 %
    741 %  The format of the RegisterSGIImage method is:
    742 %
    743 %      size_t RegisterSGIImage(void)
    744 %
    745 */
    746 ModuleExport size_t RegisterSGIImage(void)
    747 {
    748   MagickInfo
    749     *entry;
    750 
    751   entry=AcquireMagickInfo("SGI","SGI","Irix RGB image");
    752   entry->decoder=(DecodeImageHandler *) ReadSGIImage;
    753   entry->encoder=(EncodeImageHandler *) WriteSGIImage;
    754   entry->magick=(IsImageFormatHandler *) IsSGI;
    755   entry->flags|=CoderSeekableStreamFlag;
    756   (void) RegisterMagickInfo(entry);
    757   return(MagickImageCoderSignature);
    758 }
    759 
    760 /*
    762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    763 %                                                                             %
    764 %                                                                             %
    765 %                                                                             %
    766 %   U n r e g i s t e r S G I I m a g e                                       %
    767 %                                                                             %
    768 %                                                                             %
    769 %                                                                             %
    770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    771 %
    772 %  UnregisterSGIImage() removes format registrations made by the
    773 %  SGI module from the list of supported formats.
    774 %
    775 %  The format of the UnregisterSGIImage method is:
    776 %
    777 %      UnregisterSGIImage(void)
    778 %
    779 */
    780 ModuleExport void UnregisterSGIImage(void)
    781 {
    782   (void) UnregisterMagickInfo("SGI");
    783 }
    784 
    785 /*
    787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    788 %                                                                             %
    789 %                                                                             %
    790 %                                                                             %
    791 %   W r i t e S G I I m a g e                                                 %
    792 %                                                                             %
    793 %                                                                             %
    794 %                                                                             %
    795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    796 %
    797 %  WriteSGIImage() writes an image in SGI RGB encoded image format.
    798 %
    799 %  The format of the WriteSGIImage method is:
    800 %
    801 %      MagickBooleanType WriteSGIImage(const ImageInfo *image_info,
    802 %        Image *image,ExceptionInfo *exception)
    803 %
    804 %  A description of each parameter follows.
    805 %
    806 %    o image_info: the image info.
    807 %
    808 %    o image:  The image.
    809 %
    810 %    o exception: return any errors or warnings in this structure.
    811 %
    812 */
    813 
    814 static size_t SGIEncode(unsigned char *pixels,size_t length,
    815   unsigned char *packets)
    816 {
    817   short
    818     runlength;
    819 
    820   register unsigned char
    821     *p,
    822     *q;
    823 
    824   unsigned char
    825     *limit,
    826     *mark;
    827 
    828   p=pixels;
    829   limit=p+length*4;
    830   q=packets;
    831   while (p < limit)
    832   {
    833     mark=p;
    834     p+=8;
    835     while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
    836       p+=4;
    837     p-=8;
    838     length=(size_t) (p-mark) >> 2;
    839     while (length != 0)
    840     {
    841       runlength=(short) (length > 126 ? 126 : length);
    842       length-=runlength;
    843       *q++=(unsigned char) (0x80 | runlength);
    844       for ( ; runlength > 0; runlength--)
    845       {
    846         *q++=(*mark);
    847         mark+=4;
    848       }
    849     }
    850     mark=p;
    851     p+=4;
    852     while ((p < limit) && (*p == *mark))
    853       p+=4;
    854     length=(size_t) (p-mark) >> 2;
    855     while (length != 0)
    856     {
    857       runlength=(short) (length > 126 ? 126 : length);
    858       length-=runlength;
    859       *q++=(unsigned char) runlength;
    860       *q++=(*mark);
    861     }
    862   }
    863   *q++='\0';
    864   return((size_t) (q-packets));
    865 }
    866 
    867 static MagickBooleanType WriteSGIImage(const ImageInfo *image_info,Image *image,
    868   ExceptionInfo *exception)
    869 {
    870   CompressionType
    871     compression;
    872 
    873   const char
    874     *value;
    875 
    876   MagickBooleanType
    877     status;
    878 
    879   MagickOffsetType
    880     scene;
    881 
    882   MagickSizeType
    883     number_pixels;
    884 
    885   MemoryInfo
    886     *pixel_info;
    887 
    888   SGIInfo
    889     iris_info;
    890 
    891   register const Quantum
    892     *p;
    893 
    894   register ssize_t
    895     i,
    896     x;
    897 
    898   register unsigned char
    899     *q;
    900 
    901   ssize_t
    902     y,
    903     z;
    904 
    905   unsigned char
    906     *pixels,
    907     *packets;
    908 
    909   /*
    910     Open output image file.
    911   */
    912   assert(image_info != (const ImageInfo *) NULL);
    913   assert(image_info->signature == MagickCoreSignature);
    914   assert(image != (Image *) NULL);
    915   assert(image->signature == MagickCoreSignature);
    916   if (image->debug != MagickFalse)
    917     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    918   if ((image->columns > 65535UL) || (image->rows > 65535UL))
    919     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
    920   assert(exception != (ExceptionInfo *) NULL);
    921   assert(exception->signature == MagickCoreSignature);
    922   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    923   if (status == MagickFalse)
    924     return(status);
    925   scene=0;
    926   do
    927   {
    928     /*
    929       Initialize SGI raster file header.
    930     */
    931     (void) TransformImageColorspace(image,sRGBColorspace,exception);
    932     (void) ResetMagickMemory(&iris_info,0,sizeof(iris_info));
    933     iris_info.magic=0x01DA;
    934     compression=image->compression;
    935     if (image_info->compression != UndefinedCompression)
    936       compression=image_info->compression;
    937     if (image->depth > 8)
    938       compression=NoCompression;
    939     if (compression == NoCompression)
    940       iris_info.storage=(unsigned char) 0x00;
    941     else
    942       iris_info.storage=(unsigned char) 0x01;
    943     iris_info.bytes_per_pixel=(unsigned char) (image->depth > 8 ? 2 : 1);
    944     iris_info.dimension=3;
    945     iris_info.columns=(unsigned short) image->columns;
    946     iris_info.rows=(unsigned short) image->rows;
    947     if (image->alpha_trait != UndefinedPixelTrait)
    948       iris_info.depth=4;
    949     else
    950       {
    951         if ((image_info->type != TrueColorType) &&
    952             (SetImageGray(image,exception) != MagickFalse))
    953           {
    954             iris_info.dimension=2;
    955             iris_info.depth=1;
    956           }
    957         else
    958           iris_info.depth=3;
    959       }
    960     iris_info.minimum_value=0;
    961     iris_info.maximum_value=(size_t) (image->depth <= 8 ?
    962       1UL*ScaleQuantumToChar(QuantumRange) :
    963       1UL*ScaleQuantumToShort(QuantumRange));
    964     /*
    965       Write SGI header.
    966     */
    967     (void) WriteBlobMSBShort(image,iris_info.magic);
    968     (void) WriteBlobByte(image,iris_info.storage);
    969     (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
    970     (void) WriteBlobMSBShort(image,iris_info.dimension);
    971     (void) WriteBlobMSBShort(image,iris_info.columns);
    972     (void) WriteBlobMSBShort(image,iris_info.rows);
    973     (void) WriteBlobMSBShort(image,iris_info.depth);
    974     (void) WriteBlobMSBLong(image,(unsigned int) iris_info.minimum_value);
    975     (void) WriteBlobMSBLong(image,(unsigned int) iris_info.maximum_value);
    976     (void) WriteBlobMSBLong(image,(unsigned int) iris_info.sans);
    977     value=GetImageProperty(image,"label",exception);
    978     if (value != (const char *) NULL)
    979       (void) CopyMagickString(iris_info.name,value,sizeof(iris_info.name));
    980     (void) WriteBlob(image,sizeof(iris_info.name),(unsigned char *)
    981       iris_info.name);
    982     (void) WriteBlobMSBLong(image,(unsigned int) iris_info.pixel_format);
    983     (void) WriteBlob(image,sizeof(iris_info.filler),iris_info.filler);
    984     /*
    985       Allocate SGI pixels.
    986     */
    987     number_pixels=(MagickSizeType) image->columns*image->rows;
    988     if ((4*iris_info.bytes_per_pixel*number_pixels) !=
    989         ((MagickSizeType) (size_t) (4*iris_info.bytes_per_pixel*number_pixels)))
    990       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    991     pixel_info=AcquireVirtualMemory((size_t) number_pixels,4*
    992       iris_info.bytes_per_pixel*sizeof(*pixels));
    993     if (pixel_info == (MemoryInfo *) NULL)
    994       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    995     pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
    996     /*
    997       Convert image pixels to uncompressed SGI pixels.
    998     */
    999     for (y=0; y < (ssize_t) image->rows; y++)
   1000     {
   1001       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   1002       if (p == (const Quantum *) NULL)
   1003         break;
   1004       if (image->depth <= 8)
   1005         for (x=0; x < (ssize_t) image->columns; x++)
   1006         {
   1007           register unsigned char
   1008             *q;
   1009 
   1010           q=(unsigned char *) pixels;
   1011           q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
   1012           *q++=ScaleQuantumToChar(GetPixelRed(image,p));
   1013           *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
   1014           *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
   1015           *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
   1016           p+=GetPixelChannels(image);
   1017         }
   1018       else
   1019         for (x=0; x < (ssize_t) image->columns; x++)
   1020         {
   1021           register unsigned short
   1022             *q;
   1023 
   1024           q=(unsigned short *) pixels;
   1025           q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
   1026           *q++=ScaleQuantumToShort(GetPixelRed(image,p));
   1027           *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
   1028           *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
   1029           *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
   1030           p+=GetPixelChannels(image);
   1031         }
   1032       if (image->previous == (Image *) NULL)
   1033         {
   1034           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
   1035             image->rows);
   1036           if (status == MagickFalse)
   1037             break;
   1038         }
   1039     }
   1040     switch (compression)
   1041     {
   1042       case NoCompression:
   1043       {
   1044         /*
   1045           Write uncompressed SGI pixels.
   1046         */
   1047         for (z=0; z < (ssize_t) iris_info.depth; z++)
   1048         {
   1049           for (y=0; y < (ssize_t) iris_info.rows; y++)
   1050           {
   1051             if (image->depth <= 8)
   1052               for (x=0; x < (ssize_t) iris_info.columns; x++)
   1053               {
   1054                 register unsigned char
   1055                   *q;
   1056 
   1057                 q=(unsigned char *) pixels;
   1058                 q+=y*(4*iris_info.columns)+4*x+z;
   1059                 (void) WriteBlobByte(image,*q);
   1060               }
   1061             else
   1062               for (x=0; x < (ssize_t) iris_info.columns; x++)
   1063               {
   1064                 register unsigned short
   1065                   *q;
   1066 
   1067                 q=(unsigned short *) pixels;
   1068                 q+=y*(4*iris_info.columns)+4*x+z;
   1069                 (void) WriteBlobMSBShort(image,*q);
   1070               }
   1071           }
   1072         }
   1073         break;
   1074       }
   1075       default:
   1076       {
   1077         MemoryInfo
   1078           *packet_info;
   1079 
   1080         size_t
   1081           length,
   1082           number_packets,
   1083           *runlength;
   1084 
   1085         ssize_t
   1086           offset,
   1087           *offsets;
   1088 
   1089         /*
   1090           Convert SGI uncompressed pixels.
   1091         */
   1092         offsets=(ssize_t *) AcquireQuantumMemory(iris_info.rows,
   1093           iris_info.depth*sizeof(*offsets));
   1094         runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
   1095           iris_info.depth*sizeof(*runlength));
   1096         packet_info=AcquireVirtualMemory((2*(size_t) iris_info.columns+10)*
   1097           image->rows,4*sizeof(*packets));
   1098         if ((offsets == (ssize_t *) NULL) ||
   1099             (runlength == (size_t *) NULL) ||
   1100             (packet_info == (MemoryInfo *) NULL))
   1101           {
   1102             if (offsets != (ssize_t *) NULL)
   1103               offsets=(ssize_t *) RelinquishMagickMemory(offsets);
   1104             if (runlength != (size_t *) NULL)
   1105               runlength=(size_t *) RelinquishMagickMemory(runlength);
   1106             if (packet_info != (MemoryInfo *) NULL)
   1107               packet_info=RelinquishVirtualMemory(packet_info);
   1108             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1109           }
   1110         packets=(unsigned char *) GetVirtualMemoryBlob(packet_info);
   1111         offset=512+4*2*((ssize_t) iris_info.rows*iris_info.depth);
   1112         number_packets=0;
   1113         q=pixels;
   1114         for (y=0; y < (ssize_t) iris_info.rows; y++)
   1115         {
   1116           for (z=0; z < (ssize_t) iris_info.depth; z++)
   1117           {
   1118             length=SGIEncode(q+z,(size_t) iris_info.columns,packets+
   1119               number_packets);
   1120             number_packets+=length;
   1121             offsets[y+z*iris_info.rows]=offset;
   1122             runlength[y+z*iris_info.rows]=(size_t) length;
   1123             offset+=(ssize_t) length;
   1124           }
   1125           q+=(iris_info.columns*4);
   1126         }
   1127         /*
   1128           Write out line start and length tables and runlength-encoded pixels.
   1129         */
   1130         for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
   1131           (void) WriteBlobMSBLong(image,(unsigned int) offsets[i]);
   1132         for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
   1133           (void) WriteBlobMSBLong(image,(unsigned int) runlength[i]);
   1134         (void) WriteBlob(image,number_packets,packets);
   1135         /*
   1136           Relinquish resources.
   1137         */
   1138         offsets=(ssize_t *) RelinquishMagickMemory(offsets);
   1139         runlength=(size_t *) RelinquishMagickMemory(runlength);
   1140         packet_info=RelinquishVirtualMemory(packet_info);
   1141         break;
   1142       }
   1143     }
   1144     pixel_info=RelinquishVirtualMemory(pixel_info);
   1145     if (GetNextImageInList(image) == (Image *) NULL)
   1146       break;
   1147     image=SyncNextImageInList(image);
   1148     status=SetImageProgress(image,SaveImagesTag,scene++,
   1149       GetImageListLength(image));
   1150     if (status == MagickFalse)
   1151       break;
   1152   } while (image_info->adjoin != MagickFalse);
   1153   (void) CloseBlob(image);
   1154   return(MagickTrue);
   1155 }
   1156