Coverage Report

Created: 2025-08-11 08:01

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