Coverage Report

Created: 2026-01-20 07:37

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-2025 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
7.52k
{
169
7.52k
  size_t
170
7.52k
    count;
171
172
7.52k
  register unsigned char
173
7.52k
    *p,
174
7.52k
    *q;
175
176
7.52k
  unsigned int
177
7.52k
    pixel;
178
179
7.52k
  p=max_packets;
180
7.52k
  q=pixels;
181
7.52k
  if (bytes_per_pixel == 2)
182
1.62k
    {
183
1.62k
      for ( ; ; )
184
3.97k
        {
185
3.97k
          if (npackets-- == 0)
186
53
            return -1;
187
3.92k
          pixel=(*p++) << 8U;
188
3.92k
          pixel|=(*p++);
189
3.92k
          count=(pixel & 0x7fU);
190
3.92k
          if (count == 0)
191
1.12k
            break;
192
2.79k
          if (count > npixels)
193
323
            return -1;
194
2.47k
          npixels -= count;
195
2.47k
          if (pixel & 0x80U)
196
21.7k
            for ( ; count != 0U; count--)
197
21.0k
              {
198
21.0k
                if (npackets-- == 0)
199
22
                  return -1;
200
21.0k
                *q=(*p++);
201
21.0k
                *(q+1)=(*p++);
202
21.0k
                q+=8U;
203
21.0k
              }
204
1.79k
          else
205
1.79k
            {
206
1.79k
              if (npackets-- == 0)
207
103
                return -1;
208
1.68k
              pixel=(*p++) << 8U;
209
1.68k
              pixel|=(*p++);
210
62.7k
              for ( ; count != 0; count--)
211
61.0k
                {
212
61.0k
                  *q=(unsigned char) (pixel >> 8U);
213
61.0k
                  *(q+1)=(unsigned char) pixel;
214
61.0k
                  q+=8U;
215
61.0k
                }
216
1.68k
            }
217
2.47k
        }
218
1.12k
      return 0;
219
1.62k
    }
220
5.89k
  for ( ; ; )
221
21.8k
    {
222
21.8k
      if (npackets-- == 0)
223
174
        return -1;
224
21.7k
      pixel=(*p++);
225
21.7k
      count= (pixel & 0x7fU);
226
21.7k
      if (count == 0)
227
4.28k
        break;
228
17.4k
      if (count > npixels)
229
1.16k
        return -1;
230
16.2k
      npixels -= count;
231
16.2k
      if (pixel & 0x80)
232
258k
        for ( ; count != 0; count--)
233
252k
          {
234
252k
            if (npackets-- == 0)
235
16
              return -1;
236
252k
            *q=(*p++);
237
252k
            q+=4;
238
252k
          }
239
9.88k
      else
240
9.88k
        {
241
9.88k
          if (npackets-- == 0)
242
254
            return -1;
243
9.63k
          pixel=(*p++);
244
182k
          for ( ; count != 0; count--)
245
173k
            {
246
173k
              *q=(unsigned char) pixel;
247
173k
              q+=4;
248
173k
            }
249
9.63k
        }
250
16.2k
    }
251
4.28k
  return 0;
252
5.89k
}
253
254
11.5k
#define ThrowSGIReaderException(code_,reason_,image_) \
255
11.5k
{ \
256
11.5k
  MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels) \
257
11.5k
  MagickFreeResourceLimitedMemory(unsigned char *,max_packets); \
258
11.5k
  MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);   \
259
11.5k
  MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength); \
260
11.5k
  MagickFreeResourceLimitedMemory(unsigned char *,scanline) \
261
11.5k
  ThrowReaderException(code_,reason_,image_); \
262
0
}
263
264
static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
265
120k
{
266
120k
  Image
267
120k
    *image;
268
269
120k
  size_t
270
120k
    z;
271
272
120k
  register IndexPacket
273
120k
    *indexes;
274
275
120k
  register size_t
276
120k
    i;
277
278
120k
  unsigned long
279
120k
        x,
280
120k
    y;
281
282
120k
  register PixelPacket
283
120k
    *q;
284
285
120k
  register unsigned char
286
120k
    *p;
287
288
120k
  SGIInfo
289
120k
    iris_info;
290
291
120k
  magick_uint32_t
292
120k
    *offsets = (magick_uint32_t *) NULL,
293
120k
    *runlength = (magick_uint32_t *) NULL;
294
295
120k
  unsigned char
296
120k
    *iris_pixels = (unsigned char *) NULL,
297
120k
    *max_packets = (unsigned char *) NULL,
298
120k
    *scanline = (unsigned char *) NULL;
299
300
120k
  unsigned int
301
120k
    status;
302
303
120k
  size_t
304
120k
    bytes_per_pixel;
305
306
120k
  magick_off_t
307
120k
    file_size;
308
309
  /*
310
    Open image file.
311
  */
312
120k
  assert(image_info != (const ImageInfo *) NULL);
313
120k
  assert(image_info->signature == MagickSignature);
314
120k
  assert(exception != (ExceptionInfo *) NULL);
315
120k
  assert(exception->signature == MagickSignature);
316
120k
  image=AllocateImage(image_info);
317
120k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
318
120k
  if (status == False)
319
120k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
320
120k
  file_size=GetBlobSize(image);
321
120k
  do
322
120k
    {
323
      /*
324
        Read SGI raster header.
325
      */
326
120k
      (void) memset(&iris_info, 0, sizeof(iris_info));
327
120k
      iris_info.magic=ReadBlobMSBShort(image);
328
120k
      iris_info.storage=ReadBlobByte(image);
329
120k
      iris_info.bytes_per_pixel=ReadBlobByte(image) &0xF;
330
120k
      iris_info.dimension=ReadBlobMSBShort(image) & 0xFFFF;
331
120k
      iris_info.xsize=ReadBlobMSBShort(image) & 0xFFFF;
332
120k
      iris_info.ysize=ReadBlobMSBShort(image) & 0xFFFF;
333
120k
      iris_info.zsize=ReadBlobMSBShort(image) & 0xFFFF;
334
120k
      iris_info.pix_min=ReadBlobMSBLong(image) & 0xFFFFFFFF;
335
120k
      iris_info.pix_max=ReadBlobMSBLong(image) & 0xFFFFFFFF;
336
337
120k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.dummy1),
338
120k
                      iris_info.dummy1);
339
120k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.image_name),
340
120k
                      iris_info.image_name);
341
120k
      iris_info.image_name[sizeof(iris_info.image_name)-1]=0;
342
120k
      iris_info.color_map=ReadBlobMSBLong(image);
343
120k
      (void) ReadBlob(image,(unsigned int) sizeof(iris_info.dummy2),
344
120k
                      iris_info.dummy2);
345
346
120k
      if (EOFBlob(image))
347
104k
        ThrowReaderException(CorruptImageError,UnableToReadImageHeader,image);
348
349
16.2k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
350
16.2k
                            "IRIS Header:\n"
351
16.2k
                            "    MAGIC=%u\n"
352
16.2k
                            "    STORAGE=%u (%s)\n"
353
16.2k
                            "    BPC=%u\n"
354
16.2k
                            "    DIMENSION=%u\n"
355
16.2k
                            "    XSIZE=%u\n"
356
16.2k
                            "    YSIZE=%u\n"
357
16.2k
                            "    ZSIZE=%u\n"
358
16.2k
                            "    PIXMIN=%u\n"
359
16.2k
                            "    PIXMAX=%u\n"
360
16.2k
                            "    IMAGENAME=\"%.79s\"\n"
361
16.2k
                            "    COLORMAP=%u",
362
16.2k
                            (unsigned int) iris_info.magic,
363
16.2k
                            (unsigned int) iris_info.storage,
364
16.2k
                            (iris_info.storage == 1 ? "RLE" : "VERBATIM"),
365
16.2k
                            (unsigned int) iris_info.bytes_per_pixel,
366
16.2k
                            (unsigned int) iris_info.dimension,
367
16.2k
                            (unsigned int) iris_info.xsize,
368
16.2k
                            (unsigned int) iris_info.ysize,
369
16.2k
                            (unsigned int) iris_info.zsize,
370
16.2k
                            iris_info.pix_min,
371
16.2k
                            iris_info.pix_max,
372
16.2k
                            iris_info.image_name,
373
16.2k
                            iris_info.color_map);
374
16.2k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
375
16.2k
                            "File size %" MAGICK_OFF_F "d bytes", file_size);
376
377
      /*
378
        Validate image header and set image attributes.
379
      */
380
16.2k
      if (iris_info.magic != 0x01DA)
381
16.2k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
382
383
16.2k
      if (iris_info.storage == 0U)
384
4.05k
        {
385
          /* Uncompressed */
386
4.05k
          image->compression=NoCompression;
387
4.05k
        }
388
12.1k
      else if (iris_info.storage == 1U)
389
11.5k
        {
390
          /* RLE compressed */
391
11.5k
          image->compression=RLECompression;
392
11.5k
        }
393
607
      else
394
607
        {
395
          /* Error */
396
607
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
397
0
        }
398
399
15.5k
      if (iris_info.color_map != 0U)
400
2.60k
        {
401
          /* We only support images with normal (no) colormap */
402
2.60k
          ThrowReaderException(CorruptImageError,ImageTypeNotSupported,image);
403
0
        }
404
405
12.9k
      if (iris_info.bytes_per_pixel == 1U)
406
10.1k
        {
407
          /* 8 bits per sample */
408
10.1k
          image->depth=8;
409
10.1k
        }
410
2.86k
      else if (iris_info.bytes_per_pixel == 2U)
411
1.34k
        {
412
          /* 16 bits per sample */
413
1.34k
          image->depth=Min(16,QuantumDepth);
414
1.34k
        }
415
1.51k
      else
416
1.51k
        {
417
          /* Error */
418
1.51k
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
419
0
        }
420
421
      /* We only support zsize up to 4. Code further on assumes that. */
422
11.4k
      if (iris_info.zsize > 4U)
423
10.2k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
424
425
10.2k
      if (iris_info.dimension == 1U)
426
7.64k
        {
427
          /*
428
            Image contains one channel and one scanline, with scanline
429
            length specified by xsize.
430
          */
431
7.64k
          image->columns=iris_info.xsize;
432
7.64k
          image->rows=1;
433
7.64k
          if (iris_info.ysize != image->rows)
434
7.59k
            {
435
7.59k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
436
7.59k
                                    "Overriding unexpected value of YSIZE (%u) "
437
7.59k
                                    "for 1 dimensional image", iris_info.ysize);
438
7.59k
              iris_info.ysize=image->rows;
439
7.59k
            }
440
7.64k
          image->is_grayscale=MagickTrue;
441
7.64k
          if (iris_info.bytes_per_pixel == 1U)
442
6.51k
            {
443
              /* Use a grayscale colormap */
444
6.51k
              image->storage_class=PseudoClass;
445
6.51k
              image->colors=256;
446
6.51k
            }
447
7.64k
        }
448
2.59k
      else if (iris_info.dimension == 2U)
449
534
        {
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
534
          image->columns=iris_info.xsize;
455
534
          image->rows=iris_info.ysize;
456
534
          image->is_grayscale=MagickTrue;
457
534
          if (iris_info.bytes_per_pixel == 1)
458
362
            {
459
              /* Use a grayscale colormap */
460
362
              image->storage_class=PseudoClass;
461
362
              image->colors=256;
462
362
            }
463
534
        }
464
2.06k
      else if (iris_info.dimension == 3U)
465
1.27k
        {
466
          /*
467
            A number of channels.  Width and height of image are given
468
            by the values of xsize and ysize. The number of channels is
469
            specified by zsize.
470
471
            B/W images have a zsize of 1.  RGB images have a zsize of 3.
472
            RGB images with an alpha channel have a zsize of 4. Images
473
            may have more than four channels but the meaning of
474
            additional channels is implementation dependent.
475
          */
476
477
1.27k
          image->columns=iris_info.xsize;
478
1.27k
          image->rows=iris_info.ysize;
479
480
1.27k
          if (iris_info.zsize == 1U)
481
73
            {
482
              /* B/W image */
483
73
              image->matte = MagickFalse;
484
73
              image->is_grayscale=MagickTrue;
485
73
              if (iris_info.bytes_per_pixel == 1U)
486
62
                {
487
                  /* Use a grayscale colormap */
488
62
                  image->storage_class=PseudoClass;
489
62
                  image->colors=256U;
490
62
                }
491
73
            }
492
1.20k
          else if (iris_info.zsize == 3U)
493
119
            {
494
              /* RGB */
495
119
              image->matte=MagickFalse;
496
119
            }
497
1.08k
          else if (iris_info.zsize == 4U)
498
81
            {
499
              /* RGBA  */
500
81
              image->matte=MagickTrue;
501
81
            }
502
1.00k
          else
503
1.00k
            {
504
              /* Error */
505
1.00k
              ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
506
0
            }
507
1.27k
        }
508
786
      else
509
786
        {
510
          /* Error */
511
786
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
512
0
        }
513
514
8.45k
      if (iris_info.image_name[0])
515
4.30k
        (void) SetImageAttribute(image,"comment",iris_info.image_name);
516
517
8.45k
      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
8.45k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
522
8.45k
                            "Image columns=%lu rows=%lu", image->columns, image->rows);
523
524
8.45k
      if (CheckImagePixelLimits(image, exception) != MagickPass)
525
8.01k
        ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
526
527
      /*
528
        Allocate SGI pixels.
529
      */
530
8.01k
      bytes_per_pixel=iris_info.bytes_per_pixel;
531
8.01k
      if (iris_info.storage != 0x01)
532
1.50k
        {
533
1.50k
          double
534
1.50k
              uncompressed_size;
535
536
1.50k
          size_t
537
1.50k
            iris_pixels_size;
538
539
          /*
540
            Check that filesize is reasonable given header
541
          */
542
1.50k
          uncompressed_size=((double) (iris_info.dimension == 3U ? iris_info.zsize : 1U)*
543
1.50k
                             image->columns*image->rows*iris_info.bytes_per_pixel);
544
1.50k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
545
1.50k
                                "Uncompressed size: %.0f", uncompressed_size);
546
547
          /* Not compressed */
548
1.50k
          if (uncompressed_size > file_size)
549
3
            ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,
550
1.50k
                                 image);
551
552
          /*
553
            Read standard image format.
554
          */
555
1.50k
          scanline=MagickAllocateResourceLimitedArray(unsigned char *,
556
1.50k
                                       bytes_per_pixel,iris_info.xsize);
557
1.50k
          if (scanline == (unsigned char *) NULL)
558
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
559
1.50k
                                    image);
560
561
1.50k
          iris_pixels_size = MagickArraySize(MagickArraySize(4U,bytes_per_pixel),
562
1.50k
                                             MagickArraySize(iris_info.xsize,iris_info.ysize));
563
1.50k
          iris_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,iris_pixels_size);
564
1.50k
          if (iris_pixels == (unsigned char *) NULL)
565
1.50k
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,image);
566
1.50k
          (void) memset(iris_pixels,0,iris_pixels_size);
567
568
1.50k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
569
1.50k
                                "   Reading SGI scanlines");
570
3.37k
          for (z=0U; z < iris_info.zsize; z++)
571
1.98k
            {
572
1.98k
              p=iris_pixels+bytes_per_pixel*z;
573
329k
              for (y=0U; y < iris_info.ysize; y++)
574
327k
                {
575
327k
                  if (ReadBlob(image,bytes_per_pixel*iris_info.xsize,
576
327k
                               (char *) scanline) != bytes_per_pixel*iris_info.xsize)
577
118
                    {
578
118
                      ThrowSGIReaderException(CorruptImageError,
579
0
                                              UnexpectedEndOfFile, image);
580
0
                      break;
581
118
                    }
582
327k
                  if (bytes_per_pixel == 2U)
583
3.03M
                    for (x=0; x < iris_info.xsize; x++)
584
3.02M
                      {
585
3.02M
                        *p=scanline[2U*x];
586
3.02M
                        *(p+1U)=scanline[2U*x+1U];
587
3.02M
                        p+=8U;
588
3.02M
                      }
589
317k
                  else
590
30.0M
                    for (x=0; x < iris_info.xsize; x++)
591
29.7M
                      {
592
29.7M
                        *p=scanline[x];
593
29.7M
                        p+=4U;
594
29.7M
                      }
595
327k
                }
596
1.86k
              if (EOFBlob(image))
597
0
                break;
598
1.86k
            }
599
1.38k
          MagickFreeResourceLimitedMemory(unsigned char *,scanline);
600
1.38k
        }
601
6.50k
      else
602
6.50k
        {
603
6.50k
          unsigned int
604
6.50k
            data_order;
605
606
6.50k
          magick_off_t
607
6.50k
            offset;
608
609
6.50k
          size_t
610
6.50k
            iris_pixels_size,
611
6.50k
            max_packets_alloc_size,
612
6.50k
            rle_alloc_size,
613
6.50k
            rle_dimensions;
614
615
6.50k
          magick_off_t
616
6.50k
            here;
617
618
6.50k
          rle_dimensions=MagickArraySize(iris_info.ysize, iris_info.zsize);
619
6.50k
          rle_alloc_size=MagickArraySize(rle_dimensions, sizeof(magick_uint32_t));
620
621
6.50k
          if ((rle_dimensions == 0U) || (rle_alloc_size == 0U))
622
225
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
623
6.50k
                                    image);
624
625
          /*
626
            Read runlength-encoded image format.
627
          */
628
6.28k
          if (TellBlob(image)+rle_alloc_size > (size_t) file_size)
629
6.25k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
630
6.25k
          offsets=MagickAllocateResourceLimitedMemory(magick_uint32_t *,rle_alloc_size);
631
6.25k
          if (offsets == (magick_uint32_t *) NULL)
632
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
633
6.25k
                                    image);
634
6.25k
          if (ReadBlob(image,rle_alloc_size,offsets) != rle_alloc_size)
635
6.25k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
636
637
6.25k
          if (TellBlob(image)+rle_alloc_size > (size_t) file_size)
638
6.22k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
639
6.22k
          runlength=MagickAllocateResourceLimitedMemory(magick_uint32_t *,rle_alloc_size);
640
6.22k
          if (runlength == (magick_uint32_t *) NULL)
641
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
642
6.22k
                                    image);
643
6.22k
          if (ReadBlob(image,rle_alloc_size,runlength) != rle_alloc_size)
644
6.22k
            ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image);
645
646
6.22k
#if !defined(WORDS_BIGENDIAN)
647
6.22k
          MagickSwabArrayOfUInt32(offsets,rle_dimensions);
648
6.22k
          MagickSwabArrayOfUInt32(runlength,rle_dimensions);
649
6.22k
#endif
650
6.22k
          here=TellBlob(image);
651
652
18.7k
          for (i=0U; i < rle_dimensions; i++)
653
14.6k
            if ((offsets[i] != ((magick_off_t) offsets[i])) ||
654
14.6k
                (offsets[i] < here) ||
655
13.3k
                (offsets[i] > file_size))
656
4.11k
              ThrowSGIReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
657
14.9k
          for (i=0U; i < rle_dimensions; i++)
658
11.3k
            {
659
11.3k
              if (runlength[i] > ((size_t) 4U*iris_info.xsize+10U))
660
10.8k
                ThrowSGIReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
661
10.8k
            }
662
663
3.58k
          max_packets_alloc_size=MagickArraySize((size_t) iris_info.xsize+10U,4U);
664
3.58k
          max_packets=MagickAllocateResourceLimitedMemory(unsigned char *,max_packets_alloc_size);
665
3.58k
          if (max_packets == (unsigned char *) NULL)
666
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
667
3.58k
                                    image);
668
669
3.58k
          iris_pixels_size=MagickArraySize(MagickArraySize(4U,bytes_per_pixel),
670
3.58k
                                           MagickArraySize(iris_info.xsize,iris_info.ysize));
671
3.58k
          iris_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,iris_pixels_size);
672
3.58k
          if (iris_pixels == (unsigned char *) NULL)
673
3.58k
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,image);
674
675
3.58k
          (void) memset(iris_pixels,0,iris_pixels_size);
676
677
          /*
678
            Check data order.
679
          */
680
3.58k
          offset=0;
681
3.58k
          data_order=0U;
682
9.76k
          for (y=0; ((y < iris_info.ysize) && !data_order); y++)
683
14.3k
            for (z=0U; ((z < iris_info.zsize) && !data_order); z++)
684
8.19k
              {
685
8.19k
                const size_t run_index = (size_t) y+z*iris_info.ysize;
686
8.19k
                if (run_index >= rle_alloc_size)
687
0
                  ThrowSGIReaderException(CorruptImageError,
688
8.19k
                                          UnableToRunlengthDecodeImage,image);
689
8.19k
                if (offsets[run_index] < offset)
690
142
                  data_order=1;
691
8.19k
                offset=(magick_off_t) offsets[run_index];
692
8.19k
              }
693
3.58k
          offset=TellBlob(image);
694
3.58k
          if (data_order == 1)
695
142
            {
696
232
              for (z=0U; z < iris_info.zsize; z++)
697
191
                {
698
191
                  p=iris_pixels;
699
2.61k
                  for (y=0U; y < iris_info.ysize; y++)
700
2.52k
                    {
701
2.52k
                      const size_t run_index = (size_t) y+z*iris_info.ysize;
702
2.52k
                      size_t length;
703
2.52k
                      if (run_index >= rle_alloc_size)
704
0
                        ThrowSGIReaderException(CorruptImageError,
705
2.52k
                                                UnableToRunlengthDecodeImage,image);
706
2.52k
                      if (offset != (magick_off_t) offsets[run_index])
707
1.94k
                        {
708
1.94k
                          offset=(magick_off_t) offsets[run_index];
709
1.94k
                          if (SeekBlob(image,offset,SEEK_SET) != offset)
710
0
                            ThrowSGIReaderException(CorruptImageError,
711
1.94k
                                                    UnableToRunlengthDecodeImage, image);
712
1.94k
                        }
713
2.52k
                      length=runlength[run_index];
714
2.52k
                      if (length > max_packets_alloc_size)
715
0
                        ThrowSGIReaderException(CorruptImageError,
716
2.52k
                                                UnableToRunlengthDecodeImage,image);
717
2.52k
                      if (ReadBlob(image,length,(char *) max_packets) != length)
718
73
                        ThrowSGIReaderException(CorruptImageError,
719
2.52k
                                                UnexpectedEndOfFile, image);
720
2.45k
                      offset+=(magick_off_t) length;
721
2.45k
                      if (SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z,
722
2.45k
                                    length/bytes_per_pixel,
723
2.45k
                                    iris_info.xsize) == -1)
724
28
                        ThrowSGIReaderException(CorruptImageError,
725
2.45k
                                                UnableToRunlengthDecodeImage,image);
726
2.42k
                      p+=((size_t) iris_info.xsize*4U*bytes_per_pixel);
727
2.42k
                    }
728
191
                }
729
142
            }
730
3.44k
          else
731
3.44k
            {
732
3.44k
              p=iris_pixels;
733
5.56k
              for (y=0; y < iris_info.ysize; y++)
734
4.26k
                {
735
7.25k
                  for (z=0; z < iris_info.zsize; z++)
736
5.13k
                    {
737
5.13k
                      const size_t run_index = (size_t) y+z*iris_info.ysize;
738
5.13k
                      size_t length;
739
5.13k
                      if (run_index >= rle_alloc_size)
740
0
                        ThrowSGIReaderException(CorruptImageError,
741
5.13k
                                                UnableToRunlengthDecodeImage,image);
742
5.13k
                      if (offset != (magick_off_t) offsets[run_index])
743
3.80k
                        {
744
3.80k
                          offset=(magick_off_t) offsets[run_index];
745
3.80k
                          if (SeekBlob(image,offset,SEEK_SET) != offset)
746
0
                            ThrowSGIReaderException(CorruptImageError,
747
3.80k
                                                    UnableToRunlengthDecodeImage, image);
748
3.80k
                        }
749
5.13k
                      length=runlength[run_index];
750
5.13k
                      if (length > max_packets_alloc_size)
751
0
                        ThrowSGIReaderException(CorruptImageError,
752
5.13k
                                                UnableToRunlengthDecodeImage,image);
753
5.13k
                      if (ReadBlob(image,length, (char *) max_packets) != length)
754
62
                        ThrowSGIReaderException(CorruptImageError,
755
5.13k
                                                UnexpectedEndOfFile, image);
756
5.06k
                      offset+=length;
757
5.06k
                      if (SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z,
758
5.06k
                                    length/bytes_per_pixel,
759
5.06k
                                    iris_info.xsize) == -1)
760
2.08k
                        ThrowSGIReaderException(CorruptImageError,
761
5.06k
                                                UnableToRunlengthDecodeImage,image);
762
2.98k
                    }
763
2.12k
                  p+=((size_t) iris_info.xsize*4U*bytes_per_pixel);
764
2.12k
                  if (EOFBlob(image))
765
0
                    break;
766
2.12k
                }
767
3.44k
            }
768
1.34k
          MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength);
769
1.34k
          MagickFreeResourceLimitedMemory(unsigned char *,max_packets);
770
1.34k
          MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);
771
1.34k
        }
772
773
      /*
774
        Convert SGI raster image to pixel packets.
775
      */
776
2.73k
      if (image->storage_class == DirectClass)
777
624
        {
778
          /*
779
            Convert SGI image to DirectClass pixel packets.
780
          */
781
624
          if (bytes_per_pixel == 2U)
782
523
            {
783
19.1k
              for (y=0; y < image->rows; y++)
784
18.6k
                {
785
18.6k
                  p=iris_pixels+((size_t)image->rows-y-1)*8*image->columns;
786
18.6k
                  q=SetImagePixels(image,0,y,image->columns,1);
787
18.6k
                  if (q == (PixelPacket *) NULL)
788
0
                    break;
789
1.25M
                  for (x=0U; x < image->columns; x++)
790
1.23M
                    {
791
1.23M
                      q->red=ScaleShortToQuantum((*(p+0) << 8U) | (*(p+1)));
792
1.23M
                      q->green=ScaleShortToQuantum((*(p+2) << 8U) | (*(p+3)));
793
1.23M
                      q->blue=ScaleShortToQuantum((*(p+4) << 8U) | (*(p+5)));
794
1.23M
                      if (image->matte)
795
2.24k
                        q->opacity=(Quantum)
796
2.24k
                          (MaxRGB-ScaleShortToQuantum((*(p+6) << 8) | (*(p+7))));
797
1.23M
                      else
798
1.23M
                        q->opacity=OpaqueOpacity;
799
1.23M
                      p+=8U;
800
1.23M
                      q++;
801
1.23M
                    }
802
18.6k
                  if (!SyncImagePixels(image))
803
0
                    break;
804
18.6k
                  if (QuantumTick(y,image->rows))
805
6.27k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
806
6.27k
                                                LoadImageText,image->filename,
807
6.27k
                                                image->columns,image->rows))
808
0
                      break;
809
18.6k
                }
810
523
            }
811
101
          else
812
74.0k
            for (y=0; y < image->rows; y++)
813
73.9k
              {
814
73.9k
                p=iris_pixels+((size_t) image->rows-y-1)*4*image->columns;
815
73.9k
                q=SetImagePixels(image,0,y,image->columns,1);
816
73.9k
                if (q == (PixelPacket *) NULL)
817
0
                  break;
818
831k
                for (x=0; x < image->columns; x++)
819
757k
                  {
820
757k
                    q->red=ScaleCharToQuantum(*p);
821
757k
                    q->green=ScaleCharToQuantum(*(p+1));
822
757k
                    q->blue=ScaleCharToQuantum(*(p+2));
823
757k
                    if (image->matte)
824
667k
                      q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*(p+3)));
825
90.3k
                    else
826
90.3k
                      q->opacity=OpaqueOpacity;
827
757k
                    p+=4;
828
757k
                    q++;
829
757k
                  }
830
73.9k
                if (!SyncImagePixels(image))
831
0
                  break;
832
73.9k
                if (QuantumTick(y,image->rows))
833
7.25k
                  if (!MagickMonitorFormatted(y,image->rows,exception,
834
7.25k
                                              LoadImageText,image->filename,
835
7.25k
                                              image->columns,image->rows))
836
0
                    break;
837
73.9k
              }
838
624
        }
839
2.10k
      else
840
2.10k
        {
841
          /*
842
            Create grayscale map.
843
          */
844
2.10k
          if (!AllocateImageColormap(image,image->colors))
845
0
            ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,
846
2.10k
                                    image);
847
          /*
848
            Convert SGI image to PseudoClass pixel packets.
849
          */
850
2.10k
          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.10k
          else
876
2.10k
            {
877
39.4k
              for (y=0; y < image->rows; y++)
878
37.3k
                {
879
37.3k
                  p=iris_pixels+((size_t)image->rows-y-1)*4U*image->columns;
880
37.3k
                  q=SetImagePixels(image,0,y,image->columns,1);
881
37.3k
                  if (q == (PixelPacket *) NULL)
882
0
                    break;
883
37.3k
                  indexes=AccessMutableIndexes(image);
884
9.62M
                  for (x=0; x < image->columns; x++)
885
9.59M
                    {
886
9.59M
                      indexes[x]=(*p);
887
9.59M
                      p+=4;
888
9.59M
                      q++;
889
9.59M
                    }
890
37.3k
                  if (!SyncImagePixels(image))
891
0
                    break;
892
37.3k
                  if (QuantumTick(y,image->rows))
893
10.0k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
894
10.0k
                                                LoadImageText,image->filename,
895
10.0k
                                                image->columns,image->rows))
896
0
                      break;
897
37.3k
                }
898
2.10k
            }
899
2.10k
          if (y < image->rows)
900
0
            {
901
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
902
0
                                    "Only transferred %lu rows out of %lu",
903
0
                                    y, image->rows);
904
0
              MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
905
              /*
906
                Not sure what a proper error report is here
907
               */
908
0
              ThrowSGIReaderException(CorruptImageError,UnableToReadImageData,image);
909
0
            }
910
2.10k
          (void) SyncImage(image);
911
2.10k
        }
912
2.73k
      MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
913
2.73k
      if (EOFBlob(image))
914
0
        {
915
0
          ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,
916
0
                                  image);
917
0
          break;
918
0
        }
919
2.73k
    } while (0);
920
2.73k
  CloseBlob(image);
921
2.73k
  StopTimer(&image->timer);
922
2.73k
  return(image);
923
120k
}
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
6
{
950
6
  MagickInfo
951
6
    *entry;
952
953
6
  entry=SetMagickInfo("SGI");
954
6
  entry->decoder=(DecoderHandler) ReadSGIImage;
955
6
  entry->encoder=(EncoderHandler) WriteSGIImage;
956
6
  entry->magick=(MagickHandler) IsSGI;
957
6
  entry->description="Irix RGB image";
958
6
  entry->module="SGI";
959
6
  entry->adjoin=MagickFalse;
960
6
  entry->seekable_stream=True;
961
6
  (void) RegisterMagickInfo(entry);
962
6
}
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
371k
{
1021
371k
  short
1022
371k
    runlength;
1023
1024
371k
  register unsigned char
1025
371k
    *p,
1026
371k
    *q;
1027
1028
371k
  unsigned char
1029
371k
    *limit,
1030
371k
    *mark;
1031
1032
371k
  p=pixels;
1033
371k
  limit=p+count*4;
1034
371k
  q=packets;
1035
1.04M
  while (p < limit)
1036
676k
    {
1037
676k
      mark=p;
1038
676k
      p+=8;
1039
7.36M
      while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
1040
6.68M
        p+=4;
1041
676k
      p-=8;
1042
676k
      count=((p-mark) >> 2);
1043
1.01M
      while (count)
1044
333k
        {
1045
333k
          runlength=(short) (count > 126 ? 126 : count);
1046
333k
          count-=runlength;
1047
333k
          *q++=0x80 | runlength;
1048
7.01M
          for ( ; runlength > 0; runlength--)
1049
6.68M
            {
1050
6.68M
              *q++=(*mark);
1051
6.68M
              mark+=4;
1052
6.68M
            }
1053
333k
        }
1054
676k
      mark=p;
1055
676k
      p+=4;
1056
9.55M
      while ((p < limit) && (*p == *mark))
1057
8.88M
        p+=4;
1058
676k
      count=((p-mark) >> 2);
1059
1.41M
      while (count)
1060
737k
        {
1061
737k
          runlength=(short) (count > 126 ? 126 : count);
1062
737k
          count-=runlength;
1063
737k
          *q++=(unsigned char) runlength;
1064
737k
          *q++=(*mark);
1065
737k
        }
1066
676k
    }
1067
371k
  *q++=0;
1068
371k
  return(q-packets);
1069
371k
}
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
390
{
1083
390
  long
1084
390
    y,
1085
390
    z;
1086
1087
390
  SGIInfo
1088
390
    iris_info;
1089
1090
390
  register const PixelPacket
1091
390
    *p;
1092
1093
390
  register long
1094
390
    i,
1095
390
    x;
1096
1097
390
  register unsigned char
1098
390
    *q;
1099
1100
390
  magick_uint32_t
1101
390
    *offsets = (magick_uint32_t *) NULL,
1102
390
    *runlength = (magick_uint32_t *) NULL;
1103
1104
390
  unsigned char
1105
390
    *iris_pixels = (unsigned char *) NULL,
1106
390
    *packets = (unsigned char *) NULL,
1107
390
    *scanline = (unsigned char *) NULL;
1108
1109
390
  unsigned int
1110
390
    status;
1111
1112
390
  unsigned long
1113
390
    number_pixels;
1114
1115
  /*
1116
    Open output image file.
1117
  */
1118
390
  assert(image_info != (const ImageInfo *) NULL);
1119
390
  assert(image_info->signature == MagickSignature);
1120
390
  assert(image != (Image *) NULL);
1121
390
  assert(image->signature == MagickSignature);
1122
390
  if ((image->columns > 65535L) || (image->rows > 65535L))
1123
390
    ThrowWriterException(ImageError,WidthOrHeightExceedsLimit,image);
1124
390
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1125
390
  if (status == MagickFail)
1126
390
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
1127
390
  do
1128
390
    {
1129
390
      ImageCharacteristics
1130
390
        characteristics;
1131
1132
      /*
1133
        Ensure that image is in an RGB space.
1134
      */
1135
390
      (void) TransformColorspace(image,RGBColorspace);
1136
      /*
1137
        Analyze image to be written.
1138
      */
1139
390
      (void) GetImageCharacteristics(image,&characteristics,
1140
390
                                     (OptimizeType == image_info->type),
1141
390
                                     &image->exception);
1142
      /*
1143
        Initialize SGI raster file header.
1144
      */
1145
390
      iris_info.magic=0x01DA;
1146
390
      if (image_info->compression == NoCompression)
1147
0
        iris_info.storage=0x00;
1148
390
      else
1149
390
        iris_info.storage=0x01;
1150
390
      iris_info.bytes_per_pixel=1;  /* one byte per pixel */
1151
390
      iris_info.dimension=3;
1152
390
      iris_info.xsize=(unsigned short) image->columns;
1153
390
      iris_info.ysize=(unsigned short) image->rows;
1154
390
      if (image->matte != MagickFalse)
1155
51
        iris_info.zsize=4;
1156
339
      else
1157
339
        {
1158
339
          if ((image_info->type != TrueColorType) &&
1159
339
              (characteristics.grayscale))
1160
182
            {
1161
182
              iris_info.dimension=2;
1162
182
              iris_info.zsize=1;
1163
182
            }
1164
157
          else
1165
157
            iris_info.zsize=3;
1166
339
        }
1167
390
      iris_info.pix_min=0;
1168
390
      iris_info.pix_max=ScaleQuantumToChar(MaxRGB);
1169
1170
390
      (void) memset(iris_info.dummy1,0,sizeof(iris_info.dummy1));
1171
390
      {
1172
390
        const ImageAttribute
1173
390
          *attribute;
1174
1175
390
        (void) memset(iris_info.image_name,0,sizeof(iris_info.image_name));
1176
390
        if ((attribute=GetImageAttribute(image,"comment")))
1177
229
          (void) strlcpy(iris_info.image_name,attribute->value,sizeof(iris_info.image_name));
1178
390
      }
1179
390
      iris_info.color_map=0;
1180
390
      (void) memset(iris_info.dummy2,0,sizeof(iris_info.dummy2));
1181
1182
      /*
1183
        Write SGI header.
1184
      */
1185
390
      (void) WriteBlobMSBShort(image,iris_info.magic);
1186
390
      (void) WriteBlobByte(image,iris_info.storage);
1187
390
      (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
1188
390
      (void) WriteBlobMSBShort(image,iris_info.dimension);
1189
390
      (void) WriteBlobMSBShort(image,iris_info.xsize);
1190
390
      (void) WriteBlobMSBShort(image,iris_info.ysize);
1191
390
      (void) WriteBlobMSBShort(image,iris_info.zsize);
1192
390
      (void) WriteBlobMSBLong(image,iris_info.pix_min);
1193
390
      (void) WriteBlobMSBLong(image,iris_info.pix_max);
1194
390
      (void) WriteBlob(image,sizeof(iris_info.dummy1),
1195
390
                       (char *) iris_info.dummy1);
1196
390
      (void) WriteBlob(image,sizeof(iris_info.image_name),
1197
390
                       (char *) iris_info.image_name);
1198
390
      (void) WriteBlobMSBLong(image,iris_info.color_map);
1199
390
      (void) WriteBlob(image,sizeof(iris_info.dummy2),
1200
390
                       (char *) iris_info.dummy2);
1201
      /*
1202
        Allocate SGI pixels.
1203
      */
1204
390
      number_pixels=image->columns*image->rows;
1205
390
      iris_pixels=MagickAllocateResourceLimitedArray(unsigned char *,4,number_pixels);
1206
390
      if (iris_pixels == (unsigned char *) NULL)
1207
390
        ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,image);
1208
      /*
1209
        Convert image pixels to uncompressed SGI pixels.
1210
      */
1211
128k
      for (y=0; y < (long) image->rows; y++)
1212
127k
        {
1213
127k
          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1214
127k
          if (p == (const PixelPacket *) NULL)
1215
0
            break;
1216
127k
          q=iris_pixels+(((size_t)iris_info.ysize-1)-y)*((size_t)iris_info.xsize*4);
1217
11.7M
          for (x=0; x < (long) image->columns; x++)
1218
11.5M
            {
1219
11.5M
              *q++=ScaleQuantumToChar(p->red);
1220
11.5M
              *q++=ScaleQuantumToChar(p->green);
1221
11.5M
              *q++=ScaleQuantumToChar(p->blue);
1222
11.5M
              *q++=ScaleQuantumToChar(MaxRGB-p->opacity);
1223
11.5M
              p++;
1224
11.5M
            }
1225
127k
          if (QuantumTick(y,image->rows))
1226
21.2k
            if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1227
21.2k
                                        SaveImageText,image->filename,
1228
21.2k
                                        image->columns,image->rows))
1229
0
              break;
1230
127k
        }
1231
390
      if (image_info->compression == NoCompression)
1232
0
        {
1233
          /*
1234
            Write uncompressed SGI pixels.
1235
          */
1236
0
          scanline=MagickAllocateResourceLimitedMemory(unsigned char *,iris_info.xsize);
1237
0
          if (scanline == (unsigned char *) NULL)
1238
0
            ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,
1239
0
                                    image);
1240
0
          for (z=0; z < (int) iris_info.zsize; z++)
1241
0
            {
1242
0
              q=iris_pixels+z;
1243
0
              for (y=0; y < (long) iris_info.ysize; y++)
1244
0
                {
1245
0
                  for (x=0; x < (long) iris_info.xsize; x++)
1246
0
                    {
1247
0
                      scanline[x]=(*q);
1248
0
                      q+=4;
1249
0
                    }
1250
0
                  (void) WriteBlob(image,iris_info.xsize,(char *) scanline);
1251
0
                }
1252
0
            }
1253
0
          MagickFreeResourceLimitedMemory(unsigned char *,scanline);
1254
0
        }
1255
390
      else
1256
390
        {
1257
390
          magick_uint32_t
1258
390
            length,
1259
390
            number_packets,
1260
390
            offset;
1261
1262
          /*
1263
            Convert SGI uncompressed pixels.
1264
          */
1265
390
          offsets=MagickAllocateResourceLimitedArray(magick_uint32_t *,iris_info.ysize,
1266
390
                                      MagickArraySize(iris_info.zsize,
1267
390
                                                      sizeof(magick_uint32_t)));
1268
390
          packets=MagickAllocateResourceLimitedArray(unsigned char *,
1269
390
                                      4*(2*(size_t) iris_info.xsize+10),
1270
390
                                      image->rows);
1271
390
          runlength=MagickAllocateResourceLimitedArray(magick_uint32_t *,iris_info.ysize,
1272
390
                                        MagickArraySize(iris_info.zsize,
1273
390
                                                        sizeof(magick_uint32_t)));
1274
390
          if ((offsets == (magick_uint32_t *) NULL) ||
1275
390
              (packets == (unsigned char *) NULL) ||
1276
390
              (runlength == (magick_uint32_t *) NULL))
1277
0
            ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,
1278
390
                                    image);
1279
390
          offset=512+4*2*((size_t) iris_info.ysize*iris_info.zsize);
1280
390
          number_packets=0;
1281
390
          q=iris_pixels;
1282
128k
          for (y=0; y < (long) iris_info.ysize; y++)
1283
127k
            {
1284
499k
              for (z=0; z < (int) iris_info.zsize; z++)
1285
371k
                {
1286
371k
                  length=(magick_uint32_t)
1287
371k
                    SGIEncode(q+z,(int) iris_info.xsize,packets+number_packets);
1288
371k
                  number_packets+=length;
1289
371k
                  offsets[y+z*iris_info.ysize]=offset;
1290
371k
                  runlength[y+z*iris_info.ysize]=length;
1291
371k
                  offset+=length;
1292
371k
                }
1293
127k
              q+=((size_t)iris_info.xsize*4);
1294
127k
            }
1295
          /*
1296
            Write out line start and length tables and runlength-encoded pixels.
1297
          */
1298
371k
          for (i=0; i < (int) (iris_info.ysize*iris_info.zsize); i++)
1299
371k
            (void) WriteBlobMSBLong(image,offsets[i]);
1300
371k
          for (i=0; i < (int) (iris_info.ysize*iris_info.zsize); i++)
1301
371k
            (void) WriteBlobMSBLong(image,runlength[i]);
1302
390
          (void) WriteBlob(image,number_packets,(char *) packets);
1303
          /*
1304
            Free memory.
1305
          */
1306
390
          MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength);
1307
390
          MagickFreeResourceLimitedMemory(unsigned char *,packets);
1308
390
          MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets);
1309
390
        }
1310
390
      MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels);
1311
390
    } while (0);
1312
390
  status &= CloseBlob(image);
1313
390
  return(status);
1314
390
}