Coverage Report

Created: 2026-07-25 07:06

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.35k
{
169
8.35k
  size_t
170
8.35k
    count;
171
172
8.35k
  register unsigned char
173
8.35k
    *p,
174
8.35k
    *q;
175
176
8.35k
  unsigned int
177
8.35k
    pixel;
178
179
8.35k
  p=max_packets;
180
8.35k
  q=pixels;
181
8.35k
  if (bytes_per_pixel == 2)
182
1.97k
    {
183
1.97k
      for ( ; ; )
184
4.70k
        {
185
4.70k
          if (npackets-- == 0)
186
64
            return -1;
187
4.64k
          pixel=(*p++) << 8U;
188
4.64k
          pixel|=(*p++);
189
4.64k
          count=(pixel & 0x7fU);
190
4.64k
          if (count == 0)
191
1.29k
            break;
192
3.35k
          if (count > npixels)
193
495
            return -1;
194
2.85k
          npixels -= count;
195
2.85k
          if (pixel & 0x80U)
196
16.4k
            for ( ; count != 0U; count--)
197
15.8k
              {
198
15.8k
                if (npackets-- == 0)
199
19
                  return -1;
200
15.7k
                *q=(*p++);
201
15.7k
                *(q+1)=(*p++);
202
15.7k
                q+=8U;
203
15.7k
              }
204
2.16k
          else
205
2.16k
            {
206
2.16k
              if (npackets-- == 0)
207
104
                return -1;
208
2.06k
              pixel=(*p++) << 8U;
209
2.06k
              pixel|=(*p++);
210
71.3k
              for ( ; count != 0; count--)
211
69.2k
                {
212
69.2k
                  *q=(unsigned char) (pixel >> 8U);
213
69.2k
                  *(q+1)=(unsigned char) pixel;
214
69.2k
                  q+=8U;
215
69.2k
                }
216
2.06k
            }
217
2.85k
        }
218
1.29k
      return 0;
219
1.97k
    }
220
6.38k
  for ( ; ; )
221
21.5k
    {
222
21.5k
      if (npackets-- == 0)
223
351
        return -1;
224
21.1k
      pixel=(*p++);
225
21.1k
      count= (pixel & 0x7fU);
226
21.1k
      if (count == 0)
227
4.60k
        break;
228
16.5k
      if (count > npixels)
229
1.16k
        return -1;
230
15.4k
      npixels -= count;
231
15.4k
      if (pixel & 0x80)
232
268k
        for ( ; count != 0; count--)
233
263k
          {
234
263k
            if (npackets-- == 0)
235
24
              return -1;
236
263k
            *q=(*p++);
237
263k
            q+=4;
238
263k
          }
239
10.3k
      else
240
10.3k
        {
241
10.3k
          if (npackets-- == 0)
242
241
            return -1;
243
10.1k
          pixel=(*p++);
244
314k
          for ( ; count != 0; count--)
245
304k
            {
246
304k
              *q=(unsigned char) pixel;
247
304k
              q+=4;
248
304k
            }
249
10.1k
        }
250
15.4k
    }
251
4.60k
  return 0;
252
6.38k
}
253
254
13.1k
#define ThrowSGIReaderException(code_,reason_,image_) \
255
13.1k
{ \
256
13.1k
  MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels) \
257
13.1k
  MagickFreeResourceLimitedMemory(unsigned char *,max_packets); \
258
13.1k
  MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);   \
259
13.1k
  MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength); \
260
13.1k
  MagickFreeResourceLimitedMemory(unsigned char *,scanline) \
261
13.1k
  ThrowReaderException(code_,reason_,image_); \
262
0
}
263
264
static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
265
135k
{
266
135k
  Image
267
135k
    *image;
268
269
135k
  size_t
270
135k
    z;
271
272
135k
  register IndexPacket
273
135k
    *indexes;
274
275
135k
  register size_t
276
135k
    i;
277
278
135k
  unsigned long
279
135k
        x,
280
135k
    y;
281
282
135k
  register PixelPacket
283
135k
    *q;
284
285
135k
  register unsigned char
286
135k
    *p;
287
288
135k
  SGIInfo
289
135k
    iris_info;
290
291
135k
  magick_uint32_t
292
135k
    *offsets = (magick_uint32_t *) NULL,
293
135k
    *runlength = (magick_uint32_t *) NULL;
294
295
135k
  unsigned char
296
135k
    *iris_pixels = (unsigned char *) NULL,
297
135k
    *max_packets = (unsigned char *) NULL,
298
135k
    *scanline = (unsigned char *) NULL;
299
300
135k
  unsigned int
301
135k
    status;
302
303
135k
  size_t
304
135k
    bytes_per_pixel;
305
306
135k
  magick_off_t
307
135k
    file_size;
308
309
  /*
310
    Open image file.
311
  */
312
135k
  assert(image_info != (const ImageInfo *) NULL);
313
135k
  assert(image_info->signature == MagickSignature);
314
135k
  assert(exception != (ExceptionInfo *) NULL);
315
135k
  assert(exception->signature == MagickSignature);
316
135k
  image=AllocateImage(image_info);
317
135k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
318
135k
  if (status == False)
319
135k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
320
135k
  file_size=GetBlobSize(image);
321
135k
  do
322
135k
    {
323
      /*
324
        Read SGI raster header.
325
      */
326
135k
      (void) memset(&iris_info, 0, sizeof(iris_info));
327
135k
      iris_info.magic=ReadBlobMSBShort(image);
328
135k
      iris_info.storage=ReadBlobByte(image);
329
135k
      iris_info.bytes_per_pixel=ReadBlobByte(image) &0xF;
330
135k
      iris_info.dimension=ReadBlobMSBShort(image) & 0xFFFF;
331
135k
      iris_info.xsize=ReadBlobMSBShort(image) & 0xFFFF;
332
135k
      iris_info.ysize=ReadBlobMSBShort(image) & 0xFFFF;
333
135k
      iris_info.zsize=ReadBlobMSBShort(image) & 0xFFFF;
334
135k
      iris_info.pix_min=ReadBlobMSBLong(image) & 0xFFFFFFFF;
335
135k
      iris_info.pix_max=ReadBlobMSBLong(image) & 0xFFFFFFFF;
336
337
135k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.dummy1),
338
135k
                      iris_info.dummy1);
339
135k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.image_name),
340
135k
                      iris_info.image_name);
341
135k
      iris_info.image_name[sizeof(iris_info.image_name)-1]=0;
342
135k
      iris_info.color_map=ReadBlobMSBLong(image);
343
135k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.dummy2),
344
135k
                      iris_info.dummy2);
345
346
135k
      if (EOFBlob(image))
347
117k
        ThrowReaderException(CorruptImageError,UnableToReadImageHeader,image);
348
349
17.9k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
350
17.9k
                            "IRIS Header:\n"
351
17.9k
                            "    MAGIC=%u\n"
352
17.9k
                            "    STORAGE=%u (%s)\n"
353
17.9k
                            "    BPC=%u\n"
354
17.9k
                            "    DIMENSION=%u\n"
355
17.9k
                            "    XSIZE=%u\n"
356
17.9k
                            "    YSIZE=%u\n"
357
17.9k
                            "    ZSIZE=%u\n"
358
17.9k
                            "    PIXMIN=%u\n"
359
17.9k
                            "    PIXMAX=%u\n"
360
17.9k
                            "    IMAGENAME=\"%.79s\"\n"
361
17.9k
                            "    COLORMAP=%u",
362
17.9k
                            (unsigned int) iris_info.magic,
363
17.9k
                            (unsigned int) iris_info.storage,
364
17.9k
                            (iris_info.storage == 1 ? "RLE" : "VERBATIM"),
365
17.9k
                            (unsigned int) iris_info.bytes_per_pixel,
366
17.9k
                            (unsigned int) iris_info.dimension,
367
17.9k
                            (unsigned int) iris_info.xsize,
368
17.9k
                            (unsigned int) iris_info.ysize,
369
17.9k
                            (unsigned int) iris_info.zsize,
370
17.9k
                            iris_info.pix_min,
371
17.9k
                            iris_info.pix_max,
372
17.9k
                            iris_info.image_name,
373
17.9k
                            iris_info.color_map);
374
17.9k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
375
17.9k
                            "File size %" MAGICK_OFF_F "d bytes", file_size);
376
377
      /*
378
        Validate image header and set image attributes.
379
      */
380
17.9k
      if (iris_info.magic != 0x01DA)
381
17.9k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
382
383
17.9k
      if (iris_info.storage == 0U)
384
4.46k
        {
385
          /* Uncompressed */
386
4.46k
          image->compression=NoCompression;
387
4.46k
        }
388
13.4k
      else if (iris_info.storage == 1U)
389
12.8k
        {
390
          /* RLE compressed */
391
12.8k
          image->compression=RLECompression;
392
12.8k
        }
393
619
      else
394
619
        {
395
          /* Error */
396
619
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
397
0
        }
398
399
17.3k
      if (iris_info.color_map != 0U)
400
3.25k
        {
401
          /* We only support images with normal (no) colormap */
402
3.25k
          ThrowReaderException(CorruptImageError,ImageTypeNotSupported,image);
403
0
        }
404
405
14.0k
      if (iris_info.bytes_per_pixel == 1U)
406
10.7k
        {
407
          /* 8 bits per sample */
408
10.7k
          image->depth=8;
409
10.7k
        }
410
3.28k
      else if (iris_info.bytes_per_pixel == 2U)
411
1.67k
        {
412
          /* 16 bits per sample */
413
1.67k
          image->depth=Min(16,QuantumDepth);
414
1.67k
        }
415
1.60k
      else
416
1.60k
        {
417
          /* Error */
418
1.60k
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
419
0
        }
420
421
      /* We only support zsize up to 4. Code further on assumes that. */
422
12.4k
      if (iris_info.zsize > 4U)
423
11.1k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
424
425
11.1k
      if (iris_info.dimension == 1U)
426
8.34k
        {
427
          /*
428
            Image contains one channel and one scanline, with scanline
429
            length specified by xsize.
430
          */
431
8.34k
          image->columns=iris_info.xsize;
432
8.34k
          image->rows=1;
433
8.34k
          if (iris_info.ysize != image->rows)
434
8.28k
            {
435
8.28k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
436
8.28k
                                    "Overriding unexpected value of YSIZE (%u) "
437
8.28k
                                    "for 1 dimensional image", iris_info.ysize);
438
8.28k
              iris_info.ysize=image->rows;
439
8.28k
            }
440
8.34k
          image->is_grayscale=MagickTrue;
441
8.34k
          if (iris_info.bytes_per_pixel == 1U)
442
6.94k
            {
443
              /* Use a grayscale colormap */
444
6.94k
              image->storage_class=PseudoClass;
445
6.94k
              image->colors=256;
446
6.94k
            }
447
8.34k
        }
448
2.78k
      else if (iris_info.dimension == 2U)
449
618
        {
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
618
          image->columns=iris_info.xsize;
455
618
          image->rows=iris_info.ysize;
456
618
          image->is_grayscale=MagickTrue;
457
618
          if (iris_info.bytes_per_pixel == 1)
458
397
            {
459
              /* Use a grayscale colormap */
460
397
              image->storage_class=PseudoClass;
461
397
              image->colors=256;
462
397
            }
463
618
        }
464
2.17k
      else if (iris_info.dimension == 3U)
465
1.31k
        {
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.31k
          image->columns=iris_info.xsize;
478
1.31k
          image->rows=iris_info.ysize;
479
480
1.31k
          if (iris_info.zsize == 1U)
481
86
            {
482
              /* B/W image */
483
86
              image->matte = MagickFalse;
484
86
              image->is_grayscale=MagickTrue;
485
86
              if (iris_info.bytes_per_pixel == 1U)
486
65
                {
487
                  /* Use a grayscale colormap */
488
65
                  image->storage_class=PseudoClass;
489
65
                  image->colors=256U;
490
65
                }
491
86
            }
492
1.23k
          else if (iris_info.zsize == 3U)
493
144
            {
494
              /* RGB */
495
144
              image->matte=MagickFalse;
496
144
            }
497
1.08k
          else if (iris_info.zsize == 4U)
498
86
            {
499
              /* RGBA  */
500
86
              image->matte=MagickTrue;
501
86
            }
502
1.00k
          else
503
1.00k
            {
504
              /* Error */
505
1.00k
              ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
506
0
            }
507
1.31k
        }
508
852
      else
509
852
        {
510
          /* Error */
511
852
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
512
0
        }
513
514
9.27k
      if (iris_info.image_name[0])
515
5.06k
        (void) SetImageAttribute(image,"comment",iris_info.image_name);
516
517
9.27k
      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.27k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
522
9.27k
                            "Image columns=%lu rows=%lu", image->columns, image->rows);
523
524
9.27k
      if (CheckImagePixelLimits(image, exception) != MagickPass)
525
8.72k
        ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
526
527
      /*
528
        Allocate SGI pixels.
529
      */
530
8.72k
      bytes_per_pixel=iris_info.bytes_per_pixel;
531
8.72k
      if (iris_info.storage != 0x01)
532
1.63k
        {
533
1.63k
          double
534
1.63k
              uncompressed_size;
535
536
1.63k
          size_t
537
1.63k
            iris_pixels_size;
538
539
          /*
540
            Check that filesize is reasonable given header
541
          */
542
1.63k
          uncompressed_size=((double) (iris_info.dimension == 3U ? iris_info.zsize : 1U)*
543
1.63k
                             image->columns*image->rows*iris_info.bytes_per_pixel);
544
1.63k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
545
1.63k
                                "Uncompressed size: %.0f", uncompressed_size);
546
547
          /* Not compressed */
548
1.63k
          if (uncompressed_size > file_size)
549
9
            ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,
550
1.63k
                                 image);
551
552
          /*
553
            Read standard image format.
554
          */
555
1.62k
          scanline=MagickAllocateResourceLimitedArray(unsigned char *,
556
1.62k
                                       bytes_per_pixel,iris_info.xsize);
557
1.62k
          if (scanline == (unsigned char *) NULL)
558
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
559
1.62k
                                    image);
560
561
1.62k
          iris_pixels_size = MagickArraySize(MagickArraySize(4U,bytes_per_pixel),
562
1.62k
                                             MagickArraySize(iris_info.xsize,iris_info.ysize));
563
1.62k
          iris_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,iris_pixels_size);
564
1.62k
          if (iris_pixels == (unsigned char *) NULL)
565
1.62k
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,image);
566
1.62k
          (void) memset(iris_pixels,0,iris_pixels_size);
567
568
1.62k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
569
1.62k
                                "   Reading SGI scanlines");
570
3.74k
          for (z=0U; z < iris_info.zsize; z++)
571
2.25k
            {
572
2.25k
              p=iris_pixels+bytes_per_pixel*z;
573
345k
              for (y=0U; y < iris_info.ysize; y++)
574
343k
                {
575
343k
                  if (ReadBlob(image,bytes_per_pixel*iris_info.xsize,
576
343k
                               (char *) scanline) != bytes_per_pixel*iris_info.xsize)
577
137
                    {
578
137
                      ThrowSGIReaderException(CorruptImageError,
579
0
                                              UnexpectedEndOfFile, image);
580
0
                      break;
581
137
                    }
582
343k
                  if (bytes_per_pixel == 2U)
583
651k
                    for (x=0; x < iris_info.xsize; x++)
584
634k
                      {
585
634k
                        *p=scanline[2U*x];
586
634k
                        *(p+1U)=scanline[2U*x+1U];
587
634k
                        p+=8U;
588
634k
                      }
589
326k
                  else
590
38.8M
                    for (x=0; x < iris_info.xsize; x++)
591
38.5M
                      {
592
38.5M
                        *p=scanline[x];
593
38.5M
                        p+=4U;
594
38.5M
                      }
595
343k
                }
596
2.11k
              if (EOFBlob(image))
597
0
                break;
598
2.11k
            }
599
1.49k
          MagickFreeResourceLimitedMemory(unsigned char *,scanline);
600
1.49k
        }
601
7.08k
      else
602
7.08k
        {
603
7.08k
          unsigned int
604
7.08k
            data_order;
605
606
7.08k
          magick_off_t
607
7.08k
            offset;
608
609
7.08k
          size_t
610
7.08k
            iris_pixels_size,
611
7.08k
            max_packets_alloc_size,
612
7.08k
            rle_alloc_size,
613
7.08k
            rle_dimensions;
614
615
7.08k
          magick_off_t
616
7.08k
            here;
617
618
7.08k
          rle_dimensions=MagickArraySize(iris_info.ysize, iris_info.zsize);
619
7.08k
          rle_alloc_size=MagickArraySize(rle_dimensions, sizeof(magick_uint32_t));
620
621
7.08k
          if ((rle_dimensions == 0U) || (rle_alloc_size == 0U))
622
329
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
623
7.08k
                                    image);
624
625
          /*
626
            Read runlength-encoded image format.
627
          */
628
6.75k
          if (TellBlob(image)+rle_alloc_size > (size_t) file_size)
629
6.72k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
630
6.72k
          offsets=MagickAllocateResourceLimitedMemory(magick_uint32_t *,rle_alloc_size);
631
6.72k
          if (offsets == (magick_uint32_t *) NULL)
632
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
633
6.72k
                                    image);
634
6.72k
          if (ReadBlob(image,rle_alloc_size,offsets) != rle_alloc_size)
635
6.72k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
636
637
6.72k
          if (TellBlob(image)+rle_alloc_size > (size_t) file_size)
638
6.69k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
639
6.69k
          runlength=MagickAllocateResourceLimitedMemory(magick_uint32_t *,rle_alloc_size);
640
6.69k
          if (runlength == (magick_uint32_t *) NULL)
641
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
642
6.69k
                                    image);
643
6.69k
          if (ReadBlob(image,rle_alloc_size,runlength) != rle_alloc_size)
644
6.69k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
645
646
6.69k
#if !defined(WORDS_BIGENDIAN)
647
6.69k
          MagickSwabArrayOfUInt32(offsets,rle_dimensions);
648
6.69k
          MagickSwabArrayOfUInt32(runlength,rle_dimensions);
649
6.69k
#endif
650
6.69k
          here=TellBlob(image);
651
652
21.3k
          for (i=0U; i < rle_dimensions; i++)
653
16.7k
            if ((offsets[i] != ((magick_off_t) offsets[i])) ||
654
16.7k
                (offsets[i] < here) ||
655
15.5k
                (offsets[i] > file_size))
656
4.63k
              ThrowSGIReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
657
18.1k
          for (i=0U; i < rle_dimensions; i++)
658
14.0k
            {
659
14.0k
              if (runlength[i] > ((size_t) 4U*iris_info.xsize+10U))
660
13.5k
                ThrowSGIReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
661
13.5k
            }
662
663
4.09k
          max_packets_alloc_size=MagickArraySize((size_t) iris_info.xsize+10U,4U);
664
4.09k
          max_packets=MagickAllocateResourceLimitedMemory(unsigned char *,max_packets_alloc_size);
665
4.09k
          if (max_packets == (unsigned char *) NULL)
666
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
667
4.09k
                                    image);
668
669
4.09k
          iris_pixels_size=MagickArraySize(MagickArraySize(4U,bytes_per_pixel),
670
4.09k
                                           MagickArraySize(iris_info.xsize,iris_info.ysize));
671
4.09k
          iris_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,iris_pixels_size);
672
4.09k
          if (iris_pixels == (unsigned char *) NULL)
673
4.09k
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,image);
674
675
4.09k
          (void) memset(iris_pixels,0,iris_pixels_size);
676
677
          /*
678
            Check data order.
679
          */
680
4.09k
          offset=0;
681
4.09k
          data_order=0U;
682
10.9k
          for (y=0; ((y < iris_info.ysize) && !data_order); y++)
683
16.1k
            for (z=0U; ((z < iris_info.zsize) && !data_order); z++)
684
9.31k
              {
685
9.31k
                const size_t run_index = (size_t) y+z*iris_info.ysize;
686
9.31k
                if (run_index >= rle_alloc_size)
687
0
                  ThrowSGIReaderException(CorruptImageError,
688
9.31k
                                          UnableToRunlengthDecodeImage,image);
689
9.31k
                if (offsets[run_index] < offset)
690
155
                  data_order=1;
691
9.31k
                offset=(magick_off_t) offsets[run_index];
692
9.31k
              }
693
4.09k
          offset=TellBlob(image);
694
4.09k
          if (data_order == 1)
695
155
            {
696
255
              for (z=0U; z < iris_info.zsize; z++)
697
213
                {
698
213
                  p=iris_pixels;
699
2.80k
                  for (y=0U; y < iris_info.ysize; y++)
700
2.70k
                    {
701
2.70k
                      const size_t run_index = (size_t) y+z*iris_info.ysize;
702
2.70k
                      size_t length;
703
2.70k
                      if (run_index >= rle_alloc_size)
704
0
                        ThrowSGIReaderException(CorruptImageError,
705
2.70k
                                                UnableToRunlengthDecodeImage,image);
706
2.70k
                      if (offset != (magick_off_t) offsets[run_index])
707
2.31k
                        {
708
2.31k
                          offset=(magick_off_t) offsets[run_index];
709
2.31k
                          if (SeekBlob(image,offset,SEEK_SET) != offset)
710
0
                            ThrowSGIReaderException(CorruptImageError,
711
2.31k
                                                    UnableToRunlengthDecodeImage, image);
712
2.31k
                        }
713
2.70k
                      length=runlength[run_index];
714
2.70k
                      if (length > max_packets_alloc_size)
715
0
                        ThrowSGIReaderException(CorruptImageError,
716
2.70k
                                                UnableToRunlengthDecodeImage,image);
717
2.70k
                      if (ReadBlob(image,length,(char *) max_packets) != length)
718
83
                        ThrowSGIReaderException(CorruptImageError,
719
2.70k
                                                UnexpectedEndOfFile, image);
720
2.62k
                      offset+=(magick_off_t) length;
721
2.62k
                      if (SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z,
722
2.62k
                                    length/bytes_per_pixel,
723
2.62k
                                    iris_info.xsize) == -1)
724
30
                        ThrowSGIReaderException(CorruptImageError,
725
2.62k
                                                UnableToRunlengthDecodeImage,image);
726
2.59k
                      p+=((size_t) iris_info.xsize*4U*bytes_per_pixel);
727
2.59k
                    }
728
213
                }
729
155
            }
730
3.94k
          else
731
3.94k
            {
732
3.94k
              p=iris_pixels;
733
6.24k
              for (y=0; y < iris_info.ysize; y++)
734
4.80k
                {
735
8.11k
                  for (z=0; z < iris_info.zsize; z++)
736
5.80k
                    {
737
5.80k
                      const size_t run_index = (size_t) y+z*iris_info.ysize;
738
5.80k
                      size_t length;
739
5.80k
                      if (run_index >= rle_alloc_size)
740
0
                        ThrowSGIReaderException(CorruptImageError,
741
5.80k
                                                UnableToRunlengthDecodeImage,image);
742
5.80k
                      if (offset != (magick_off_t) offsets[run_index])
743
4.42k
                        {
744
4.42k
                          offset=(magick_off_t) offsets[run_index];
745
4.42k
                          if (SeekBlob(image,offset,SEEK_SET) != offset)
746
0
                            ThrowSGIReaderException(CorruptImageError,
747
4.42k
                                                    UnableToRunlengthDecodeImage, image);
748
4.42k
                        }
749
5.80k
                      length=runlength[run_index];
750
5.80k
                      if (length > max_packets_alloc_size)
751
0
                        ThrowSGIReaderException(CorruptImageError,
752
5.80k
                                                UnableToRunlengthDecodeImage,image);
753
5.80k
                      if (ReadBlob(image,length, (char *) max_packets) != length)
754
69
                        ThrowSGIReaderException(CorruptImageError,
755
5.80k
                                                UnexpectedEndOfFile, image);
756
5.73k
                      offset+=length;
757
5.73k
                      if (SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z,
758
5.73k
                                    length/bytes_per_pixel,
759
5.73k
                                    iris_info.xsize) == -1)
760
2.43k
                        ThrowSGIReaderException(CorruptImageError,
761
5.73k
                                                UnableToRunlengthDecodeImage,image);
762
3.30k
                    }
763
2.30k
                  p+=((size_t) iris_info.xsize*4U*bytes_per_pixel);
764
2.30k
                  if (EOFBlob(image))
765
0
                    break;
766
2.30k
                }
767
3.94k
            }
768
1.47k
          MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength);
769
1.47k
          MagickFreeResourceLimitedMemory(unsigned char *,max_packets);
770
1.47k
          MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);
771
1.47k
        }
772
773
      /*
774
        Convert SGI raster image to pixel packets.
775
      */
776
2.97k
      if (image->storage_class == DirectClass)
777
659
        {
778
          /*
779
            Convert SGI image to DirectClass pixel packets.
780
          */
781
659
          if (bytes_per_pixel == 2U)
782
554
            {
783
34.6k
              for (y=0; y < image->rows; y++)
784
34.1k
                {
785
34.1k
                  p=iris_pixels+((size_t)image->rows-y-1)*8*image->columns;
786
34.1k
                  q=SetImagePixels(image,0,y,image->columns,1);
787
34.1k
                  if (q == (PixelPacket *) NULL)
788
145
                    break;
789
897k
                  for (x=0U; x < image->columns; x++)
790
863k
                    {
791
863k
                      q->red=ScaleShortToQuantum((*(p+0) << 8U) | (*(p+1)));
792
863k
                      q->green=ScaleShortToQuantum((*(p+2) << 8U) | (*(p+3)));
793
863k
                      q->blue=ScaleShortToQuantum((*(p+4) << 8U) | (*(p+5)));
794
863k
                      if (image->matte)
795
4.43k
                        q->opacity=(Quantum)
796
4.43k
                          (MaxRGB-ScaleShortToQuantum((*(p+6) << 8) | (*(p+7))));
797
858k
                      else
798
858k
                        q->opacity=OpaqueOpacity;
799
863k
                      p+=8U;
800
863k
                      q++;
801
863k
                    }
802
34.0k
                  if (!SyncImagePixels(image))
803
0
                    break;
804
34.0k
                  if (QuantumTick(y,image->rows))
805
8.58k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
806
8.58k
                                                LoadImageText,image->filename,
807
8.58k
                                                image->columns,image->rows))
808
0
                      break;
809
34.0k
                }
810
554
            }
811
105
          else
812
69.7k
            for (y=0; y < image->rows; y++)
813
69.6k
              {
814
69.6k
                p=iris_pixels+((size_t) image->rows-y-1)*4*image->columns;
815
69.6k
                q=SetImagePixels(image,0,y,image->columns,1);
816
69.6k
                if (q == (PixelPacket *) NULL)
817
0
                  break;
818
625k
                for (x=0; x < image->columns; x++)
819
556k
                  {
820
556k
                    q->red=ScaleCharToQuantum(*p);
821
556k
                    q->green=ScaleCharToQuantum(*(p+1));
822
556k
                    q->blue=ScaleCharToQuantum(*(p+2));
823
556k
                    if (image->matte)
824
476k
                      q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*(p+3)));
825
79.0k
                    else
826
79.0k
                      q->opacity=OpaqueOpacity;
827
556k
                    p+=4;
828
556k
                    q++;
829
556k
                  }
830
69.6k
                if (!SyncImagePixels(image))
831
0
                  break;
832
69.6k
                if (QuantumTick(y,image->rows))
833
7.11k
                  if (!MagickMonitorFormatted(y,image->rows,exception,
834
7.11k
                                              LoadImageText,image->filename,
835
7.11k
                                              image->columns,image->rows))
836
0
                    break;
837
69.6k
              }
838
659
        }
839
2.31k
      else
840
2.31k
        {
841
          /*
842
            Create grayscale map.
843
          */
844
2.31k
          if (!AllocateImageColormap(image,image->colors))
845
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
846
2.31k
                                    image);
847
          /*
848
            Convert SGI image to PseudoClass pixel packets.
849
          */
850
2.31k
          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.31k
          else
876
2.31k
            {
877
44.0k
              for (y=0; y < image->rows; y++)
878
42.4k
                {
879
42.4k
                  p=iris_pixels+((size_t)image->rows-y-1)*4U*image->columns;
880
42.4k
                  q=SetImagePixels(image,0,y,image->columns,1);
881
42.4k
                  if (q == (PixelPacket *) NULL)
882
733
                    break;
883
41.7k
                  indexes=AccessMutableIndexes(image);
884
10.4M
                  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
41.7k
                  if (!SyncImagePixels(image))
891
0
                    break;
892
41.7k
                  if (QuantumTick(y,image->rows))
893
10.7k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
894
10.7k
                                                LoadImageText,image->filename,
895
10.7k
                                                image->columns,image->rows))
896
0
                      break;
897
41.7k
                }
898
2.31k
            }
899
2.31k
          if (y < image->rows)
900
733
            {
901
733
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
902
733
                                    "Only transferred %lu rows out of %lu",
903
733
                                    y, image->rows);
904
733
              MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
905
              /*
906
                Not sure what a proper error report is here
907
               */
908
733
              ThrowSGIReaderException(CorruptImageError,UnableToReadImageData,image);
909
0
            }
910
1.57k
          (void) SyncImage(image);
911
1.57k
        }
912
2.23k
      MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
913
2.23k
      if (EOFBlob(image))
914
0
        {
915
0
          ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,
916
0
                                  image);
917
0
          break;
918
0
        }
919
2.23k
    } while (0);
920
2.23k
  CloseBlob(image);
921
2.23k
  StopTimer(&image->timer);
922
2.23k
  return(image);
923
135k
}
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
407k
{
1021
407k
  short
1022
407k
    runlength;
1023
1024
407k
  register unsigned char
1025
407k
    *p,
1026
407k
    *q;
1027
1028
407k
  unsigned char
1029
407k
    *limit,
1030
407k
    *mark;
1031
1032
407k
  p=pixels;
1033
407k
  limit=p+count*4;
1034
407k
  q=packets;
1035
1.11M
  while (p < limit)
1036
709k
    {
1037
709k
      mark=p;
1038
709k
      p+=8;
1039
6.97M
      while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
1040
6.26M
        p+=4;
1041
709k
      p-=8;
1042
709k
      count=((p-mark) >> 2);
1043
1.03M
      while (count)
1044
329k
        {
1045
329k
          runlength=(short) (count > 126 ? 126 : count);
1046
329k
          count-=runlength;
1047
329k
          *q++=0x80 | runlength;
1048
6.59M
          for ( ; runlength > 0; runlength--)
1049
6.26M
            {
1050
6.26M
              *q++=(*mark);
1051
6.26M
              mark+=4;
1052
6.26M
            }
1053
329k
        }
1054
709k
      mark=p;
1055
709k
      p+=4;
1056
8.84M
      while ((p < limit) && (*p == *mark))
1057
8.13M
        p+=4;
1058
709k
      count=((p-mark) >> 2);
1059
1.47M
      while (count)
1060
765k
        {
1061
765k
          runlength=(short) (count > 126 ? 126 : count);
1062
765k
          count-=runlength;
1063
765k
          *q++=(unsigned char) runlength;
1064
765k
          *q++=(*mark);
1065
765k
        }
1066
709k
    }
1067
407k
  *q++=0;
1068
407k
  return(q-packets);
1069
407k
}
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
470
{
1083
470
  long
1084
470
    y,
1085
470
    z;
1086
1087
470
  SGIInfo
1088
470
    iris_info;
1089
1090
470
  register const PixelPacket
1091
470
    *p;
1092
1093
470
  register long
1094
470
    i,
1095
470
    x;
1096
1097
470
  register unsigned char
1098
470
    *q;
1099
1100
470
  magick_uint32_t
1101
470
    *offsets = (magick_uint32_t *) NULL,
1102
470
    *runlength = (magick_uint32_t *) NULL;
1103
1104
470
  unsigned char
1105
470
    *iris_pixels = (unsigned char *) NULL,
1106
470
    *packets = (unsigned char *) NULL,
1107
470
    *scanline = (unsigned char *) NULL;
1108
1109
470
  unsigned int
1110
470
    status;
1111
1112
470
  unsigned long
1113
470
    number_pixels;
1114
1115
  /*
1116
    Open output image file.
1117
  */
1118
470
  assert(image_info != (const ImageInfo *) NULL);
1119
470
  assert(image_info->signature == MagickSignature);
1120
470
  assert(image != (Image *) NULL);
1121
470
  assert(image->signature == MagickSignature);
1122
470
  if ((image->columns > 65535L) || (image->rows > 65535L))
1123
470
    ThrowWriterException(ImageError,WidthOrHeightExceedsLimit,image);
1124
470
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1125
470
  if (status == MagickFail)
1126
470
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
1127
470
  do
1128
470
    {
1129
470
      ImageCharacteristics
1130
470
        characteristics;
1131
1132
      /*
1133
        Ensure that image is in an RGB space.
1134
      */
1135
470
      if (TransformColorspace(image,RGBColorspace) == MagickFail)
1136
470
        ThrowWriterException(CoderError,UnableToTransformColorspace,image);
1137
      /*
1138
        Analyze image to be written.
1139
      */
1140
470
      if (GetImageCharacteristics(image,&characteristics,
1141
470
                                  (OptimizeType == image_info->type),
1142
470
                                  &image->exception) == MagickFail)
1143
470
        ThrowWriterException(CoderError,UnableToGetImageCharacteristics,image);
1144
      /*
1145
        Initialize SGI raster file header.
1146
      */
1147
470
      iris_info.magic=0x01DA;
1148
470
      if (image_info->compression == NoCompression)
1149
0
        iris_info.storage=0x00;
1150
470
      else
1151
470
        iris_info.storage=0x01;
1152
470
      iris_info.bytes_per_pixel=1;  /* one byte per pixel */
1153
470
      iris_info.dimension=3;
1154
470
      iris_info.xsize=(unsigned short) image->columns;
1155
470
      iris_info.ysize=(unsigned short) image->rows;
1156
470
      if (image->matte != MagickFalse)
1157
53
        iris_info.zsize=4;
1158
417
      else
1159
417
        {
1160
417
          if ((image_info->type != TrueColorType) &&
1161
417
              (characteristics.grayscale))
1162
221
            {
1163
221
              iris_info.dimension=2;
1164
221
              iris_info.zsize=1;
1165
221
            }
1166
196
          else
1167
196
            iris_info.zsize=3;
1168
417
        }
1169
470
      iris_info.pix_min=0;
1170
470
      iris_info.pix_max=ScaleQuantumToChar(MaxRGB);
1171
1172
470
      (void) memset(iris_info.dummy1,0,sizeof(iris_info.dummy1));
1173
470
      {
1174
470
        const ImageAttribute
1175
470
          *attribute;
1176
1177
470
        (void) memset(iris_info.image_name,0,sizeof(iris_info.image_name));
1178
470
        if ((attribute=GetImageAttribute(image,"comment")))
1179
272
          (void) strlcpy(iris_info.image_name,attribute->value,sizeof(iris_info.image_name));
1180
470
      }
1181
470
      iris_info.color_map=0;
1182
470
      (void) memset(iris_info.dummy2,0,sizeof(iris_info.dummy2));
1183
1184
      /*
1185
        Write SGI header.
1186
      */
1187
470
      (void) WriteBlobMSBShort(image,iris_info.magic);
1188
470
      (void) WriteBlobByte(image,iris_info.storage);
1189
470
      (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
1190
470
      (void) WriteBlobMSBShort(image,iris_info.dimension);
1191
470
      (void) WriteBlobMSBShort(image,iris_info.xsize);
1192
470
      (void) WriteBlobMSBShort(image,iris_info.ysize);
1193
470
      (void) WriteBlobMSBShort(image,iris_info.zsize);
1194
470
      (void) WriteBlobMSBLong(image,iris_info.pix_min);
1195
470
      (void) WriteBlobMSBLong(image,iris_info.pix_max);
1196
470
      (void) WriteBlob(image,sizeof(iris_info.dummy1),
1197
470
                       (char *) iris_info.dummy1);
1198
470
      (void) WriteBlob(image,sizeof(iris_info.image_name),
1199
470
                       (char *) iris_info.image_name);
1200
470
      (void) WriteBlobMSBLong(image,iris_info.color_map);
1201
470
      (void) WriteBlob(image,sizeof(iris_info.dummy2),
1202
470
                       (char *) iris_info.dummy2);
1203
      /*
1204
        Allocate SGI pixels.
1205
      */
1206
470
      number_pixels=image->columns*image->rows;
1207
470
      iris_pixels=MagickAllocateResourceLimitedArray(unsigned char *,4,number_pixels);
1208
470
      if (iris_pixels == (unsigned char *) NULL)
1209
470
        ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,image);
1210
      /*
1211
        Convert image pixels to uncompressed SGI pixels.
1212
      */
1213
144k
      for (y=0; y < (long) image->rows; y++)
1214
143k
        {
1215
143k
          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1216
143k
          if (p == (const PixelPacket *) NULL)
1217
0
            break;
1218
143k
          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.7M
            {
1221
11.7M
              *q++=ScaleQuantumToChar(p->red);
1222
11.7M
              *q++=ScaleQuantumToChar(p->green);
1223
11.7M
              *q++=ScaleQuantumToChar(p->blue);
1224
11.7M
              *q++=ScaleQuantumToChar(MaxRGB-p->opacity);
1225
11.7M
              p++;
1226
11.7M
            }
1227
143k
          if (QuantumTick(y,image->rows))
1228
24.8k
            if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1229
24.8k
                                        SaveImageText,image->filename,
1230
24.8k
                                        image->columns,image->rows))
1231
0
              break;
1232
143k
        }
1233
470
      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
470
      else
1258
470
        {
1259
470
          magick_uint32_t
1260
470
            length,
1261
470
            number_packets,
1262
470
            offset;
1263
1264
          /*
1265
            Convert SGI uncompressed pixels.
1266
          */
1267
470
          offsets=MagickAllocateResourceLimitedArray(magick_uint32_t *,iris_info.ysize,
1268
470
                                      MagickArraySize(iris_info.zsize,
1269
470
                                                      sizeof(magick_uint32_t)));
1270
470
          packets=MagickAllocateResourceLimitedArray(unsigned char *,
1271
470
                                      4*(2*(size_t) iris_info.xsize+10),
1272
470
                                      image->rows);
1273
470
          runlength=MagickAllocateResourceLimitedArray(magick_uint32_t *,iris_info.ysize,
1274
470
                                        MagickArraySize(iris_info.zsize,
1275
470
                                                        sizeof(magick_uint32_t)));
1276
470
          if ((offsets == (magick_uint32_t *) NULL) ||
1277
470
              (packets == (unsigned char *) NULL) ||
1278
470
              (runlength == (magick_uint32_t *) NULL))
1279
0
            ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,
1280
470
                                    image);
1281
470
          offset=512+4*2*((size_t) iris_info.ysize*iris_info.zsize);
1282
470
          number_packets=0;
1283
470
          q=iris_pixels;
1284
144k
          for (y=0; y < (long) iris_info.ysize; y++)
1285
143k
            {
1286
551k
              for (z=0; z < (int) iris_info.zsize; z++)
1287
407k
                {
1288
407k
                  length=(magick_uint32_t)
1289
407k
                    SGIEncode(q+z,(int) iris_info.xsize,packets+number_packets);
1290
407k
                  number_packets+=length;
1291
407k
                  offsets[y+z*iris_info.ysize]=offset;
1292
407k
                  runlength[y+z*iris_info.ysize]=length;
1293
407k
                  offset+=length;
1294
407k
                }
1295
143k
              q+=((size_t)iris_info.xsize*4);
1296
143k
            }
1297
          /*
1298
            Write out line start and length tables and runlength-encoded pixels.
1299
          */
1300
407k
          for (i=0; i < (int) (iris_info.ysize*iris_info.zsize); i++)
1301
407k
            (void) WriteBlobMSBLong(image,offsets[i]);
1302
407k
          for (i=0; i < (int) (iris_info.ysize*iris_info.zsize); i++)
1303
407k
            (void) WriteBlobMSBLong(image,runlength[i]);
1304
470
          (void) WriteBlob(image,number_packets,(char *) packets);
1305
          /*
1306
            Free memory.
1307
          */
1308
470
          MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength);
1309
470
          MagickFreeResourceLimitedMemory(unsigned char *,packets);
1310
470
          MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);
1311
470
        }
1312
470
      MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
1313
470
    } while (0);
1314
470
  status &= CloseBlob(image);
1315
470
  return(status);
1316
470
}