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-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/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             if (number_packets-- == 0)
    213               return(MagickFalse);
    214             pixel=(size_t) (*p++) << 8;
    215             pixel|=(*p++);
    216             for ( ; count != 0; count--)
    217             {
    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     n,
    270     number_pixels;
    271 
    272   MemoryInfo
    273     *pixel_info;
    274 
    275   register Quantum
    276     *q;
    277 
    278   register ssize_t
    279     i,
    280     x;
    281 
    282   register unsigned char
    283     *p;
    284 
    285   SGIInfo
    286     iris_info;
    287 
    288   size_t
    289     bytes_per_pixel,
    290     quantum;
    291 
    292   ssize_t
    293     count,
    294     y,
    295     z;
    296 
    297   unsigned char
    298     *pixels;
    299 
    300   /*
    301     Open image file.
    302   */
    303   assert(image_info != (const ImageInfo *) NULL);
    304   assert(image_info->signature == MagickCoreSignature);
    305   if (image_info->debug != MagickFalse)
    306     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    307       image_info->filename);
    308   assert(exception != (ExceptionInfo *) NULL);
    309   assert(exception->signature == MagickCoreSignature);
    310   image=AcquireImage(image_info,exception);
    311   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    312   if (status == MagickFalse)
    313     {
    314       image=DestroyImageList(image);
    315       return((Image *) NULL);
    316     }
    317   /*
    318     Read SGI raster header.
    319   */
    320   (void) memset(&iris_info,0,sizeof(iris_info));
    321   iris_info.magic=ReadBlobMSBShort(image);
    322   do
    323   {
    324     /*
    325       Verify SGI identifier.
    326     */
    327     if (iris_info.magic != 0x01DA)
    328       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    329     iris_info.storage=(unsigned char) ReadBlobByte(image);
    330     switch (iris_info.storage)
    331     {
    332       case 0x00: image->compression=NoCompression; break;
    333       case 0x01: image->compression=RLECompression; break;
    334       default:
    335         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    336     }
    337     iris_info.bytes_per_pixel=(unsigned char) ReadBlobByte(image);
    338     if ((iris_info.bytes_per_pixel == 0) || (iris_info.bytes_per_pixel > 2))
    339       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    340     iris_info.dimension=ReadBlobMSBShort(image);
    341     if ((iris_info.dimension == 0) || (iris_info.dimension > 3))
    342       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    343     iris_info.columns=ReadBlobMSBShort(image);
    344     iris_info.rows=ReadBlobMSBShort(image);
    345     iris_info.depth=ReadBlobMSBShort(image);
    346     if ((iris_info.depth == 0) || (iris_info.depth > 4))
    347       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    348     iris_info.minimum_value=ReadBlobMSBLong(image);
    349     iris_info.maximum_value=ReadBlobMSBLong(image);
    350     iris_info.sans=ReadBlobMSBLong(image);
    351     count=ReadBlob(image,sizeof(iris_info.name),(unsigned char *)
    352       iris_info.name);
    353     if ((size_t) count != sizeof(iris_info.name))
    354       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    355     iris_info.name[sizeof(iris_info.name)-1]='\0';
    356     if (*iris_info.name != '\0')
    357       (void) SetImageProperty(image,"label",iris_info.name,exception);
    358     iris_info.pixel_format=ReadBlobMSBLong(image);
    359     if (iris_info.pixel_format != 0)
    360       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    361     count=ReadBlob(image,sizeof(iris_info.filler),iris_info.filler);
    362     if ((size_t) count != sizeof(iris_info.filler))
    363       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    364     image->columns=iris_info.columns;
    365     image->rows=iris_info.rows;
    366     image->alpha_trait=iris_info.depth == 4 ? BlendPixelTrait :
    367       UndefinedPixelTrait;
    368     image->depth=(size_t) MagickMin(iris_info.depth,MAGICKCORE_QUANTUM_DEPTH);
    369     if (iris_info.pixel_format == 0)
    370       image->depth=(size_t) MagickMin((size_t) 8*iris_info.bytes_per_pixel,
    371         MAGICKCORE_QUANTUM_DEPTH);
    372     if (iris_info.depth < 3)
    373       {
    374         image->storage_class=PseudoClass;
    375         image->colors=(size_t) (iris_info.bytes_per_pixel > 1 ? 65535 : 256);
    376       }
    377     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
    378       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    379         break;
    380     if ((MagickSizeType) (image->columns*image->rows/255) > GetBlobSize(image))
    381       ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    382     status=SetImageExtent(image,image->columns,image->rows,exception);
    383     if (status != MagickFalse)
    384       status=ResetImagePixels(image,exception);
    385     if (status == MagickFalse)
    386       return(DestroyImageList(image));
    387     /*
    388       Allocate SGI pixels.
    389     */
    390     bytes_per_pixel=(size_t) iris_info.bytes_per_pixel;
    391     number_pixels=(MagickSizeType) iris_info.columns*iris_info.rows;
    392     if ((4*bytes_per_pixel*number_pixels) != ((MagickSizeType) (size_t)
    393         (4*bytes_per_pixel*number_pixels)))
    394       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    395     pixel_info=AcquireVirtualMemory(iris_info.columns,iris_info.rows*4*
    396       bytes_per_pixel*sizeof(*pixels));
    397     if (pixel_info == (MemoryInfo *) NULL)
    398       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    399     pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
    400     for (n=0; n < (4*bytes_per_pixel*number_pixels); n++)
    401       pixels[n]=0;
    402     if ((int) iris_info.storage != 0x01)
    403       {
    404         unsigned char
    405           *scanline;
    406 
    407         /*
    408           Read standard image format.
    409         */
    410         scanline=(unsigned char *) AcquireQuantumMemory(iris_info.columns,
    411           bytes_per_pixel*sizeof(*scanline));
    412         if (scanline == (unsigned char *) NULL)
    413           {
    414             pixel_info=RelinquishVirtualMemory(pixel_info);
    415             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    416           }
    417         for (z=0; z < (ssize_t) iris_info.depth; z++)
    418         {
    419           p=pixels+bytes_per_pixel*z;
    420           for (y=0; y < (ssize_t) iris_info.rows; y++)
    421           {
    422             count=ReadBlob(image,bytes_per_pixel*iris_info.columns,scanline);
    423             if (count != (ssize_t) (bytes_per_pixel*iris_info.columns))
    424               break;
    425             if (bytes_per_pixel == 2)
    426               for (x=0; x < (ssize_t) iris_info.columns; x++)
    427               {
    428                 *p=scanline[2*x];
    429                 *(p+1)=scanline[2*x+1];
    430                 p+=8;
    431               }
    432             else
    433               for (x=0; x < (ssize_t) iris_info.columns; x++)
    434               {
    435                 *p=scanline[x];
    436                 p+=4;
    437               }
    438           }
    439           if (y < (ssize_t) iris_info.rows)
    440             break;
    441         }
    442         scanline=(unsigned char *) RelinquishMagickMemory(scanline);
    443       }
    444     else
    445       {
    446         MemoryInfo
    447           *packet_info;
    448 
    449         size_t
    450           *runlength;
    451 
    452         ssize_t
    453           offset,
    454           *offsets;
    455 
    456         unsigned char
    457           *packets;
    458 
    459         unsigned int
    460           data_order;
    461 
    462         /*
    463           Read runlength-encoded image format.
    464         */
    465         offsets=(ssize_t *) AcquireQuantumMemory((size_t) iris_info.rows,
    466           iris_info.depth*sizeof(*offsets));
    467         runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
    468           iris_info.depth*sizeof(*runlength));
    469         packet_info=AcquireVirtualMemory((size_t) iris_info.columns+10UL,4UL*
    470           sizeof(*packets));
    471         if ((offsets == (ssize_t *) NULL) || (runlength == (size_t *) NULL) ||
    472             (packet_info == (MemoryInfo *) NULL))
    473           {
    474             offsets=(ssize_t *) RelinquishMagickMemory(offsets);
    475             runlength=(size_t *) RelinquishMagickMemory(runlength);
    476             if (packet_info != (MemoryInfo *) NULL)
    477               packet_info=RelinquishVirtualMemory(packet_info);
    478             pixel_info=RelinquishVirtualMemory(pixel_info);
    479             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    480           }
    481         packets=(unsigned char *) GetVirtualMemoryBlob(packet_info);
    482         for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
    483           offsets[i]=(ssize_t) ReadBlobMSBSignedLong(image);
    484         for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
    485         {
    486           runlength[i]=ReadBlobMSBLong(image);
    487           if (runlength[i] > (4*(size_t) iris_info.columns+10))
    488             {
    489               packet_info=RelinquishVirtualMemory(packet_info);
    490               runlength=(size_t *) RelinquishMagickMemory(runlength);
    491               offsets=(ssize_t *) RelinquishMagickMemory(offsets);
    492               pixel_info=RelinquishVirtualMemory(pixel_info);
    493               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    494             }
    495         }
    496         /*
    497           Check data order.
    498         */
    499         offset=0;
    500         data_order=0;
    501         for (y=0; ((y < (ssize_t) iris_info.rows) && (data_order == 0)); y++)
    502           for (z=0; ((z < (ssize_t) iris_info.depth) && (data_order == 0)); z++)
    503           {
    504             if (offsets[y+z*iris_info.rows] < offset)
    505               data_order=1;
    506             offset=offsets[y+z*iris_info.rows];
    507           }
    508         offset=(ssize_t) TellBlob(image);
    509         if (data_order == 1)
    510           {
    511             for (z=0; z < (ssize_t) iris_info.depth; z++)
    512             {
    513               p=pixels;
    514               for (y=0; y < (ssize_t) iris_info.rows; y++)
    515               {
    516                 if (offset != offsets[y+z*iris_info.rows])
    517                   {
    518                     offset=offsets[y+z*iris_info.rows];
    519                     offset=(ssize_t) SeekBlob(image,(MagickOffsetType) offset,
    520                       SEEK_SET);
    521                   }
    522                 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
    523                   packets);
    524                 if (count != (ssize_t) runlength[y+z*iris_info.rows])
    525                   break;
    526                 offset+=(ssize_t) runlength[y+z*iris_info.rows];
    527                 status=SGIDecode(bytes_per_pixel,(ssize_t)
    528                   (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
    529                   (ssize_t) iris_info.columns,p+bytes_per_pixel*z);
    530                 if (status == MagickFalse)
    531                   {
    532                     packet_info=RelinquishVirtualMemory(packet_info);
    533                     runlength=(size_t *) RelinquishMagickMemory(runlength);
    534                     offsets=(ssize_t *) RelinquishMagickMemory(offsets);
    535                     pixel_info=RelinquishVirtualMemory(pixel_info);
    536                     ThrowReaderException(CorruptImageError,
    537                       "ImproperImageHeader");
    538                   }
    539                 p+=(iris_info.columns*4*bytes_per_pixel);
    540               }
    541               if (y < (ssize_t) iris_info.rows)
    542                 break;
    543             }
    544           }
    545         else
    546           {
    547             MagickOffsetType
    548               position;
    549 
    550             position=TellBlob(image);
    551             p=pixels;
    552             for (y=0; y < (ssize_t) iris_info.rows; y++)
    553             {
    554               for (z=0; z < (ssize_t) iris_info.depth; z++)
    555               {
    556                 if (offset != offsets[y+z*iris_info.rows])
    557                   {
    558                     offset=offsets[y+z*iris_info.rows];
    559                     offset=(ssize_t) SeekBlob(image,(MagickOffsetType) offset,
    560                       SEEK_SET);
    561                   }
    562                 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
    563                   packets);
    564                 if (count != (ssize_t) runlength[y+z*iris_info.rows])
    565                   break;
    566                 offset+=(ssize_t) runlength[y+z*iris_info.rows];
    567                 status=SGIDecode(bytes_per_pixel,(ssize_t)
    568                   (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
    569                   (ssize_t) iris_info.columns,p+bytes_per_pixel*z);
    570                 if (status == MagickFalse)
    571                   {
    572                     packet_info=RelinquishVirtualMemory(packet_info);
    573                     runlength=(size_t *) RelinquishMagickMemory(runlength);
    574                     offsets=(ssize_t *) RelinquishMagickMemory(offsets);
    575                     pixel_info=RelinquishVirtualMemory(pixel_info);
    576                     ThrowReaderException(CorruptImageError,
    577                       "ImproperImageHeader");
    578                   }
    579               }
    580               if (z < (ssize_t) iris_info.depth)
    581                 break;
    582               p+=(iris_info.columns*4*bytes_per_pixel);
    583             }
    584             offset=(ssize_t) SeekBlob(image,position,SEEK_SET);
    585           }
    586         packet_info=RelinquishVirtualMemory(packet_info);
    587         runlength=(size_t *) RelinquishMagickMemory(runlength);
    588         offsets=(ssize_t *) RelinquishMagickMemory(offsets);
    589       }
    590     /*
    591       Convert SGI raster image to pixel packets.
    592     */
    593     if (image->storage_class == DirectClass)
    594       {
    595         /*
    596           Convert SGI image to DirectClass pixel packets.
    597         */
    598         if (bytes_per_pixel == 2)
    599           {
    600             for (y=0; y < (ssize_t) image->rows; y++)
    601             {
    602               p=pixels+(image->rows-y-1)*8*image->columns;
    603               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    604               if (q == (Quantum *) NULL)
    605                 break;
    606               for (x=0; x < (ssize_t) image->columns; x++)
    607               {
    608                 SetPixelRed(image,ScaleShortToQuantum((unsigned short)
    609                   ((*(p+0) << 8) | (*(p+1)))),q);
    610                 SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
    611                   ((*(p+2) << 8) | (*(p+3)))),q);
    612                 SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
    613                   ((*(p+4) << 8) | (*(p+5)))),q);
    614                 SetPixelAlpha(image,OpaqueAlpha,q);
    615                 if (image->alpha_trait != UndefinedPixelTrait)
    616                   SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
    617                     ((*(p+6) << 8) | (*(p+7)))),q);
    618                 p+=8;
    619                 q+=GetPixelChannels(image);
    620               }
    621               if (SyncAuthenticPixels(image,exception) == MagickFalse)
    622                 break;
    623               if (image->previous == (Image *) NULL)
    624                 {
    625                   status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
    626                     y,image->rows);
    627                   if (status == MagickFalse)
    628                     break;
    629                 }
    630             }
    631           }
    632         else
    633           for (y=0; y < (ssize_t) image->rows; y++)
    634           {
    635             p=pixels+(image->rows-y-1)*4*image->columns;
    636             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    637             if (q == (Quantum *) NULL)
    638               break;
    639             for (x=0; x < (ssize_t) image->columns; x++)
    640             {
    641               SetPixelRed(image,ScaleCharToQuantum(*p),q);
    642               SetPixelGreen(image,ScaleCharToQuantum(*(p+1)),q);
    643               SetPixelBlue(image,ScaleCharToQuantum(*(p+2)),q);
    644               SetPixelAlpha(image,OpaqueAlpha,q);
    645               if (image->alpha_trait != UndefinedPixelTrait)
    646                 SetPixelAlpha(image,ScaleCharToQuantum(*(p+3)),q);
    647               p+=4;
    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) y,
    655                   image->rows);
    656                 if (status == MagickFalse)
    657                   break;
    658               }
    659           }
    660       }
    661     else
    662       {
    663         /*
    664           Create grayscale map.
    665         */
    666         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
    667           {
    668             pixel_info=RelinquishVirtualMemory(pixel_info);
    669             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    670           }
    671         /*
    672           Convert SGI image to PseudoClass pixel packets.
    673         */
    674         if (bytes_per_pixel == 2)
    675           {
    676             for (y=0; y < (ssize_t) image->rows; y++)
    677             {
    678               p=pixels+(image->rows-y-1)*8*image->columns;
    679               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    680               if (q == (Quantum *) NULL)
    681                 break;
    682               for (x=0; x < (ssize_t) image->columns; x++)
    683               {
    684                 quantum=(*p << 8);
    685                 quantum|=(*(p+1));
    686                 SetPixelIndex(image,(Quantum) quantum,q);
    687                 p+=8;
    688                 q+=GetPixelChannels(image);
    689               }
    690               if (SyncAuthenticPixels(image,exception) == MagickFalse)
    691                 break;
    692               if (image->previous == (Image *) NULL)
    693                 {
    694                   status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
    695                     y,image->rows);
    696                   if (status == MagickFalse)
    697                     break;
    698                 }
    699             }
    700           }
    701         else
    702           for (y=0; y < (ssize_t) image->rows; y++)
    703           {
    704             p=pixels+(image->rows-y-1)*4*image->columns;
    705             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    706             if (q == (Quantum *) NULL)
    707               break;
    708             for (x=0; x < (ssize_t) image->columns; x++)
    709             {
    710               SetPixelIndex(image,*p,q);
    711               p+=4;
    712               q+=GetPixelChannels(image);
    713             }
    714             if (SyncAuthenticPixels(image,exception) == MagickFalse)
    715               break;
    716             if (image->previous == (Image *) NULL)
    717               {
    718                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    719                 image->rows);
    720                 if (status == MagickFalse)
    721                   break;
    722               }
    723           }
    724         (void) SyncImage(image,exception);
    725       }
    726     pixel_info=RelinquishVirtualMemory(pixel_info);
    727     if (EOFBlob(image) != MagickFalse)
    728       {
    729         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    730           image->filename);
    731         break;
    732       }
    733     /*
    734       Proceed to next image.
    735     */
    736     if (image_info->number_scenes != 0)
    737       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    738         break;
    739     iris_info.magic=ReadBlobMSBShort(image);
    740     if (iris_info.magic == 0x01DA)
    741       {
    742         /*
    743           Allocate next image structure.
    744         */
    745         AcquireNextImage(image_info,image,exception);
    746         if (GetNextImageInList(image) == (Image *) NULL)
    747           {
    748             status=MagickFalse;
    749             break;
    750           }
    751         image=SyncNextImageInList(image);
    752         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
    753           GetBlobSize(image));
    754         if (status == MagickFalse)
    755           break;
    756       }
    757   } while (iris_info.magic == 0x01DA);
    758   (void) CloseBlob(image);
    759   if (status == MagickFalse)
    760     return(DestroyImageList(image));
    761   return(GetFirstImageInList(image));
    762 }
    763 
    764 /*
    766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    767 %                                                                             %
    768 %                                                                             %
    769 %                                                                             %
    770 %   R e g i s t e r S G I I m a g e                                           %
    771 %                                                                             %
    772 %                                                                             %
    773 %                                                                             %
    774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    775 %
    776 %  RegisterSGIImage() adds properties for the SGI image format to
    777 %  the list of supported formats.  The properties include the image format
    778 %  tag, a method to read and/or write the format, whether the format
    779 %  supports the saving of more than one frame to the same file or blob,
    780 %  whether the format supports native in-memory I/O, and a brief
    781 %  description of the format.
    782 %
    783 %  The format of the RegisterSGIImage method is:
    784 %
    785 %      size_t RegisterSGIImage(void)
    786 %
    787 */
    788 ModuleExport size_t RegisterSGIImage(void)
    789 {
    790   MagickInfo
    791     *entry;
    792 
    793   entry=AcquireMagickInfo("SGI","SGI","Irix RGB image");
    794   entry->decoder=(DecodeImageHandler *) ReadSGIImage;
    795   entry->encoder=(EncodeImageHandler *) WriteSGIImage;
    796   entry->magick=(IsImageFormatHandler *) IsSGI;
    797   entry->flags|=CoderDecoderSeekableStreamFlag;
    798   (void) RegisterMagickInfo(entry);
    799   return(MagickImageCoderSignature);
    800 }
    801 
    802 /*
    804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    805 %                                                                             %
    806 %                                                                             %
    807 %                                                                             %
    808 %   U n r e g i s t e r S G I I m a g e                                       %
    809 %                                                                             %
    810 %                                                                             %
    811 %                                                                             %
    812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    813 %
    814 %  UnregisterSGIImage() removes format registrations made by the
    815 %  SGI module from the list of supported formats.
    816 %
    817 %  The format of the UnregisterSGIImage method is:
    818 %
    819 %      UnregisterSGIImage(void)
    820 %
    821 */
    822 ModuleExport void UnregisterSGIImage(void)
    823 {
    824   (void) UnregisterMagickInfo("SGI");
    825 }
    826 
    827 /*
    829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    830 %                                                                             %
    831 %                                                                             %
    832 %                                                                             %
    833 %   W r i t e S G I I m a g e                                                 %
    834 %                                                                             %
    835 %                                                                             %
    836 %                                                                             %
    837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    838 %
    839 %  WriteSGIImage() writes an image in SGI RGB encoded image format.
    840 %
    841 %  The format of the WriteSGIImage method is:
    842 %
    843 %      MagickBooleanType WriteSGIImage(const ImageInfo *image_info,
    844 %        Image *image,ExceptionInfo *exception)
    845 %
    846 %  A description of each parameter follows.
    847 %
    848 %    o image_info: the image info.
    849 %
    850 %    o image:  The image.
    851 %
    852 %    o exception: return any errors or warnings in this structure.
    853 %
    854 */
    855 
    856 static size_t SGIEncode(unsigned char *pixels,size_t length,
    857   unsigned char *packets)
    858 {
    859   short
    860     runlength;
    861 
    862   register unsigned char
    863     *p,
    864     *q;
    865 
    866   unsigned char
    867     *limit,
    868     *mark;
    869 
    870   p=pixels;
    871   limit=p+length*4;
    872   q=packets;
    873   while (p < limit)
    874   {
    875     mark=p;
    876     p+=8;
    877     while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
    878       p+=4;
    879     p-=8;
    880     length=(size_t) (p-mark) >> 2;
    881     while (length != 0)
    882     {
    883       runlength=(short) (length > 126 ? 126 : length);
    884       length-=runlength;
    885       *q++=(unsigned char) (0x80 | runlength);
    886       for ( ; runlength > 0; runlength--)
    887       {
    888         *q++=(*mark);
    889         mark+=4;
    890       }
    891     }
    892     mark=p;
    893     p+=4;
    894     while ((p < limit) && (*p == *mark))
    895       p+=4;
    896     length=(size_t) (p-mark) >> 2;
    897     while (length != 0)
    898     {
    899       runlength=(short) (length > 126 ? 126 : length);
    900       length-=runlength;
    901       *q++=(unsigned char) runlength;
    902       *q++=(*mark);
    903     }
    904   }
    905   *q++='\0';
    906   return((size_t) (q-packets));
    907 }
    908 
    909 static MagickBooleanType WriteSGIImage(const ImageInfo *image_info,Image *image,
    910   ExceptionInfo *exception)
    911 {
    912   CompressionType
    913     compression;
    914 
    915   const char
    916     *value;
    917 
    918   MagickBooleanType
    919     status;
    920 
    921   MagickOffsetType
    922     scene;
    923 
    924   MagickSizeType
    925     number_pixels;
    926 
    927   MemoryInfo
    928     *pixel_info;
    929 
    930   SGIInfo
    931     iris_info;
    932 
    933   register const Quantum
    934     *p;
    935 
    936   register ssize_t
    937     i,
    938     x;
    939 
    940   register unsigned char
    941     *q;
    942 
    943   size_t
    944     imageListLength;
    945 
    946   ssize_t
    947     y,
    948     z;
    949 
    950   unsigned char
    951     *pixels,
    952     *packets;
    953 
    954   /*
    955     Open output image file.
    956   */
    957   assert(image_info != (const ImageInfo *) NULL);
    958   assert(image_info->signature == MagickCoreSignature);
    959   assert(image != (Image *) NULL);
    960   assert(image->signature == MagickCoreSignature);
    961   if (image->debug != MagickFalse)
    962     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    963   if ((image->columns > 65535UL) || (image->rows > 65535UL))
    964     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
    965   assert(exception != (ExceptionInfo *) NULL);
    966   assert(exception->signature == MagickCoreSignature);
    967   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    968   if (status == MagickFalse)
    969     return(status);
    970   scene=0;
    971   imageListLength=GetImageListLength(image);
    972   do
    973   {
    974     /*
    975       Initialize SGI raster file header.
    976     */
    977     (void) TransformImageColorspace(image,sRGBColorspace,exception);
    978     (void) memset(&iris_info,0,sizeof(iris_info));
    979     iris_info.magic=0x01DA;
    980     compression=image->compression;
    981     if (image_info->compression != UndefinedCompression)
    982       compression=image_info->compression;
    983     if (image->depth > 8)
    984       compression=NoCompression;
    985     if (compression == NoCompression)
    986       iris_info.storage=(unsigned char) 0x00;
    987     else
    988       iris_info.storage=(unsigned char) 0x01;
    989     iris_info.bytes_per_pixel=(unsigned char) (image->depth > 8 ? 2 : 1);
    990     iris_info.dimension=3;
    991     iris_info.columns=(unsigned short) image->columns;
    992     iris_info.rows=(unsigned short) image->rows;
    993     if (image->alpha_trait != UndefinedPixelTrait)
    994       iris_info.depth=4;
    995     else
    996       {
    997         if ((image_info->type != TrueColorType) &&
    998             (SetImageGray(image,exception) != MagickFalse))
    999           {
   1000             iris_info.dimension=2;
   1001             iris_info.depth=1;
   1002           }
   1003         else
   1004           iris_info.depth=3;
   1005       }
   1006     iris_info.minimum_value=0;
   1007     iris_info.maximum_value=(size_t) (image->depth <= 8 ?
   1008       1UL*ScaleQuantumToChar(QuantumRange) :
   1009       1UL*ScaleQuantumToShort(QuantumRange));
   1010     /*
   1011       Write SGI header.
   1012     */
   1013     (void) WriteBlobMSBShort(image,iris_info.magic);
   1014     (void) WriteBlobByte(image,iris_info.storage);
   1015     (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
   1016     (void) WriteBlobMSBShort(image,iris_info.dimension);
   1017     (void) WriteBlobMSBShort(image,iris_info.columns);
   1018     (void) WriteBlobMSBShort(image,iris_info.rows);
   1019     (void) WriteBlobMSBShort(image,iris_info.depth);
   1020     (void) WriteBlobMSBLong(image,(unsigned int) iris_info.minimum_value);
   1021     (void) WriteBlobMSBLong(image,(unsigned int) iris_info.maximum_value);
   1022     (void) WriteBlobMSBLong(image,(unsigned int) iris_info.sans);
   1023     value=GetImageProperty(image,"label",exception);
   1024     if (value != (const char *) NULL)
   1025       (void) CopyMagickString(iris_info.name,value,sizeof(iris_info.name));
   1026     (void) WriteBlob(image,sizeof(iris_info.name),(unsigned char *)
   1027       iris_info.name);
   1028     (void) WriteBlobMSBLong(image,(unsigned int) iris_info.pixel_format);
   1029     (void) WriteBlob(image,sizeof(iris_info.filler),iris_info.filler);
   1030     /*
   1031       Allocate SGI pixels.
   1032     */
   1033     number_pixels=(MagickSizeType) image->columns*image->rows;
   1034     if ((4*iris_info.bytes_per_pixel*number_pixels) !=
   1035         ((MagickSizeType) (size_t) (4*iris_info.bytes_per_pixel*number_pixels)))
   1036       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1037     pixel_info=AcquireVirtualMemory((size_t) number_pixels,4*
   1038       iris_info.bytes_per_pixel*sizeof(*pixels));
   1039     if (pixel_info == (MemoryInfo *) NULL)
   1040       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1041     pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
   1042     /*
   1043       Convert image pixels to uncompressed SGI pixels.
   1044     */
   1045     for (y=0; y < (ssize_t) image->rows; y++)
   1046     {
   1047       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   1048       if (p == (const Quantum *) NULL)
   1049         break;
   1050       if (image->depth <= 8)
   1051         for (x=0; x < (ssize_t) image->columns; x++)
   1052         {
   1053           register unsigned char
   1054             *q;
   1055 
   1056           q=(unsigned char *) pixels;
   1057           q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
   1058           *q++=ScaleQuantumToChar(GetPixelRed(image,p));
   1059           *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
   1060           *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
   1061           *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
   1062           p+=GetPixelChannels(image);
   1063         }
   1064       else
   1065         for (x=0; x < (ssize_t) image->columns; x++)
   1066         {
   1067           register unsigned short
   1068             *q;
   1069 
   1070           q=(unsigned short *) pixels;
   1071           q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
   1072           *q++=ScaleQuantumToShort(GetPixelRed(image,p));
   1073           *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
   1074           *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
   1075           *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
   1076           p+=GetPixelChannels(image);
   1077         }
   1078       if (image->previous == (Image *) NULL)
   1079         {
   1080           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
   1081             image->rows);
   1082           if (status == MagickFalse)
   1083             break;
   1084         }
   1085     }
   1086     switch (compression)
   1087     {
   1088       case NoCompression:
   1089       {
   1090         /*
   1091           Write uncompressed SGI pixels.
   1092         */
   1093         for (z=0; z < (ssize_t) iris_info.depth; z++)
   1094         {
   1095           for (y=0; y < (ssize_t) iris_info.rows; y++)
   1096           {
   1097             if (image->depth <= 8)
   1098               for (x=0; x < (ssize_t) iris_info.columns; x++)
   1099               {
   1100                 register unsigned char
   1101                   *q;
   1102 
   1103                 q=(unsigned char *) pixels;
   1104                 q+=y*(4*iris_info.columns)+4*x+z;
   1105                 (void) WriteBlobByte(image,*q);
   1106               }
   1107             else
   1108               for (x=0; x < (ssize_t) iris_info.columns; x++)
   1109               {
   1110                 register unsigned short
   1111                   *q;
   1112 
   1113                 q=(unsigned short *) pixels;
   1114                 q+=y*(4*iris_info.columns)+4*x+z;
   1115                 (void) WriteBlobMSBShort(image,*q);
   1116               }
   1117           }
   1118         }
   1119         break;
   1120       }
   1121       default:
   1122       {
   1123         MemoryInfo
   1124           *packet_info;
   1125 
   1126         size_t
   1127           length,
   1128           number_packets,
   1129           *runlength;
   1130 
   1131         ssize_t
   1132           offset,
   1133           *offsets;
   1134 
   1135         /*
   1136           Convert SGI uncompressed pixels.
   1137         */
   1138         offsets=(ssize_t *) AcquireQuantumMemory(iris_info.rows,
   1139           iris_info.depth*sizeof(*offsets));
   1140         runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
   1141           iris_info.depth*sizeof(*runlength));
   1142         packet_info=AcquireVirtualMemory((2*(size_t) iris_info.columns+10)*
   1143           image->rows,4*sizeof(*packets));
   1144         if ((offsets == (ssize_t *) NULL) ||
   1145             (runlength == (size_t *) NULL) ||
   1146             (packet_info == (MemoryInfo *) NULL))
   1147           {
   1148             if (offsets != (ssize_t *) NULL)
   1149               offsets=(ssize_t *) RelinquishMagickMemory(offsets);
   1150             if (runlength != (size_t *) NULL)
   1151               runlength=(size_t *) RelinquishMagickMemory(runlength);
   1152             if (packet_info != (MemoryInfo *) NULL)
   1153               packet_info=RelinquishVirtualMemory(packet_info);
   1154             pixel_info=RelinquishVirtualMemory(pixel_info);
   1155             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1156           }
   1157         packets=(unsigned char *) GetVirtualMemoryBlob(packet_info);
   1158         offset=512+4*2*((ssize_t) iris_info.rows*iris_info.depth);
   1159         number_packets=0;
   1160         q=pixels;
   1161         for (y=0; y < (ssize_t) iris_info.rows; y++)
   1162         {
   1163           for (z=0; z < (ssize_t) iris_info.depth; z++)
   1164           {
   1165             length=SGIEncode(q+z,(size_t) iris_info.columns,packets+
   1166               number_packets);
   1167             number_packets+=length;
   1168             offsets[y+z*iris_info.rows]=offset;
   1169             runlength[y+z*iris_info.rows]=(size_t) length;
   1170             offset+=(ssize_t) length;
   1171           }
   1172           q+=(iris_info.columns*4);
   1173         }
   1174         /*
   1175           Write out line start and length tables and runlength-encoded pixels.
   1176         */
   1177         for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
   1178           (void) WriteBlobMSBLong(image,(unsigned int) offsets[i]);
   1179         for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
   1180           (void) WriteBlobMSBLong(image,(unsigned int) runlength[i]);
   1181         (void) WriteBlob(image,number_packets,packets);
   1182         /*
   1183           Relinquish resources.
   1184         */
   1185         offsets=(ssize_t *) RelinquishMagickMemory(offsets);
   1186         runlength=(size_t *) RelinquishMagickMemory(runlength);
   1187         packet_info=RelinquishVirtualMemory(packet_info);
   1188         break;
   1189       }
   1190     }
   1191     pixel_info=RelinquishVirtualMemory(pixel_info);
   1192     if (GetNextImageInList(image) == (Image *) NULL)
   1193       break;
   1194     image=SyncNextImageInList(image);
   1195     status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
   1196     if (status == MagickFalse)
   1197       break;
   1198   } while (image_info->adjoin != MagickFalse);
   1199   (void) CloseBlob(image);
   1200   return(MagickTrue);
   1201 }
   1202