Coverage Report

Created: 2026-05-24 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/sgi.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                            SSSSS   GGGG  IIIII                              %
15
%                            SS     G        I                                %
16
%                             SSS   G  GG    I                                %
17
%                               SS  G   G    I                                %
18
%                            SSSSS   GGG   IIIII                              %
19
%                                                                             %
20
%                                                                             %
21
%                     Read/Write Irix RGB Image Format.                       %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                                 July 1992                                   %
27
%                                                                             %
28
%                                                                             %
29
%                                                                             %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31
%
32
%
33
*/
34

35
/*
36
  Include declarations.
37
*/
38
#include "magick/studio.h"
39
#include "magick/analyze.h"
40
#include "magick/attribute.h"
41
#include "magick/blob.h"
42
#include "magick/colormap.h"
43
#include "magick/log.h"
44
#include "magick/magick.h"
45
#include "magick/magick_endian.h"
46
#include "magick/monitor.h"
47
#include "magick/pixel_cache.h"
48
#include "magick/utility.h"
49
#include "magick/static.h"
50

51
/*
52
  Typedef declaractions.
53
*/
54
55
/*
56
  The SGI file header is 512 bytes in size.
57
*/
58
typedef struct _SGIInfo
59
{
60
  unsigned short
61
    magic;                  /* Identification number (474) */
62
63
  magick_int8_t
64
    storage,                /* Compression flag */
65
    bytes_per_pixel;        /* Bytes per pixel (per bit plane) */
66
67
  magick_uint16_t
68
    dimension,              /* Number of image dimensions */
69
    xsize,                  /* Width of image in pixels */
70
    ysize,                  /* Height of image in pixels */
71
    zsize;                  /* Number of bit planes */
72
73
  magick_uint32_t
74
    pix_min,                /* Smallest pixel component value */
75
    pix_max;                /* Largest pixel component value */
76
77
  char
78
    dummy1[4];              /* Not used */
79
80
  char
81
    image_name[80];         /* Name of image (null terminated) */
82
83
  magick_uint32_t
84
    color_map;              /* Format of pixel data */
85
86
  char
87
    dummy2[404];            /* Not used */
88
} SGIInfo;
89

90
/*
91
  Forward declarations.
92
*/
93
static unsigned int
94
  WriteSGIImage(const ImageInfo *,Image *);
95
/*
96
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97
%                                                                             %
98
%                                                                             %
99
%                                                                             %
100
%   I s S G I                                                                 %
101
%                                                                             %
102
%                                                                             %
103
%                                                                             %
104
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105
%
106
%  Method IsSGI returns True if the image format type, identified by the
107
%  magick string, is SGI.
108
%
109
%  The format of the IsSGI method is:
110
%
111
%      unsigned int IsSGI(const unsigned char *magick,const size_t length)
112
%
113
%  A description of each parameter follows:
114
%
115
%    o status:  Method IsSGI returns True if the image format type is SGI.
116
%
117
%    o magick: This string is generally the first few bytes of an image file
118
%      or blob.
119
%
120
%    o length: Specifies the length of the magick string.
121
%
122
%
123
*/
124
static unsigned int IsSGI(const unsigned char *magick,const size_t length)
125
0
{
126
0
  if (length < 2)
127
0
    return(False);
128
0
  if (memcmp(magick,"\001\332",2) == 0)
129
0
    return(True);
130
0
  return(False);
131
0
}
132

133
/*
134
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135
%                                                                             %
136
%                                                                             %
137
%                                                                             %
138
%   R e a d S G I I m a g e                                                   %
139
%                                                                             %
140
%                                                                             %
141
%                                                                             %
142
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
%
144
%  Method ReadSGIImage reads a SGI RGB image file and returns it.  It
145
%  allocates the memory necessary for the new Image structure and returns a
146
%  pointer to the new image.
147
%
148
%  The format of the ReadSGIImage method is:
149
%
150
%      Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
151
%
152
%  A description of each parameter follows:
153
%
154
%    o image:  Method ReadSGIImage returns a pointer to the image after
155
%      reading.  A null image is returned if there is a memory shortage or
156
%      if the image cannot be read.
157
%
158
%    o image_info: Specifies a pointer to a ImageInfo structure.
159
%
160
%    o exception: return any errors or warnings in this structure.
161
%
162
%
163
*/
164
165
static int SGIDecode(const size_t bytes_per_pixel,
166
                     unsigned char *max_packets,unsigned char *pixels,
167
                     size_t npackets,size_t npixels)
168
8.62k
{
169
8.62k
  size_t
170
8.62k
    count;
171
172
8.62k
  register unsigned char
173
8.62k
    *p,
174
8.62k
    *q;
175
176
8.62k
  unsigned int
177
8.62k
    pixel;
178
179
8.62k
  p=max_packets;
180
8.62k
  q=pixels;
181
8.62k
  if (bytes_per_pixel == 2)
182
2.03k
    {
183
2.03k
      for ( ; ; )
184
4.83k
        {
185
4.83k
          if (npackets-- == 0)
186
64
            return -1;
187
4.77k
          pixel=(*p++) << 8U;
188
4.77k
          pixel|=(*p++);
189
4.77k
          count=(pixel & 0x7fU);
190
4.77k
          if (count == 0)
191
1.36k
            break;
192
3.40k
          if (count > npixels)
193
484
            return -1;
194
2.92k
          npixels -= count;
195
2.92k
          if (pixel & 0x80U)
196
19.2k
            for ( ; count != 0U; count--)
197
18.5k
              {
198
18.5k
                if (npackets-- == 0)
199
21
                  return -1;
200
18.5k
                *q=(*p++);
201
18.5k
                *(q+1)=(*p++);
202
18.5k
                q+=8U;
203
18.5k
              }
204
2.27k
          else
205
2.27k
            {
206
2.27k
              if (npackets-- == 0)
207
102
                return -1;
208
2.17k
              pixel=(*p++) << 8U;
209
2.17k
              pixel|=(*p++);
210
78.3k
              for ( ; count != 0; count--)
211
76.1k
                {
212
76.1k
                  *q=(unsigned char) (pixel >> 8U);
213
76.1k
                  *(q+1)=(unsigned char) pixel;
214
76.1k
                  q+=8U;
215
76.1k
                }
216
2.17k
            }
217
2.92k
        }
218
1.36k
      return 0;
219
2.03k
    }
220
6.59k
  for ( ; ; )
221
18.8k
    {
222
18.8k
      if (npackets-- == 0)
223
325
        return -1;
224
18.5k
      pixel=(*p++);
225
18.5k
      count= (pixel & 0x7fU);
226
18.5k
      if (count == 0)
227
4.87k
        break;
228
13.6k
      if (count > npixels)
229
1.13k
        return -1;
230
12.4k
      npixels -= count;
231
12.4k
      if (pixel & 0x80)
232
243k
        for ( ; count != 0; count--)
233
238k
          {
234
238k
            if (npackets-- == 0)
235
19
              return -1;
236
238k
            *q=(*p++);
237
238k
            q+=4;
238
238k
          }
239
7.99k
      else
240
7.99k
        {
241
7.99k
          if (npackets-- == 0)
242
239
            return -1;
243
7.75k
          pixel=(*p++);
244
244k
          for ( ; count != 0; count--)
245
236k
            {
246
236k
              *q=(unsigned char) pixel;
247
236k
              q+=4;
248
236k
            }
249
7.75k
        }
250
12.4k
    }
251
4.87k
  return 0;
252
6.59k
}
253
254
12.9k
#define ThrowSGIReaderException(code_,reason_,image_) \
255
12.9k
{ \
256
12.9k
  MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels) \
257
12.9k
  MagickFreeResourceLimitedMemory(unsigned char *,max_packets); \
258
12.9k
  MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);   \
259
12.9k
  MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength); \
260
12.9k
  MagickFreeResourceLimitedMemory(unsigned char *,scanline) \
261
12.9k
  ThrowReaderException(code_,reason_,image_); \
262
0
}
263
264
static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
265
127k
{
266
127k
  Image
267
127k
    *image;
268
269
127k
  size_t
270
127k
    z;
271
272
127k
  register IndexPacket
273
127k
    *indexes;
274
275
127k
  register size_t
276
127k
    i;
277
278
127k
  unsigned long
279
127k
        x,
280
127k
    y;
281
282
127k
  register PixelPacket
283
127k
    *q;
284
285
127k
  register unsigned char
286
127k
    *p;
287
288
127k
  SGIInfo
289
127k
    iris_info;
290
291
127k
  magick_uint32_t
292
127k
    *offsets = (magick_uint32_t *) NULL,
293
127k
    *runlength = (magick_uint32_t *) NULL;
294
295
127k
  unsigned char
296
127k
    *iris_pixels = (unsigned char *) NULL,
297
127k
    *max_packets = (unsigned char *) NULL,
298
127k
    *scanline = (unsigned char *) NULL;
299
300
127k
  unsigned int
301
127k
    status;
302
303
127k
  size_t
304
127k
    bytes_per_pixel;
305
306
127k
  magick_off_t
307
127k
    file_size;
308
309
  /*
310
    Open image file.
311
  */
312
127k
  assert(image_info != (const ImageInfo *) NULL);
313
127k
  assert(image_info->signature == MagickSignature);
314
127k
  assert(exception != (ExceptionInfo *) NULL);
315
127k
  assert(exception->signature == MagickSignature);
316
127k
  image=AllocateImage(image_info);
317
127k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
318
127k
  if (status == False)
319
127k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
320
127k
  file_size=GetBlobSize(image);
321
127k
  do
322
127k
    {
323
      /*
324
        Read SGI raster header.
325
      */
326
127k
      (void) memset(&iris_info, 0, sizeof(iris_info));
327
127k
      iris_info.magic=ReadBlobMSBShort(image);
328
127k
      iris_info.storage=ReadBlobByte(image);
329
127k
      iris_info.bytes_per_pixel=ReadBlobByte(image) &0xF;
330
127k
      iris_info.dimension=ReadBlobMSBShort(image) & 0xFFFF;
331
127k
      iris_info.xsize=ReadBlobMSBShort(image) & 0xFFFF;
332
127k
      iris_info.ysize=ReadBlobMSBShort(image) & 0xFFFF;
333
127k
      iris_info.zsize=ReadBlobMSBShort(image) & 0xFFFF;
334
127k
      iris_info.pix_min=ReadBlobMSBLong(image) & 0xFFFFFFFF;
335
127k
      iris_info.pix_max=ReadBlobMSBLong(image) & 0xFFFFFFFF;
336
337
127k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.dummy1),
338
127k
                      iris_info.dummy1);
339
127k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.image_name),
340
127k
                      iris_info.image_name);
341
127k
      iris_info.image_name[sizeof(iris_info.image_name)-1]=0;
342
127k
      iris_info.color_map=ReadBlobMSBLong(image);
343
127k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.dummy2),
344
127k
                      iris_info.dummy2);
345
346
127k
      if (EOFBlob(image))
347
110k
        ThrowReaderException(CorruptImageError,UnableToReadImageHeader,image);
348
349
17.2k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
350
17.2k
                            "IRIS Header:\n"
351
17.2k
                            "    MAGIC=%u\n"
352
17.2k
                            "    STORAGE=%u (%s)\n"
353
17.2k
                            "    BPC=%u\n"
354
17.2k
                            "    DIMENSION=%u\n"
355
17.2k
                            "    XSIZE=%u\n"
356
17.2k
                            "    YSIZE=%u\n"
357
17.2k
                            "    ZSIZE=%u\n"
358
17.2k
                            "    PIXMIN=%u\n"
359
17.2k
                            "    PIXMAX=%u\n"
360
17.2k
                            "    IMAGENAME=\"%.79s\"\n"
361
17.2k
                            "    COLORMAP=%u",
362
17.2k
                            (unsigned int) iris_info.magic,
363
17.2k
                            (unsigned int) iris_info.storage,
364
17.2k
                            (iris_info.storage == 1 ? "RLE" : "VERBATIM"),
365
17.2k
                            (unsigned int) iris_info.bytes_per_pixel,
366
17.2k
                            (unsigned int) iris_info.dimension,
367
17.2k
                            (unsigned int) iris_info.xsize,
368
17.2k
                            (unsigned int) iris_info.ysize,
369
17.2k
                            (unsigned int) iris_info.zsize,
370
17.2k
                            iris_info.pix_min,
371
17.2k
                            iris_info.pix_max,
372
17.2k
                            iris_info.image_name,
373
17.2k
                            iris_info.color_map);
374
17.2k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
375
17.2k
                            "File size %" MAGICK_OFF_F "d bytes", file_size);
376
377
      /*
378
        Validate image header and set image attributes.
379
      */
380
17.2k
      if (iris_info.magic != 0x01DA)
381
17.2k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
382
383
17.2k
      if (iris_info.storage == 0U)
384
4.28k
        {
385
          /* Uncompressed */
386
4.28k
          image->compression=NoCompression;
387
4.28k
        }
388
12.9k
      else if (iris_info.storage == 1U)
389
12.3k
        {
390
          /* RLE compressed */
391
12.3k
          image->compression=RLECompression;
392
12.3k
        }
393
598
      else
394
598
        {
395
          /* Error */
396
598
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
397
0
        }
398
399
16.6k
      if (iris_info.color_map != 0U)
400
3.09k
        {
401
          /* We only support images with normal (no) colormap */
402
3.09k
          ThrowReaderException(CorruptImageError,ImageTypeNotSupported,image);
403
0
        }
404
405
13.5k
      if (iris_info.bytes_per_pixel == 1U)
406
10.3k
        {
407
          /* 8 bits per sample */
408
10.3k
          image->depth=8;
409
10.3k
        }
410
3.17k
      else if (iris_info.bytes_per_pixel == 2U)
411
1.65k
        {
412
          /* 16 bits per sample */
413
1.65k
          image->depth=Min(16,QuantumDepth);
414
1.65k
        }
415
1.51k
      else
416
1.51k
        {
417
          /* Error */
418
1.51k
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
419
0
        }
420
421
      /* We only support zsize up to 4. Code further on assumes that. */
422
12.0k
      if (iris_info.zsize > 4U)
423
10.7k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
424
425
10.7k
      if (iris_info.dimension == 1U)
426
8.11k
        {
427
          /*
428
            Image contains one channel and one scanline, with scanline
429
            length specified by xsize.
430
          */
431
8.11k
          image->columns=iris_info.xsize;
432
8.11k
          image->rows=1;
433
8.11k
          if (iris_info.ysize != image->rows)
434
8.06k
            {
435
8.06k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
436
8.06k
                                    "Overriding unexpected value of YSIZE (%u) "
437
8.06k
                                    "for 1 dimensional image", iris_info.ysize);
438
8.06k
              iris_info.ysize=image->rows;
439
8.06k
            }
440
8.11k
          image->is_grayscale=MagickTrue;
441
8.11k
          if (iris_info.bytes_per_pixel == 1U)
442
6.72k
            {
443
              /* Use a grayscale colormap */
444
6.72k
              image->storage_class=PseudoClass;
445
6.72k
              image->colors=256;
446
6.72k
            }
447
8.11k
        }
448
2.66k
      else if (iris_info.dimension == 2U)
449
603
        {
450
          /*
451
            One channel with a number of scan lines.  Width and height
452
            of image are given by the values of xsize and ysize.
453
          */
454
603
          image->columns=iris_info.xsize;
455
603
          image->rows=iris_info.ysize;
456
603
          image->is_grayscale=MagickTrue;
457
603
          if (iris_info.bytes_per_pixel == 1)
458
387
            {
459
              /* Use a grayscale colormap */
460
387
              image->storage_class=PseudoClass;
461
387
              image->colors=256;
462
387
            }
463
603
        }
464
2.06k
      else if (iris_info.dimension == 3U)
465
1.27k
        {
466
          /*
467
            A number of channels.  Width and height of image are given
468
            by the values of xsize and ysize. The number of channels is
469
            specified by zsize.
470
471
            B/W images have a zsize of 1.  RGB images have a zsize of 3.
472
            RGB images with an alpha channel have a zsize of 4. Images
473
            may have more than four channels but the meaning of
474
            additional channels is implementation dependent.
475
          */
476
477
1.27k
          image->columns=iris_info.xsize;
478
1.27k
          image->rows=iris_info.ysize;
479
480
1.27k
          if (iris_info.zsize == 1U)
481
87
            {
482
              /* B/W image */
483
87
              image->matte = MagickFalse;
484
87
              image->is_grayscale=MagickTrue;
485
87
              if (iris_info.bytes_per_pixel == 1U)
486
69
                {
487
                  /* Use a grayscale colormap */
488
69
                  image->storage_class=PseudoClass;
489
69
                  image->colors=256U;
490
69
                }
491
87
            }
492
1.18k
          else if (iris_info.zsize == 3U)
493
146
            {
494
              /* RGB */
495
146
              image->matte=MagickFalse;
496
146
            }
497
1.03k
          else if (iris_info.zsize == 4U)
498
77
            {
499
              /* RGBA  */
500
77
              image->matte=MagickTrue;
501
77
            }
502
960
          else
503
960
            {
504
              /* Error */
505
960
              ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
506
0
            }
507
1.27k
        }
508
791
      else
509
791
        {
510
          /* Error */
511
791
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
512
0
        }
513
514
9.03k
      if (iris_info.image_name[0])
515
4.81k
        (void) SetImageAttribute(image,"comment",iris_info.image_name);
516
517
9.03k
      if (image_info->ping && (image_info->subrange != 0))
518
0
        if (image->scene >= (image_info->subimage+image_info->subrange-1))
519
0
          break;
520
521
9.03k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
522
9.03k
                            "Image columns=%lu rows=%lu", image->columns, image->rows);
523
524
9.03k
      if (CheckImagePixelLimits(image, exception) != MagickPass)
525
8.51k
        ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
526
527
      /*
528
        Allocate SGI pixels.
529
      */
530
8.51k
      bytes_per_pixel=iris_info.bytes_per_pixel;
531
8.51k
      if (iris_info.storage != 0x01)
532
1.61k
        {
533
1.61k
          double
534
1.61k
              uncompressed_size;
535
536
1.61k
          size_t
537
1.61k
            iris_pixels_size;
538
539
          /*
540
            Check that filesize is reasonable given header
541
          */
542
1.61k
          uncompressed_size=((double) (iris_info.dimension == 3U ? iris_info.zsize : 1U)*
543
1.61k
                             image->columns*image->rows*iris_info.bytes_per_pixel);
544
1.61k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
545
1.61k
                                "Uncompressed size: %.0f", uncompressed_size);
546
547
          /* Not compressed */
548
1.61k
          if (uncompressed_size > file_size)
549
3
            ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,
550
1.61k
                                 image);
551
552
          /*
553
            Read standard image format.
554
          */
555
1.60k
          scanline=MagickAllocateResourceLimitedArray(unsigned char *,
556
1.60k
                                       bytes_per_pixel,iris_info.xsize);
557
1.60k
          if (scanline == (unsigned char *) NULL)
558
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
559
1.60k
                                    image);
560
561
1.60k
          iris_pixels_size = MagickArraySize(MagickArraySize(4U,bytes_per_pixel),
562
1.60k
                                             MagickArraySize(iris_info.xsize,iris_info.ysize));
563
1.60k
          iris_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,iris_pixels_size);
564
1.60k
          if (iris_pixels == (unsigned char *) NULL)
565
1.60k
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,image);
566
1.60k
          (void) memset(iris_pixels,0,iris_pixels_size);
567
568
1.60k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
569
1.60k
                                "   Reading SGI scanlines");
570
3.74k
          for (z=0U; z < iris_info.zsize; z++)
571
2.26k
            {
572
2.26k
              p=iris_pixels+bytes_per_pixel*z;
573
331k
              for (y=0U; y < iris_info.ysize; y++)
574
329k
                {
575
329k
                  if (ReadBlob(image,bytes_per_pixel*iris_info.xsize,
576
329k
                               (char *) scanline) != bytes_per_pixel*iris_info.xsize)
577
131
                    {
578
131
                      ThrowSGIReaderException(CorruptImageError,
579
0
                                              UnexpectedEndOfFile, image);
580
0
                      break;
581
131
                    }
582
329k
                  if (bytes_per_pixel == 2U)
583
629k
                    for (x=0; x < iris_info.xsize; x++)
584
618k
                      {
585
618k
                        *p=scanline[2U*x];
586
618k
                        *(p+1U)=scanline[2U*x+1U];
587
618k
                        p+=8U;
588
618k
                      }
589
317k
                  else
590
37.1M
                    for (x=0; x < iris_info.xsize; x++)
591
36.8M
                      {
592
36.8M
                        *p=scanline[x];
593
36.8M
                        p+=4U;
594
36.8M
                      }
595
329k
                }
596
2.13k
              if (EOFBlob(image))
597
0
                break;
598
2.13k
            }
599
1.47k
          MagickFreeResourceLimitedMemory(unsigned char *,scanline);
600
1.47k
        }
601
6.90k
      else
602
6.90k
        {
603
6.90k
          unsigned int
604
6.90k
            data_order;
605
606
6.90k
          magick_off_t
607
6.90k
            offset;
608
609
6.90k
          size_t
610
6.90k
            iris_pixels_size,
611
6.90k
            max_packets_alloc_size,
612
6.90k
            rle_alloc_size,
613
6.90k
            rle_dimensions;
614
615
6.90k
          magick_off_t
616
6.90k
            here;
617
618
6.90k
          rle_dimensions=MagickArraySize(iris_info.ysize, iris_info.zsize);
619
6.90k
          rle_alloc_size=MagickArraySize(rle_dimensions, sizeof(magick_uint32_t));
620
621
6.90k
          if ((rle_dimensions == 0U) || (rle_alloc_size == 0U))
622
328
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
623
6.90k
                                    image);
624
625
          /*
626
            Read runlength-encoded image format.
627
          */
628
6.57k
          if (TellBlob(image)+rle_alloc_size > (size_t) file_size)
629
6.54k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
630
6.54k
          offsets=MagickAllocateResourceLimitedMemory(magick_uint32_t *,rle_alloc_size);
631
6.54k
          if (offsets == (magick_uint32_t *) NULL)
632
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
633
6.54k
                                    image);
634
6.54k
          if (ReadBlob(image,rle_alloc_size,offsets) != rle_alloc_size)
635
6.54k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
636
637
6.54k
          if (TellBlob(image)+rle_alloc_size > (size_t) file_size)
638
6.51k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
639
6.51k
          runlength=MagickAllocateResourceLimitedMemory(magick_uint32_t *,rle_alloc_size);
640
6.51k
          if (runlength == (magick_uint32_t *) NULL)
641
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
642
6.51k
                                    image);
643
6.51k
          if (ReadBlob(image,rle_alloc_size,runlength) != rle_alloc_size)
644
6.51k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
645
646
6.51k
#if !defined(WORDS_BIGENDIAN)
647
6.51k
          MagickSwabArrayOfUInt32(offsets,rle_dimensions);
648
6.51k
          MagickSwabArrayOfUInt32(runlength,rle_dimensions);
649
6.51k
#endif
650
6.51k
          here=TellBlob(image);
651
652
20.6k
          for (i=0U; i < rle_dimensions; i++)
653
16.1k
            if ((offsets[i] != ((magick_off_t) offsets[i])) ||
654
16.1k
                (offsets[i] < here) ||
655
14.9k
                (offsets[i] > file_size))
656
4.48k
              ThrowSGIReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
657
17.5k
          for (i=0U; i < rle_dimensions; i++)
658
13.6k
            {
659
13.6k
              if (runlength[i] > ((size_t) 4U*iris_info.xsize+10U))
660
13.1k
                ThrowSGIReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
661
13.1k
            }
662
663
3.95k
          max_packets_alloc_size=MagickArraySize((size_t) iris_info.xsize+10U,4U);
664
3.95k
          max_packets=MagickAllocateResourceLimitedMemory(unsigned char *,max_packets_alloc_size);
665
3.95k
          if (max_packets == (unsigned char *) NULL)
666
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
667
3.95k
                                    image);
668
669
3.95k
          iris_pixels_size=MagickArraySize(MagickArraySize(4U,bytes_per_pixel),
670
3.95k
                                           MagickArraySize(iris_info.xsize,iris_info.ysize));
671
3.95k
          iris_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,iris_pixels_size);
672
3.95k
          if (iris_pixels == (unsigned char *) NULL)
673
3.95k
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,image);
674
675
3.95k
          (void) memset(iris_pixels,0,iris_pixels_size);
676
677
          /*
678
            Check data order.
679
          */
680
3.95k
          offset=0;
681
3.95k
          data_order=0U;
682
10.5k
          for (y=0; ((y < iris_info.ysize) && !data_order); y++)
683
15.3k
            for (z=0U; ((z < iris_info.zsize) && !data_order); z++)
684
8.77k
              {
685
8.77k
                const size_t run_index = (size_t) y+z*iris_info.ysize;
686
8.77k
                if (run_index >= rle_alloc_size)
687
0
                  ThrowSGIReaderException(CorruptImageError,
688
8.77k
                                          UnableToRunlengthDecodeImage,image);
689
8.77k
                if (offsets[run_index] < offset)
690
162
                  data_order=1;
691
8.77k
                offset=(magick_off_t) offsets[run_index];
692
8.77k
              }
693
3.95k
          offset=TellBlob(image);
694
3.95k
          if (data_order == 1)
695
162
            {
696
268
              for (z=0U; z < iris_info.zsize; z++)
697
223
                {
698
223
                  p=iris_pixels;
699
3.24k
                  for (y=0U; y < iris_info.ysize; y++)
700
3.13k
                    {
701
3.13k
                      const size_t run_index = (size_t) y+z*iris_info.ysize;
702
3.13k
                      size_t length;
703
3.13k
                      if (run_index >= rle_alloc_size)
704
0
                        ThrowSGIReaderException(CorruptImageError,
705
3.13k
                                                UnableToRunlengthDecodeImage,image);
706
3.13k
                      if (offset != (magick_off_t) offsets[run_index])
707
2.69k
                        {
708
2.69k
                          offset=(magick_off_t) offsets[run_index];
709
2.69k
                          if (SeekBlob(image,offset,SEEK_SET) != offset)
710
0
                            ThrowSGIReaderException(CorruptImageError,
711
2.69k
                                                    UnableToRunlengthDecodeImage, image);
712
2.69k
                        }
713
3.13k
                      length=runlength[run_index];
714
3.13k
                      if (length > max_packets_alloc_size)
715
0
                        ThrowSGIReaderException(CorruptImageError,
716
3.13k
                                                UnableToRunlengthDecodeImage,image);
717
3.13k
                      if (ReadBlob(image,length,(char *) max_packets) != length)
718
85
                        ThrowSGIReaderException(CorruptImageError,
719
3.13k
                                                UnexpectedEndOfFile, image);
720
3.05k
                      offset+=(magick_off_t) length;
721
3.05k
                      if (SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z,
722
3.05k
                                    length/bytes_per_pixel,
723
3.05k
                                    iris_info.xsize) == -1)
724
32
                        ThrowSGIReaderException(CorruptImageError,
725
3.05k
                                                UnableToRunlengthDecodeImage,image);
726
3.01k
                      p+=((size_t) iris_info.xsize*4U*bytes_per_pixel);
727
3.01k
                    }
728
223
                }
729
162
            }
730
3.79k
          else
731
3.79k
            {
732
3.79k
              p=iris_pixels;
733
5.98k
              for (y=0; y < iris_info.ysize; y++)
734
4.61k
                {
735
7.83k
                  for (z=0; z < iris_info.zsize; z++)
736
5.64k
                    {
737
5.64k
                      const size_t run_index = (size_t) y+z*iris_info.ysize;
738
5.64k
                      size_t length;
739
5.64k
                      if (run_index >= rle_alloc_size)
740
0
                        ThrowSGIReaderException(CorruptImageError,
741
5.64k
                                                UnableToRunlengthDecodeImage,image);
742
5.64k
                      if (offset != (magick_off_t) offsets[run_index])
743
4.21k
                        {
744
4.21k
                          offset=(magick_off_t) offsets[run_index];
745
4.21k
                          if (SeekBlob(image,offset,SEEK_SET) != offset)
746
0
                            ThrowSGIReaderException(CorruptImageError,
747
4.21k
                                                    UnableToRunlengthDecodeImage, image);
748
4.21k
                        }
749
5.64k
                      length=runlength[run_index];
750
5.64k
                      if (length > max_packets_alloc_size)
751
0
                        ThrowSGIReaderException(CorruptImageError,
752
5.64k
                                                UnableToRunlengthDecodeImage,image);
753
5.64k
                      if (ReadBlob(image,length, (char *) max_packets) != length)
754
64
                        ThrowSGIReaderException(CorruptImageError,
755
5.64k
                                                UnexpectedEndOfFile, image);
756
5.57k
                      offset+=length;
757
5.57k
                      if (SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z,
758
5.57k
                                    length/bytes_per_pixel,
759
5.57k
                                    iris_info.xsize) == -1)
760
2.36k
                        ThrowSGIReaderException(CorruptImageError,
761
5.57k
                                                UnableToRunlengthDecodeImage,image);
762
3.21k
                    }
763
2.19k
                  p+=((size_t) iris_info.xsize*4U*bytes_per_pixel);
764
2.19k
                  if (EOFBlob(image))
765
0
                    break;
766
2.19k
                }
767
3.79k
            }
768
1.41k
          MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength);
769
1.41k
          MagickFreeResourceLimitedMemory(unsigned char *,max_packets);
770
1.41k
          MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);
771
1.41k
        }
772
773
      /*
774
        Convert SGI raster image to pixel packets.
775
      */
776
2.89k
      if (image->storage_class == DirectClass)
777
670
        {
778
          /*
779
            Convert SGI image to DirectClass pixel packets.
780
          */
781
670
          if (bytes_per_pixel == 2U)
782
568
            {
783
26.9k
              for (y=0; y < image->rows; y++)
784
26.6k
                {
785
26.6k
                  p=iris_pixels+((size_t)image->rows-y-1)*8*image->columns;
786
26.6k
                  q=SetImagePixels(image,0,y,image->columns,1);
787
26.6k
                  if (q == (PixelPacket *) NULL)
788
179
                    break;
789
893k
                  for (x=0U; x < image->columns; x++)
790
867k
                    {
791
867k
                      q->red=ScaleShortToQuantum((*(p+0) << 8U) | (*(p+1)));
792
867k
                      q->green=ScaleShortToQuantum((*(p+2) << 8U) | (*(p+3)));
793
867k
                      q->blue=ScaleShortToQuantum((*(p+4) << 8U) | (*(p+5)));
794
867k
                      if (image->matte)
795
2.24k
                        q->opacity=(Quantum)
796
2.24k
                          (MaxRGB-ScaleShortToQuantum((*(p+6) << 8) | (*(p+7))));
797
865k
                      else
798
865k
                        q->opacity=OpaqueOpacity;
799
867k
                      p+=8U;
800
867k
                      q++;
801
867k
                    }
802
26.4k
                  if (!SyncImagePixels(image))
803
0
                    break;
804
26.4k
                  if (QuantumTick(y,image->rows))
805
6.42k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
806
6.42k
                                                LoadImageText,image->filename,
807
6.42k
                                                image->columns,image->rows))
808
0
                      break;
809
26.4k
                }
810
568
            }
811
102
          else
812
69.8k
            for (y=0; y < image->rows; y++)
813
69.7k
              {
814
69.7k
                p=iris_pixels+((size_t) image->rows-y-1)*4*image->columns;
815
69.7k
                q=SetImagePixels(image,0,y,image->columns,1);
816
69.7k
                if (q == (PixelPacket *) NULL)
817
0
                  break;
818
702k
                for (x=0; x < image->columns; x++)
819
632k
                  {
820
632k
                    q->red=ScaleCharToQuantum(*p);
821
632k
                    q->green=ScaleCharToQuantum(*(p+1));
822
632k
                    q->blue=ScaleCharToQuantum(*(p+2));
823
632k
                    if (image->matte)
824
520k
                      q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*(p+3)));
825
111k
                    else
826
111k
                      q->opacity=OpaqueOpacity;
827
632k
                    p+=4;
828
632k
                    q++;
829
632k
                  }
830
69.7k
                if (!SyncImagePixels(image))
831
0
                  break;
832
69.7k
                if (QuantumTick(y,image->rows))
833
7.27k
                  if (!MagickMonitorFormatted(y,image->rows,exception,
834
7.27k
                                              LoadImageText,image->filename,
835
7.27k
                                              image->columns,image->rows))
836
0
                    break;
837
69.7k
              }
838
670
        }
839
2.22k
      else
840
2.22k
        {
841
          /*
842
            Create grayscale map.
843
          */
844
2.22k
          if (!AllocateImageColormap(image,image->colors))
845
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
846
2.22k
                                    image);
847
          /*
848
            Convert SGI image to PseudoClass pixel packets.
849
          */
850
2.22k
          if (bytes_per_pixel == 2)
851
0
            {
852
0
              for (y=0; y < image->rows; y++)
853
0
                {
854
0
                  p=iris_pixels+((size_t)image->rows-y-1)*8*image->columns;
855
0
                  q=SetImagePixels(image,0,y,image->columns,1);
856
0
                  if (q == (PixelPacket *) NULL)
857
0
                    break;
858
0
                  indexes=AccessMutableIndexes(image);
859
0
                  for (x=0; x < image->columns; x++)
860
0
                    {
861
0
                      indexes[x]=(*p << 8);
862
0
                      indexes[x]|=(*(p+1));
863
0
                      p+=8;
864
0
                      q++;
865
0
                    }
866
0
                  if (!SyncImagePixels(image))
867
0
                    break;
868
0
                  if (QuantumTick(y,image->rows))
869
0
                    if (!MagickMonitorFormatted(y,image->rows,exception,
870
0
                                                LoadImageText,image->filename,
871
0
                                                image->columns,image->rows))
872
0
                      break;
873
0
                }
874
0
            }
875
2.22k
          else
876
2.22k
            {
877
42.7k
              for (y=0; y < image->rows; y++)
878
41.2k
                {
879
41.2k
                  p=iris_pixels+((size_t)image->rows-y-1)*4U*image->columns;
880
41.2k
                  q=SetImagePixels(image,0,y,image->columns,1);
881
41.2k
                  if (q == (PixelPacket *) NULL)
882
777
                    break;
883
40.5k
                  indexes=AccessMutableIndexes(image);
884
10.3M
                  for (x=0; x < image->columns; x++)
885
10.3M
                    {
886
10.3M
                      indexes[x]=(*p);
887
10.3M
                      p+=4;
888
10.3M
                      q++;
889
10.3M
                    }
890
40.5k
                  if (!SyncImagePixels(image))
891
0
                    break;
892
40.5k
                  if (QuantumTick(y,image->rows))
893
10.8k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
894
10.8k
                                                LoadImageText,image->filename,
895
10.8k
                                                image->columns,image->rows))
896
0
                      break;
897
40.5k
                }
898
2.22k
            }
899
2.22k
          if (y < image->rows)
900
777
            {
901
777
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
902
777
                                    "Only transferred %lu rows out of %lu",
903
777
                                    y, image->rows);
904
777
              MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
905
              /*
906
                Not sure what a proper error report is here
907
               */
908
777
              ThrowSGIReaderException(CorruptImageError,UnableToReadImageData,image);
909
0
            }
910
1.44k
          (void) SyncImage(image);
911
1.44k
        }
912
2.11k
      MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
913
2.11k
      if (EOFBlob(image))
914
0
        {
915
0
          ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,
916
0
                                  image);
917
0
          break;
918
0
        }
919
2.11k
    } while (0);
920
2.11k
  CloseBlob(image);
921
2.11k
  StopTimer(&image->timer);
922
2.11k
  return(image);
923
127k
}
924

925
/*
926
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
927
%                                                                             %
928
%                                                                             %
929
%                                                                             %
930
%   R e g i s t e r S G I I m a g e                                           %
931
%                                                                             %
932
%                                                                             %
933
%                                                                             %
934
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935
%
936
%  Method RegisterSGIImage adds attributes for the SGI image format to
937
%  the list of supported formats.  The attributes include the image format
938
%  tag, a method to read and/or write the format, whether the format
939
%  supports the saving of more than one frame to the same file or blob,
940
%  whether the format supports native in-memory I/O, and a brief
941
%  description of the format.
942
%
943
%  The format of the RegisterSGIImage method is:
944
%
945
%      RegisterSGIImage(void)
946
%
947
*/
948
ModuleExport void RegisterSGIImage(void)
949
5
{
950
5
  MagickInfo
951
5
    *entry;
952
953
5
  entry=SetMagickInfo("SGI");
954
5
  entry->decoder=(DecoderHandler) ReadSGIImage;
955
5
  entry->encoder=(EncoderHandler) WriteSGIImage;
956
5
  entry->magick=(MagickHandler) IsSGI;
957
5
  entry->description="Irix RGB image";
958
5
  entry->module="SGI";
959
5
  entry->adjoin=MagickFalse;
960
5
  entry->seekable_stream=True;
961
5
  (void) RegisterMagickInfo(entry);
962
5
}
963

964
/*
965
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966
%                                                                             %
967
%                                                                             %
968
%                                                                             %
969
%   U n r e g i s t e r S G I I m a g e                                       %
970
%                                                                             %
971
%                                                                             %
972
%                                                                             %
973
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
974
%
975
%  Method UnregisterSGIImage removes format registrations made by the
976
%  SGI module from the list of supported formats.
977
%
978
%  The format of the UnregisterSGIImage method is:
979
%
980
%      UnregisterSGIImage(void)
981
%
982
*/
983
ModuleExport void UnregisterSGIImage(void)
984
0
{
985
0
  (void) UnregisterMagickInfo("SGI");
986
0
}
987

988
/*
989
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990
%                                                                             %
991
%                                                                             %
992
%                                                                             %
993
%   W r i t e S G I I m a g e                                                 %
994
%                                                                             %
995
%                                                                             %
996
%                                                                             %
997
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
998
%
999
%  Method WriteSGIImage writes an image in SGI RGB encoded image format.
1000
%
1001
%  The format of the WriteSGIImage method is:
1002
%
1003
%      unsigned int WriteSGIImage(const ImageInfo *image_info,Image *image)
1004
%
1005
%  A description of each parameter follows.
1006
%
1007
%    o status: Method WriteSGIImage return True if the image is written.
1008
%      False is returned is there is a memory shortage or if the image file
1009
%      fails to write.
1010
%
1011
%    o image_info: Specifies a pointer to a ImageInfo structure.
1012
%
1013
%    o image:  A pointer to an Image structure.
1014
%
1015
%
1016
*/
1017
1018
static size_t SGIEncode(unsigned char *pixels,size_t count,
1019
                        unsigned char *packets)
1020
383k
{
1021
383k
  short
1022
383k
    runlength;
1023
1024
383k
  register unsigned char
1025
383k
    *p,
1026
383k
    *q;
1027
1028
383k
  unsigned char
1029
383k
    *limit,
1030
383k
    *mark;
1031
1032
383k
  p=pixels;
1033
383k
  limit=p+count*4;
1034
383k
  q=packets;
1035
1.07M
  while (p < limit)
1036
687k
    {
1037
687k
      mark=p;
1038
687k
      p+=8;
1039
7.13M
      while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
1040
6.44M
        p+=4;
1041
687k
      p-=8;
1042
687k
      count=((p-mark) >> 2);
1043
1.01M
      while (count)
1044
331k
        {
1045
331k
          runlength=(short) (count > 126 ? 126 : count);
1046
331k
          count-=runlength;
1047
331k
          *q++=0x80 | runlength;
1048
6.77M
          for ( ; runlength > 0; runlength--)
1049
6.44M
            {
1050
6.44M
              *q++=(*mark);
1051
6.44M
              mark+=4;
1052
6.44M
            }
1053
331k
        }
1054
687k
      mark=p;
1055
687k
      p+=4;
1056
8.92M
      while ((p < limit) && (*p == *mark))
1057
8.23M
        p+=4;
1058
687k
      count=((p-mark) >> 2);
1059
1.43M
      while (count)
1060
744k
        {
1061
744k
          runlength=(short) (count > 126 ? 126 : count);
1062
744k
          count-=runlength;
1063
744k
          *q++=(unsigned char) runlength;
1064
744k
          *q++=(*mark);
1065
744k
        }
1066
687k
    }
1067
383k
  *q++=0;
1068
383k
  return(q-packets);
1069
383k
}
1070
1071
0
#define ThrowSGIWriterException(code_,reason_,image_) \
1072
0
{ \
1073
0
  MagickFreeResourceLimitedMemory(unsigned char *,scanline) \
1074
0
  MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets); \
1075
0
  MagickFreeResourceLimitedMemory(unsigned char *,packets); \
1076
0
  MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength); \
1077
0
  MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels); \
1078
0
  ThrowWriterException(code_,reason_,image_); \
1079
0
}
1080
1081
static unsigned int WriteSGIImage(const ImageInfo *image_info,Image *image)
1082
439
{
1083
439
  long
1084
439
    y,
1085
439
    z;
1086
1087
439
  SGIInfo
1088
439
    iris_info;
1089
1090
439
  register const PixelPacket
1091
439
    *p;
1092
1093
439
  register long
1094
439
    i,
1095
439
    x;
1096
1097
439
  register unsigned char
1098
439
    *q;
1099
1100
439
  magick_uint32_t
1101
439
    *offsets = (magick_uint32_t *) NULL,
1102
439
    *runlength = (magick_uint32_t *) NULL;
1103
1104
439
  unsigned char
1105
439
    *iris_pixels = (unsigned char *) NULL,
1106
439
    *packets = (unsigned char *) NULL,
1107
439
    *scanline = (unsigned char *) NULL;
1108
1109
439
  unsigned int
1110
439
    status;
1111
1112
439
  unsigned long
1113
439
    number_pixels;
1114
1115
  /*
1116
    Open output image file.
1117
  */
1118
439
  assert(image_info != (const ImageInfo *) NULL);
1119
439
  assert(image_info->signature == MagickSignature);
1120
439
  assert(image != (Image *) NULL);
1121
439
  assert(image->signature == MagickSignature);
1122
439
  if ((image->columns > 65535L) || (image->rows > 65535L))
1123
439
    ThrowWriterException(ImageError,WidthOrHeightExceedsLimit,image);
1124
439
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1125
439
  if (status == MagickFail)
1126
439
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
1127
439
  do
1128
439
    {
1129
439
      ImageCharacteristics
1130
439
        characteristics;
1131
1132
      /*
1133
        Ensure that image is in an RGB space.
1134
      */
1135
439
      if (TransformColorspace(image,RGBColorspace) == MagickFail)
1136
439
        ThrowWriterException(CoderError,UnableToTransformColorspace,image);
1137
      /*
1138
        Analyze image to be written.
1139
      */
1140
439
      if (GetImageCharacteristics(image,&characteristics,
1141
439
                                  (OptimizeType == image_info->type),
1142
439
                                  &image->exception) == MagickFail)
1143
439
        ThrowWriterException(CoderError,UnableToGetImageCharacteristics,image);
1144
      /*
1145
        Initialize SGI raster file header.
1146
      */
1147
439
      iris_info.magic=0x01DA;
1148
439
      if (image_info->compression == NoCompression)
1149
0
        iris_info.storage=0x00;
1150
439
      else
1151
439
        iris_info.storage=0x01;
1152
439
      iris_info.bytes_per_pixel=1;  /* one byte per pixel */
1153
439
      iris_info.dimension=3;
1154
439
      iris_info.xsize=(unsigned short) image->columns;
1155
439
      iris_info.ysize=(unsigned short) image->rows;
1156
439
      if (image->matte != MagickFalse)
1157
49
        iris_info.zsize=4;
1158
390
      else
1159
390
        {
1160
390
          if ((image_info->type != TrueColorType) &&
1161
390
              (characteristics.grayscale))
1162
218
            {
1163
218
              iris_info.dimension=2;
1164
218
              iris_info.zsize=1;
1165
218
            }
1166
172
          else
1167
172
            iris_info.zsize=3;
1168
390
        }
1169
439
      iris_info.pix_min=0;
1170
439
      iris_info.pix_max=ScaleQuantumToChar(MaxRGB);
1171
1172
439
      (void) memset(iris_info.dummy1,0,sizeof(iris_info.dummy1));
1173
439
      {
1174
439
        const ImageAttribute
1175
439
          *attribute;
1176
1177
439
        (void) memset(iris_info.image_name,0,sizeof(iris_info.image_name));
1178
439
        if ((attribute=GetImageAttribute(image,"comment")))
1179
246
          (void) strlcpy(iris_info.image_name,attribute->value,sizeof(iris_info.image_name));
1180
439
      }
1181
439
      iris_info.color_map=0;
1182
439
      (void) memset(iris_info.dummy2,0,sizeof(iris_info.dummy2));
1183
1184
      /*
1185
        Write SGI header.
1186
      */
1187
439
      (void) WriteBlobMSBShort(image,iris_info.magic);
1188
439
      (void) WriteBlobByte(image,iris_info.storage);
1189
439
      (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
1190
439
      (void) WriteBlobMSBShort(image,iris_info.dimension);
1191
439
      (void) WriteBlobMSBShort(image,iris_info.xsize);
1192
439
      (void) WriteBlobMSBShort(image,iris_info.ysize);
1193
439
      (void) WriteBlobMSBShort(image,iris_info.zsize);
1194
439
      (void) WriteBlobMSBLong(image,iris_info.pix_min);
1195
439
      (void) WriteBlobMSBLong(image,iris_info.pix_max);
1196
439
      (void) WriteBlob(image,sizeof(iris_info.dummy1),
1197
439
                       (char *) iris_info.dummy1);
1198
439
      (void) WriteBlob(image,sizeof(iris_info.image_name),
1199
439
                       (char *) iris_info.image_name);
1200
439
      (void) WriteBlobMSBLong(image,iris_info.color_map);
1201
439
      (void) WriteBlob(image,sizeof(iris_info.dummy2),
1202
439
                       (char *) iris_info.dummy2);
1203
      /*
1204
        Allocate SGI pixels.
1205
      */
1206
439
      number_pixels=image->columns*image->rows;
1207
439
      iris_pixels=MagickAllocateResourceLimitedArray(unsigned char *,4,number_pixels);
1208
439
      if (iris_pixels == (unsigned char *) NULL)
1209
439
        ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,image);
1210
      /*
1211
        Convert image pixels to uncompressed SGI pixels.
1212
      */
1213
135k
      for (y=0; y < (long) image->rows; y++)
1214
135k
        {
1215
135k
          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1216
135k
          if (p == (const PixelPacket *) NULL)
1217
0
            break;
1218
135k
          q=iris_pixels+(((size_t)iris_info.ysize-1)-y)*((size_t)iris_info.xsize*4);
1219
11.9M
          for (x=0; x < (long) image->columns; x++)
1220
11.8M
            {
1221
11.8M
              *q++=ScaleQuantumToChar(p->red);
1222
11.8M
              *q++=ScaleQuantumToChar(p->green);
1223
11.8M
              *q++=ScaleQuantumToChar(p->blue);
1224
11.8M
              *q++=ScaleQuantumToChar(MaxRGB-p->opacity);
1225
11.8M
              p++;
1226
11.8M
            }
1227
135k
          if (QuantumTick(y,image->rows))
1228
23.0k
            if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1229
23.0k
                                        SaveImageText,image->filename,
1230
23.0k
                                        image->columns,image->rows))
1231
0
              break;
1232
135k
        }
1233
439
      if (image_info->compression == NoCompression)
1234
0
        {
1235
          /*
1236
            Write uncompressed SGI pixels.
1237
          */
1238
0
          scanline=MagickAllocateResourceLimitedMemory(unsigned char *,iris_info.xsize);
1239
0
          if (scanline == (unsigned char *) NULL)
1240
0
            ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,
1241
0
                                    image);
1242
0
          for (z=0; z < (int) iris_info.zsize; z++)
1243
0
            {
1244
0
              q=iris_pixels+z;
1245
0
              for (y=0; y < (long) iris_info.ysize; y++)
1246
0
                {
1247
0
                  for (x=0; x < (long) iris_info.xsize; x++)
1248
0
                    {
1249
0
                      scanline[x]=(*q);
1250
0
                      q+=4;
1251
0
                    }
1252
0
                  (void) WriteBlob(image,iris_info.xsize,(char *) scanline);
1253
0
                }
1254
0
            }
1255
0
          MagickFreeResourceLimitedMemory(unsigned char *,scanline);
1256
0
        }
1257
439
      else
1258
439
        {
1259
439
          magick_uint32_t
1260
439
            length,
1261
439
            number_packets,
1262
439
            offset;
1263
1264
          /*
1265
            Convert SGI uncompressed pixels.
1266
          */
1267
439
          offsets=MagickAllocateResourceLimitedArray(magick_uint32_t *,iris_info.ysize,
1268
439
                                      MagickArraySize(iris_info.zsize,
1269
439
                                                      sizeof(magick_uint32_t)));
1270
439
          packets=MagickAllocateResourceLimitedArray(unsigned char *,
1271
439
                                      4*(2*(size_t) iris_info.xsize+10),
1272
439
                                      image->rows);
1273
439
          runlength=MagickAllocateResourceLimitedArray(magick_uint32_t *,iris_info.ysize,
1274
439
                                        MagickArraySize(iris_info.zsize,
1275
439
                                                        sizeof(magick_uint32_t)));
1276
439
          if ((offsets == (magick_uint32_t *) NULL) ||
1277
439
              (packets == (unsigned char *) NULL) ||
1278
439
              (runlength == (magick_uint32_t *) NULL))
1279
0
            ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,
1280
439
                                    image);
1281
439
          offset=512+4*2*((size_t) iris_info.ysize*iris_info.zsize);
1282
439
          number_packets=0;
1283
439
          q=iris_pixels;
1284
135k
          for (y=0; y < (long) iris_info.ysize; y++)
1285
135k
            {
1286
518k
              for (z=0; z < (int) iris_info.zsize; z++)
1287
383k
                {
1288
383k
                  length=(magick_uint32_t)
1289
383k
                    SGIEncode(q+z,(int) iris_info.xsize,packets+number_packets);
1290
383k
                  number_packets+=length;
1291
383k
                  offsets[y+z*iris_info.ysize]=offset;
1292
383k
                  runlength[y+z*iris_info.ysize]=length;
1293
383k
                  offset+=length;
1294
383k
                }
1295
135k
              q+=((size_t)iris_info.xsize*4);
1296
135k
            }
1297
          /*
1298
            Write out line start and length tables and runlength-encoded pixels.
1299
          */
1300
383k
          for (i=0; i < (int) (iris_info.ysize*iris_info.zsize); i++)
1301
383k
            (void) WriteBlobMSBLong(image,offsets[i]);
1302
383k
          for (i=0; i < (int) (iris_info.ysize*iris_info.zsize); i++)
1303
383k
            (void) WriteBlobMSBLong(image,runlength[i]);
1304
439
          (void) WriteBlob(image,number_packets,(char *) packets);
1305
          /*
1306
            Free memory.
1307
          */
1308
439
          MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength);
1309
439
          MagickFreeResourceLimitedMemory(unsigned char *,packets);
1310
439
          MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);
1311
439
        }
1312
439
      MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
1313
439
    } while (0);
1314
439
  status &= CloseBlob(image);
1315
439
  return(status);
1316
439
}