~ubuntu-branches/ubuntu/intrepid/graphicsmagick/intrepid

« back to all changes in this revision

Viewing changes to coders/sgi.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2006-05-06 16:28:08 UTC
  • Revision ID: james.westby@ubuntu.com-20060506162808-vt2ni3r5nytcszms
Tags: upstream-1.1.7
ImportĀ upstreamĀ versionĀ 1.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
% Copyright (C) 2003 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/blob.h"
 
40
#include "magick/cache.h"
 
41
#include "magick/color.h"
 
42
#include "magick/magick.h"
 
43
#include "magick/monitor.h"
 
44
#include "magick/utility.h"
 
45
 
 
46
/*
 
47
  Typedef declaractions.
 
48
*/
 
49
typedef struct _SGIInfo
 
50
{
 
51
  unsigned short
 
52
    magic;
 
53
 
 
54
  unsigned char
 
55
    storage,
 
56
    bytes_per_pixel;
 
57
 
 
58
  unsigned short
 
59
    dimension,
 
60
    columns,
 
61
    rows,
 
62
    depth;
 
63
 
 
64
  unsigned long
 
65
    minimum_value,
 
66
    maximum_value;
 
67
 
 
68
  unsigned char
 
69
    filler[492];
 
70
} SGIInfo;
 
71
 
 
72
/*
 
73
  Forward declarations.
 
74
*/
 
75
static unsigned int
 
76
  WriteSGIImage(const ImageInfo *,Image *);
 
77
/*
 
78
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
79
%                                                                             %
 
80
%                                                                             %
 
81
%                                                                             %
 
82
%   I s S G I                                                                 %
 
83
%                                                                             %
 
84
%                                                                             %
 
85
%                                                                             %
 
86
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
87
%
 
88
%  Method IsSGI returns True if the image format type, identified by the
 
89
%  magick string, is SGI.
 
90
%
 
91
%  The format of the IsSGI method is:
 
92
%
 
93
%      unsigned int IsSGI(const unsigned char *magick,const size_t length)
 
94
%
 
95
%  A description of each parameter follows:
 
96
%
 
97
%    o status:  Method IsSGI returns True if the image format type is SGI.
 
98
%
 
99
%    o magick: This string is generally the first few bytes of an image file
 
100
%      or blob.
 
101
%
 
102
%    o length: Specifies the length of the magick string.
 
103
%
 
104
%
 
105
*/
 
106
static unsigned int IsSGI(const unsigned char *magick,const size_t length)
 
107
{
 
108
  if (length < 2)
 
109
    return(False);
 
110
  if (memcmp(magick,"\001\332",2) == 0)
 
111
    return(True);
 
112
  return(False);
 
113
}
 
114
 
 
115
/*
 
116
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
117
%                                                                             %
 
118
%                                                                             %
 
119
%                                                                             %
 
120
%   R e a d S G I I m a g e                                                   %
 
121
%                                                                             %
 
122
%                                                                             %
 
123
%                                                                             %
 
124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
125
%
 
126
%  Method ReadSGIImage reads a SGI RGB image file and returns it.  It
 
127
%  allocates the memory necessary for the new Image structure and returns a
 
128
%  pointer to the new image.
 
129
%
 
130
%  The format of the ReadSGIImage method is:
 
131
%
 
132
%      Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
133
%
 
134
%  A description of each parameter follows:
 
135
%
 
136
%    o image:  Method ReadSGIImage returns a pointer to the image after
 
137
%      reading.  A null image is returned if there is a memory shortage or
 
138
%      if the image cannot be read.
 
139
%
 
140
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
141
%
 
142
%    o exception: return any errors or warnings in this structure.
 
143
%
 
144
%
 
145
*/
 
146
 
 
147
static void SGIDecode(const unsigned long bytes_per_pixel,
 
148
  unsigned char *max_packets,unsigned char *pixels)
 
149
{
 
150
  long
 
151
    count;
 
152
 
 
153
  register unsigned char
 
154
    *p,
 
155
    *q;
 
156
 
 
157
  unsigned long
 
158
    pixel;
 
159
 
 
160
  p=max_packets;
 
161
  q=pixels;
 
162
  if (bytes_per_pixel == 2)
 
163
    {
 
164
      for ( ; ; )
 
165
      {
 
166
        pixel=(*p++) << 8;
 
167
        pixel|=(*p++);
 
168
        count=(long) (pixel & 0x7f);
 
169
        if (count == 0)
 
170
          break;
 
171
        if (pixel & 0x80)
 
172
          for ( ; count != 0; count--)
 
173
          {
 
174
            *q=(*p++);
 
175
            *(q+1)=(*p++);
 
176
            q+=8;
 
177
          }
 
178
        else
 
179
          {
 
180
            pixel=(*p++) << 8;
 
181
            pixel|=(*p++);
 
182
            for ( ; count != 0; count--)
 
183
            {
 
184
              *q=(unsigned char) (pixel >> 8);
 
185
              *(q+1)=(unsigned char) pixel;
 
186
              q+=8;
 
187
            }
 
188
          }
 
189
      }
 
190
      return;
 
191
    }
 
192
  for ( ; ; )
 
193
  {
 
194
    pixel=(*p++);
 
195
    count=(long) (pixel & 0x7f);
 
196
    if (count == 0)
 
197
      break;
 
198
    if (pixel & 0x80)
 
199
      for ( ; count != 0; count--)
 
200
      {
 
201
        *q=(*p++);
 
202
        q+=4;
 
203
      }
 
204
    else
 
205
      {
 
206
        pixel=(*p++);
 
207
        for ( ; count != 0; count--)
 
208
        {
 
209
          *q=(unsigned char) pixel;
 
210
          q+=4;
 
211
        }
 
212
      }
 
213
  }
 
214
}
 
215
 
 
216
static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
217
{
 
218
  Image
 
219
    *image;
 
220
 
 
221
  long
 
222
    y,
 
223
    z;
 
224
 
 
225
  register IndexPacket
 
226
    *indexes;
 
227
 
 
228
  register long
 
229
    i,
 
230
    x;
 
231
 
 
232
  register PixelPacket
 
233
    *q;
 
234
 
 
235
  register unsigned char
 
236
    *p;
 
237
 
 
238
  SGIInfo
 
239
    iris_info;
 
240
 
 
241
  unsigned char
 
242
    *iris_pixels;
 
243
 
 
244
  unsigned int
 
245
    status;
 
246
 
 
247
  unsigned long
 
248
    bytes_per_pixel,
 
249
    number_pixels;
 
250
 
 
251
  /*
 
252
    Open image file.
 
253
  */
 
254
  assert(image_info != (const ImageInfo *) NULL);
 
255
  assert(image_info->signature == MagickSignature);
 
256
  assert(exception != (ExceptionInfo *) NULL);
 
257
  assert(exception->signature == MagickSignature);
 
258
  image=AllocateImage(image_info);
 
259
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
 
260
  if (status == False)
 
261
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
 
262
  /*
 
263
    Read SGI raster header.
 
264
  */
 
265
  iris_info.magic=ReadBlobMSBShort(image);
 
266
  do
 
267
  {
 
268
    /*
 
269
      Verify SGI identifier.
 
270
    */
 
271
    if (iris_info.magic != 0x01DA)
 
272
      ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
 
273
    iris_info.storage=ReadBlobByte(image);
 
274
    if (iris_info.storage == 0x01)
 
275
      image->compression=RLECompression;
 
276
    iris_info.bytes_per_pixel=ReadBlobByte(image);
 
277
    iris_info.dimension=ReadBlobMSBShort(image);
 
278
    iris_info.columns=ReadBlobMSBShort(image);
 
279
    iris_info.rows=ReadBlobMSBShort(image);
 
280
    iris_info.depth=ReadBlobMSBShort(image);
 
281
    image->columns=iris_info.columns;
 
282
    image->rows=iris_info.rows;
 
283
    image->depth=iris_info.depth <= 8 ? 8 : QuantumDepth;
 
284
    if (iris_info.depth < 3)
 
285
      {
 
286
        image->storage_class=PseudoClass;
 
287
        image->colors=256;
 
288
      }
 
289
    if (image_info->ping && (image_info->subrange != 0))
 
290
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
 
291
        break;
 
292
    iris_info.minimum_value=ReadBlobMSBLong(image);
 
293
    iris_info.maximum_value=ReadBlobMSBLong(image);
 
294
    (void) ReadBlob(image,(unsigned int) sizeof(iris_info.filler),
 
295
      (char *) iris_info.filler);
 
296
    /*
 
297
      Allocate SGI pixels.
 
298
    */
 
299
    bytes_per_pixel=iris_info.bytes_per_pixel;
 
300
    number_pixels=iris_info.columns*iris_info.rows;
 
301
    iris_pixels=MagickAllocateMemory(unsigned char *,
 
302
      4*bytes_per_pixel*number_pixels);
 
303
    if (iris_pixels == (unsigned char *) NULL)
 
304
      ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
 
305
    if (iris_info.storage != 0x01)
 
306
      {
 
307
        unsigned char
 
308
          *scanline;
 
309
 
 
310
        /*
 
311
          Read standard image format.
 
312
        */
 
313
        scanline=MagickAllocateMemory(unsigned char *,
 
314
          bytes_per_pixel*iris_info.columns);
 
315
        if (scanline == (unsigned char *) NULL)
 
316
          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
317
            image);
 
318
        for (z=0; z < (int) iris_info.depth; z++)
 
319
        {
 
320
          p=iris_pixels+bytes_per_pixel*z;
 
321
          for (y=0; y < (long) iris_info.rows; y++)
 
322
          {
 
323
            (void) ReadBlob(image,bytes_per_pixel*iris_info.columns,
 
324
              (char *) scanline);
 
325
            if (bytes_per_pixel == 2)
 
326
              for (x=0; x < (long) iris_info.columns; x++)
 
327
              {
 
328
                *p=scanline[2*x];
 
329
                *(p+1)=scanline[2*x+1];
 
330
                p+=8;
 
331
              }
 
332
            else
 
333
              for (x=0; x < (long) iris_info.columns; x++)
 
334
              {
 
335
                *p=scanline[x];
 
336
                p+=4;
 
337
              }
 
338
          }
 
339
        }
 
340
        MagickFreeMemory(scanline);
 
341
      }
 
342
    else
 
343
      {
 
344
        unsigned char
 
345
          *max_packets;
 
346
 
 
347
        unsigned int
 
348
          data_order;
 
349
 
 
350
        unsigned long
 
351
          offset,
 
352
          *offsets,
 
353
          *runlength;
 
354
 
 
355
        /*
 
356
          Read runlength-encoded image format.
 
357
        */
 
358
        offsets=MagickAllocateMemory(unsigned long *,iris_info.rows*
 
359
          iris_info.depth*sizeof(unsigned long));
 
360
        max_packets=MagickAllocateMemory(unsigned char *,4*iris_info.columns+10);
 
361
        runlength=MagickAllocateMemory(unsigned long *,iris_info.rows*
 
362
          iris_info.depth*sizeof(unsigned long));
 
363
        if ((offsets == (unsigned long *) NULL) ||
 
364
            (max_packets == (unsigned char *) NULL) ||
 
365
            (runlength == (unsigned long *) NULL))
 
366
          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
367
            image);
 
368
        for (i=0; i < (int) (iris_info.rows*iris_info.depth); i++)
 
369
          offsets[i]=ReadBlobMSBLong(image);
 
370
        for (i=0; i < (int) (iris_info.rows*iris_info.depth); i++)
 
371
          runlength[i]=ReadBlobMSBLong(image);
 
372
        /*
 
373
          Check data order.
 
374
        */
 
375
        offset=0;
 
376
        data_order=0;
 
377
        for (y=0; ((y < (long) iris_info.rows) && !data_order); y++)
 
378
          for (z=0; ((z < (int) iris_info.depth) && !data_order); z++)
 
379
          {
 
380
            if (offsets[y+z*iris_info.rows] < offset)
 
381
              data_order=1;
 
382
            offset=offsets[y+z*iris_info.rows];
 
383
          }
 
384
        offset=512+4*bytes_per_pixel*2*(iris_info.rows*iris_info.depth);
 
385
        if (data_order == 1)
 
386
          {
 
387
            for (z=0; z < (int) iris_info.depth; z++)
 
388
            {
 
389
              p=iris_pixels;
 
390
              for (y=0; y < (long) iris_info.rows; y++)
 
391
              {
 
392
                if (offset != offsets[y+z*iris_info.rows])
 
393
                  {
 
394
                    offset=offsets[y+z*iris_info.rows];
 
395
                    (void) SeekBlob(image,(long) offset,SEEK_SET);
 
396
                  }
 
397
                (void) ReadBlob(image,runlength[y+z*iris_info.rows],
 
398
                  (char *) max_packets);
 
399
                offset+=runlength[y+z*iris_info.rows];
 
400
                SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z);
 
401
                p+=(iris_info.columns*4*bytes_per_pixel);
 
402
              }
 
403
            }
 
404
          }
 
405
        else
 
406
          {
 
407
            p=iris_pixels;
 
408
            for (y=0; y < (long) iris_info.rows; y++)
 
409
            {
 
410
              for (z=0; z < (int) iris_info.depth; z++)
 
411
              {
 
412
                if (offset != offsets[y+z*iris_info.rows])
 
413
                  {
 
414
                    offset=offsets[y+z*iris_info.rows];
 
415
                    (void) SeekBlob(image,(long) offset,SEEK_SET);
 
416
                  }
 
417
                (void) ReadBlob(image,runlength[y+z*iris_info.rows],
 
418
                  (char *) max_packets);
 
419
                offset+=runlength[y+z*iris_info.rows];
 
420
                SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z);
 
421
              }
 
422
              p+=(iris_info.columns*4*bytes_per_pixel);
 
423
            }
 
424
          }
 
425
        MagickFreeMemory(runlength);
 
426
        MagickFreeMemory(max_packets);
 
427
        MagickFreeMemory(offsets);
 
428
      }
 
429
    /*
 
430
      Initialize image structure.
 
431
    */
 
432
    image->matte=iris_info.depth == 4;
 
433
    image->columns=iris_info.columns;
 
434
    image->rows=iris_info.rows;
 
435
    /*
 
436
      Convert SGI raster image to pixel packets.
 
437
    */
 
438
    if (image->storage_class == DirectClass)
 
439
      {
 
440
        /*
 
441
          Convert SGI image to DirectClass pixel packets.
 
442
        */
 
443
        if (bytes_per_pixel == 2)
 
444
          {
 
445
            for (y=0; y < (long) image->rows; y++)
 
446
            {
 
447
              p=iris_pixels+(image->rows-y-1)*8*image->columns;
 
448
              q=SetImagePixels(image,0,y,image->columns,1);
 
449
              if (q == (PixelPacket *) NULL)
 
450
                break;
 
451
              for (x=0; x < (long) image->columns; x++)
 
452
              {
 
453
                q->red=ScaleShortToQuantum((*(p+0) << 8) | (*(p+1)));
 
454
                q->green=ScaleShortToQuantum((*(p+2) << 8) | (*(p+3)));
 
455
                q->blue=ScaleShortToQuantum((*(p+4) << 8) | (*(p+5)));
 
456
                q->opacity=(Quantum)
 
457
                  (MaxRGB-ScaleShortToQuantum((*(p+6) << 8) | (*(p+7))));
 
458
                p+=8;
 
459
                q++;
 
460
              }
 
461
              if (!SyncImagePixels(image))
 
462
                break;
 
463
              if (image->previous == (Image *) NULL)
 
464
                if (QuantumTick(y,image->rows))
 
465
                  if (!MagickMonitor(LoadImageText,y,image->rows,exception))
 
466
                    break;
 
467
            }
 
468
          }
 
469
        else
 
470
          for (y=0; y < (long) image->rows; y++)
 
471
          {
 
472
            p=iris_pixels+(image->rows-y-1)*4*image->columns;
 
473
            q=SetImagePixels(image,0,y,image->columns,1);
 
474
            if (q == (PixelPacket *) NULL)
 
475
              break;
 
476
            for (x=0; x < (long) image->columns; x++)
 
477
            {
 
478
              q->red=ScaleCharToQuantum(*p);
 
479
              q->green=ScaleCharToQuantum(*(p+1));
 
480
              q->blue=ScaleCharToQuantum(*(p+2));
 
481
              q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*(p+3)));
 
482
              p+=4;
 
483
              q++;
 
484
            }
 
485
            if (!SyncImagePixels(image))
 
486
              break;
 
487
            if (image->previous == (Image *) NULL)
 
488
              if (QuantumTick(y,image->rows))
 
489
                if (!MagickMonitor(LoadImageText,y,image->rows,exception))
 
490
                  break;
 
491
          }
 
492
      }
 
493
    else
 
494
      {
 
495
        /*
 
496
          Create grayscale map.
 
497
        */
 
498
        if (!AllocateImageColormap(image,image->colors))
 
499
          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
500
            image);
 
501
        /*
 
502
          Convert SGI image to PseudoClass pixel packets.
 
503
        */
 
504
        if (bytes_per_pixel == 2)
 
505
          {
 
506
            for (y=0; y < (long) image->rows; y++)
 
507
            {
 
508
              p=iris_pixels+(image->rows-y-1)*8*image->columns;
 
509
              q=SetImagePixels(image,0,y,image->columns,1);
 
510
              if (q == (PixelPacket *) NULL)
 
511
                break;
 
512
              indexes=GetIndexes(image);
 
513
              for (x=0; x < (long) image->columns; x++)
 
514
              {
 
515
                indexes[x]=(*p << 8);
 
516
                indexes[x]|=(*(p+1));
 
517
                p+=8;
 
518
                q++;
 
519
              }
 
520
              if (!SyncImagePixels(image))
 
521
                break;
 
522
              if (image->previous == (Image *) NULL)
 
523
                if (QuantumTick(y,image->rows))
 
524
                  if (!MagickMonitor(LoadImageText,y,image->rows,exception))
 
525
                    break;
 
526
            }
 
527
          }
 
528
        else
 
529
          for (y=0; y < (long) image->rows; y++)
 
530
          {
 
531
            p=iris_pixels+(image->rows-y-1)*4*image->columns;
 
532
            q=SetImagePixels(image,0,y,image->columns,1);
 
533
            if (q == (PixelPacket *) NULL)
 
534
              break;
 
535
            indexes=GetIndexes(image);
 
536
            for (x=0; x < (long) image->columns; x++)
 
537
            {
 
538
              indexes[x]=(*p);
 
539
              p+=4;
 
540
              q++;
 
541
            }
 
542
            if (!SyncImagePixels(image))
 
543
              break;
 
544
            if (image->previous == (Image *) NULL)
 
545
              if (QuantumTick(y,image->rows))
 
546
                if (!MagickMonitor(LoadImageText,y,image->rows,exception))
 
547
                  break;
 
548
          }
 
549
        SyncImage(image);
 
550
      }
 
551
    MagickFreeMemory(iris_pixels);
 
552
    if (EOFBlob(image))
 
553
      {
 
554
        ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
 
555
          image->filename);
 
556
        break;
 
557
      }
 
558
    /*
 
559
      Proceed to next image.
 
560
    */
 
561
    if (image_info->subrange != 0)
 
562
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
 
563
        break;
 
564
    iris_info.magic=ReadBlobMSBShort(image);
 
565
    if (iris_info.magic == 0x01DA)
 
566
      {
 
567
        /*
 
568
          Allocate next image structure.
 
569
        */
 
570
        AllocateNextImage(image_info,image);
 
571
        if (image->next == (Image *) NULL)
 
572
          {
 
573
            DestroyImageList(image);
 
574
            return((Image *) NULL);
 
575
          }
 
576
        image=SyncNextImageInList(image);
 
577
        if (!MagickMonitor(LoadImagesText,TellBlob(image),GetBlobSize(image),exception))
 
578
          break;
 
579
      }
 
580
  } while (iris_info.magic == 0x01DA);
 
581
  while (image->previous != (Image *) NULL)
 
582
    image=image->previous;
 
583
  CloseBlob(image);
 
584
  return(image);
 
585
}
 
586
 
 
587
/*
 
588
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
589
%                                                                             %
 
590
%                                                                             %
 
591
%                                                                             %
 
592
%   R e g i s t e r S G I I m a g e                                           %
 
593
%                                                                             %
 
594
%                                                                             %
 
595
%                                                                             %
 
596
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
597
%
 
598
%  Method RegisterSGIImage adds attributes for the SGI image format to
 
599
%  the list of supported formats.  The attributes include the image format
 
600
%  tag, a method to read and/or write the format, whether the format
 
601
%  supports the saving of more than one frame to the same file or blob,
 
602
%  whether the format supports native in-memory I/O, and a brief
 
603
%  description of the format.
 
604
%
 
605
%  The format of the RegisterSGIImage method is:
 
606
%
 
607
%      RegisterSGIImage(void)
 
608
%
 
609
*/
 
610
ModuleExport void RegisterSGIImage(void)
 
611
{
 
612
  MagickInfo
 
613
    *entry;
 
614
 
 
615
  entry=SetMagickInfo("SGI");
 
616
  entry->decoder=(DecoderHandler) ReadSGIImage;
 
617
  entry->encoder=(EncoderHandler) WriteSGIImage;
 
618
  entry->magick=(MagickHandler) IsSGI;
 
619
  entry->description=AcquireString("Irix RGB image");
 
620
  entry->module=AcquireString("SGI");
 
621
  entry->seekable_stream=True;
 
622
  (void) RegisterMagickInfo(entry);
 
623
}
 
624
 
 
625
/*
 
626
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
627
%                                                                             %
 
628
%                                                                             %
 
629
%                                                                             %
 
630
%   U n r e g i s t e r S G I I m a g e                                       %
 
631
%                                                                             %
 
632
%                                                                             %
 
633
%                                                                             %
 
634
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
635
%
 
636
%  Method UnregisterSGIImage removes format registrations made by the
 
637
%  SGI module from the list of supported formats.
 
638
%
 
639
%  The format of the UnregisterSGIImage method is:
 
640
%
 
641
%      UnregisterSGIImage(void)
 
642
%
 
643
*/
 
644
ModuleExport void UnregisterSGIImage(void)
 
645
{
 
646
  (void) UnregisterMagickInfo("SGI");
 
647
}
 
648
 
 
649
/*
 
650
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
651
%                                                                             %
 
652
%                                                                             %
 
653
%                                                                             %
 
654
%   W r i t e S G I I m a g e                                                 %
 
655
%                                                                             %
 
656
%                                                                             %
 
657
%                                                                             %
 
658
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
659
%
 
660
%  Method WriteSGIImage writes an image in SGI RGB encoded image format.
 
661
%
 
662
%  The format of the WriteSGIImage method is:
 
663
%
 
664
%      unsigned int WriteSGIImage(const ImageInfo *image_info,Image *image)
 
665
%
 
666
%  A description of each parameter follows.
 
667
%
 
668
%    o status: Method WriteSGIImage return True if the image is written.
 
669
%      False is returned is there is a memory shortage or if the image file
 
670
%      fails to write.
 
671
%
 
672
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
673
%
 
674
%    o image:  A pointer to an Image structure.
 
675
%
 
676
%
 
677
*/
 
678
 
 
679
static size_t SGIEncode(unsigned char *pixels,size_t count,
 
680
  unsigned char *packets)
 
681
{
 
682
  short
 
683
    runlength;
 
684
 
 
685
  register unsigned char
 
686
    *p,
 
687
    *q;
 
688
 
 
689
  unsigned char
 
690
    *limit,
 
691
    *mark;
 
692
 
 
693
  p=pixels;
 
694
  limit=p+count*4;
 
695
  q=packets;
 
696
  while (p < limit)
 
697
  {
 
698
    mark=p;
 
699
    p+=8;
 
700
    while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
 
701
      p+=4;
 
702
    p-=8;
 
703
    count=((p-mark) >> 2);
 
704
    while (count)
 
705
    {
 
706
      runlength=(short) (count > 126 ? 126 : count);
 
707
      count-=runlength;
 
708
      *q++=0x80 | runlength;
 
709
      for ( ; runlength > 0; runlength--)
 
710
      {
 
711
        *q++=(*mark);
 
712
        mark+=4;
 
713
      }
 
714
    }
 
715
    mark=p;
 
716
    p+=4;
 
717
    while ((p < limit) && (*p == *mark))
 
718
      p+=4;
 
719
    count=((p-mark) >> 2);
 
720
    while (count)
 
721
    {
 
722
      runlength=(short) (count > 126 ? 126 : count);
 
723
      count-=runlength;
 
724
      *q++=(unsigned char) runlength;
 
725
      *q++=(*mark);
 
726
    }
 
727
  }
 
728
  *q++=0;
 
729
  return(q-packets);
 
730
}
 
731
 
 
732
static unsigned int WriteSGIImage(const ImageInfo *image_info,Image *image)
 
733
{
 
734
  long
 
735
    y,
 
736
    z;
 
737
 
 
738
  SGIInfo
 
739
    iris_info;
 
740
 
 
741
  register const PixelPacket
 
742
    *p;
 
743
 
 
744
  register long
 
745
    i,
 
746
    x;
 
747
 
 
748
  register unsigned char
 
749
    *q;
 
750
 
 
751
  unsigned char
 
752
    *iris_pixels,
 
753
    *packets;
 
754
 
 
755
  unsigned int
 
756
    status;
 
757
 
 
758
  unsigned long
 
759
    number_pixels,
 
760
    scene;
 
761
 
 
762
  /*
 
763
    Open output image file.
 
764
  */
 
765
  assert(image_info != (const ImageInfo *) NULL);
 
766
  assert(image_info->signature == MagickSignature);
 
767
  assert(image != (Image *) NULL);
 
768
  assert(image->signature == MagickSignature);
 
769
  if ((image->columns > 65535L) || (image->rows > 65535L))
 
770
    ThrowWriterException(ImageError,WidthOrHeightExceedsLimit,image);
 
771
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
 
772
  if (status == False)
 
773
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
 
774
  scene=0;
 
775
  do
 
776
  {
 
777
    /*
 
778
      Initialize SGI raster file header.
 
779
    */
 
780
    TransformColorspace(image,RGBColorspace);
 
781
    iris_info.magic=0x01DA;
 
782
    if (image_info->compression == NoCompression)
 
783
      iris_info.storage=0x00;
 
784
    else
 
785
      iris_info.storage=0x01;
 
786
    iris_info.bytes_per_pixel=1;  /* one byte per pixel */
 
787
    iris_info.dimension=3;
 
788
    iris_info.columns=(unsigned short) image->columns;
 
789
    iris_info.rows=(unsigned short) image->rows;
 
790
    if (image->matte != False)
 
791
      iris_info.depth=4;
 
792
    else
 
793
      {
 
794
        if ((image_info->type != TrueColorType) &&
 
795
            (IsGrayImage(image,&image->exception) != False))
 
796
          {
 
797
            iris_info.dimension=2;
 
798
            iris_info.depth=1;
 
799
          }
 
800
        else
 
801
          iris_info.depth=3;
 
802
      }
 
803
    iris_info.minimum_value=0;
 
804
    iris_info.maximum_value=ScaleQuantumToChar(MaxRGB);
 
805
    for (i=0; i < (int) sizeof(iris_info.filler); i++)
 
806
      iris_info.filler[i]=0;
 
807
    /*
 
808
      Write SGI header.
 
809
    */
 
810
    (void) WriteBlobMSBShort(image,iris_info.magic);
 
811
    (void) WriteBlobByte(image,iris_info.storage);
 
812
    (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
 
813
    (void) WriteBlobMSBShort(image,iris_info.dimension);
 
814
    (void) WriteBlobMSBShort(image,iris_info.columns);
 
815
    (void) WriteBlobMSBShort(image,iris_info.rows);
 
816
    (void) WriteBlobMSBShort(image,iris_info.depth);
 
817
    (void) WriteBlobMSBLong(image,iris_info.minimum_value);
 
818
    (void) WriteBlobMSBLong(image,iris_info.maximum_value);
 
819
    (void) WriteBlob(image,sizeof(iris_info.filler),
 
820
      (char *) iris_info.filler);
 
821
    /*
 
822
      Allocate SGI pixels.
 
823
    */
 
824
    number_pixels=image->columns*image->rows;
 
825
    iris_pixels=MagickAllocateMemory(unsigned char *,4*number_pixels);
 
826
    if (iris_pixels == (unsigned char *) NULL)
 
827
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
 
828
    /*
 
829
      Convert image pixels to uncompressed SGI pixels.
 
830
    */
 
831
    for (y=0; y < (long) image->rows; y++)
 
832
    {
 
833
      p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
 
834
      if (p == (const PixelPacket *) NULL)
 
835
        break;
 
836
      q=iris_pixels+((iris_info.rows-1)-y)*(iris_info.columns*4);
 
837
      for (x=0; x < (long) image->columns; x++)
 
838
      {
 
839
        *q++=ScaleQuantumToChar(p->red);
 
840
        *q++=ScaleQuantumToChar(p->green);
 
841
        *q++=ScaleQuantumToChar(p->blue);
 
842
        *q++=ScaleQuantumToChar(MaxRGB-p->opacity);
 
843
        p++;
 
844
      }
 
845
      if (image->previous == (Image *) NULL)
 
846
        if (QuantumTick(y,image->rows))
 
847
          if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
 
848
            break;
 
849
    }
 
850
    if (image_info->compression == NoCompression)
 
851
      {
 
852
        unsigned char
 
853
          *scanline;
 
854
 
 
855
        /*
 
856
          Write uncompressed SGI pixels.
 
857
        */
 
858
        scanline=MagickAllocateMemory(unsigned char *,iris_info.columns);
 
859
        if (scanline == (unsigned char *) NULL)
 
860
          ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
 
861
            image);
 
862
        for (z=0; z < (int) iris_info.depth; z++)
 
863
        {
 
864
          q=iris_pixels+z;
 
865
          for (y=0; y < (long) iris_info.rows; y++)
 
866
          {
 
867
            for (x=0; x < (long) iris_info.columns; x++)
 
868
            {
 
869
              scanline[x]=(*q);
 
870
              q+=4;
 
871
            }
 
872
            (void) WriteBlob(image,iris_info.columns,(char *) scanline);
 
873
          }
 
874
        }
 
875
        MagickFreeMemory(scanline);
 
876
      }
 
877
    else
 
878
      {
 
879
        unsigned long
 
880
          length,
 
881
          number_packets,
 
882
          offset,
 
883
          *offsets,
 
884
          *runlength;
 
885
 
 
886
        /*
 
887
          Convert SGI uncompressed pixels.
 
888
        */
 
889
        offsets=MagickAllocateMemory(unsigned long *,iris_info.rows*
 
890
          iris_info.depth*sizeof(unsigned long));
 
891
        packets=MagickAllocateMemory(unsigned char *,
 
892
          4*(2*iris_info.columns+10)*image->rows);
 
893
        runlength=MagickAllocateMemory(unsigned long *,iris_info.rows*
 
894
          iris_info.depth*sizeof(unsigned long));
 
895
        if ((offsets == (unsigned long *) NULL) ||
 
896
            (packets == (unsigned char *) NULL) ||
 
897
            (runlength == (unsigned long *) NULL))
 
898
          ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
 
899
            image);
 
900
        offset=512+4*2*(iris_info.rows*iris_info.depth);
 
901
        number_packets=0;
 
902
        q=iris_pixels;
 
903
        for (y=0; y < (long) iris_info.rows; y++)
 
904
        {
 
905
          for (z=0; z < (int) iris_info.depth; z++)
 
906
          {
 
907
            length=
 
908
              SGIEncode(q+z,(int) iris_info.columns,packets+number_packets);
 
909
            number_packets+=length;
 
910
            offsets[y+z*iris_info.rows]=offset;
 
911
            runlength[y+z*iris_info.rows]=length;
 
912
            offset+=length;
 
913
          }
 
914
          q+=(iris_info.columns*4);
 
915
        }
 
916
        /*
 
917
          Write out line start and length tables and runlength-encoded pixels.
 
918
        */
 
919
        for (i=0; i < (int) (iris_info.rows*iris_info.depth); i++)
 
920
          (void) WriteBlobMSBLong(image,offsets[i]);
 
921
        for (i=0; i < (int) (iris_info.rows*iris_info.depth); i++)
 
922
          (void) WriteBlobMSBLong(image,runlength[i]);
 
923
        (void) WriteBlob(image,number_packets,(char *) packets);
 
924
        /*
 
925
          Free memory.
 
926
        */
 
927
        MagickFreeMemory(runlength);
 
928
        MagickFreeMemory(packets);
 
929
        MagickFreeMemory(offsets);
 
930
      }
 
931
    MagickFreeMemory(iris_pixels);
 
932
    if (image->next == (Image *) NULL)
 
933
      break;
 
934
    image=SyncNextImageInList(image);
 
935
    if (!MagickMonitor(SaveImagesText,scene++,GetImageListLength(image),&image->exception))
 
936
      break;
 
937
  } while (image_info->adjoin);
 
938
  if (image_info->adjoin)
 
939
    while (image->previous != (Image *) NULL)
 
940
      image=image->previous;
 
941
  CloseBlob(image);
 
942
  return(True);
 
943
}