2
% Copyright (C) 2003 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
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.
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21
% Read/Write Irix RGB Image Format. %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
47
Typedef declaractions.
49
typedef struct _SGIInfo
76
WriteSGIImage(const ImageInfo *,Image *);
78
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88
% Method IsSGI returns True if the image format type, identified by the
89
% magick string, is SGI.
91
% The format of the IsSGI method is:
93
% unsigned int IsSGI(const unsigned char *magick,const size_t length)
95
% A description of each parameter follows:
97
% o status: Method IsSGI returns True if the image format type is SGI.
99
% o magick: This string is generally the first few bytes of an image file
102
% o length: Specifies the length of the magick string.
106
static unsigned int IsSGI(const unsigned char *magick,const size_t length)
110
if (memcmp(magick,"\001\332",2) == 0)
116
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120
% R e a d S G I I m a g e %
124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
130
% The format of the ReadSGIImage method is:
132
% Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
134
% A description of each parameter follows:
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.
140
% o image_info: Specifies a pointer to a ImageInfo structure.
142
% o exception: return any errors or warnings in this structure.
147
static void SGIDecode(const unsigned long bytes_per_pixel,
148
unsigned char *max_packets,unsigned char *pixels)
153
register unsigned char
162
if (bytes_per_pixel == 2)
168
count=(long) (pixel & 0x7f);
172
for ( ; count != 0; count--)
182
for ( ; count != 0; count--)
184
*q=(unsigned char) (pixel >> 8);
185
*(q+1)=(unsigned char) pixel;
195
count=(long) (pixel & 0x7f);
199
for ( ; count != 0; count--)
207
for ( ; count != 0; count--)
209
*q=(unsigned char) pixel;
216
static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
235
register unsigned char
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);
261
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
263
Read SGI raster header.
265
iris_info.magic=ReadBlobMSBShort(image);
269
Verify SGI identifier.
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)
286
image->storage_class=PseudoClass;
289
if (image_info->ping && (image_info->subrange != 0))
290
if (image->scene >= (image_info->subimage+image_info->subrange-1))
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);
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)
311
Read standard image format.
313
scanline=MagickAllocateMemory(unsigned char *,
314
bytes_per_pixel*iris_info.columns);
315
if (scanline == (unsigned char *) NULL)
316
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
318
for (z=0; z < (int) iris_info.depth; z++)
320
p=iris_pixels+bytes_per_pixel*z;
321
for (y=0; y < (long) iris_info.rows; y++)
323
(void) ReadBlob(image,bytes_per_pixel*iris_info.columns,
325
if (bytes_per_pixel == 2)
326
for (x=0; x < (long) iris_info.columns; x++)
329
*(p+1)=scanline[2*x+1];
333
for (x=0; x < (long) iris_info.columns; x++)
340
MagickFreeMemory(scanline);
356
Read runlength-encoded image format.
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,
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);
377
for (y=0; ((y < (long) iris_info.rows) && !data_order); y++)
378
for (z=0; ((z < (int) iris_info.depth) && !data_order); z++)
380
if (offsets[y+z*iris_info.rows] < offset)
382
offset=offsets[y+z*iris_info.rows];
384
offset=512+4*bytes_per_pixel*2*(iris_info.rows*iris_info.depth);
387
for (z=0; z < (int) iris_info.depth; z++)
390
for (y=0; y < (long) iris_info.rows; y++)
392
if (offset != offsets[y+z*iris_info.rows])
394
offset=offsets[y+z*iris_info.rows];
395
(void) SeekBlob(image,(long) offset,SEEK_SET);
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);
408
for (y=0; y < (long) iris_info.rows; y++)
410
for (z=0; z < (int) iris_info.depth; z++)
412
if (offset != offsets[y+z*iris_info.rows])
414
offset=offsets[y+z*iris_info.rows];
415
(void) SeekBlob(image,(long) offset,SEEK_SET);
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);
422
p+=(iris_info.columns*4*bytes_per_pixel);
425
MagickFreeMemory(runlength);
426
MagickFreeMemory(max_packets);
427
MagickFreeMemory(offsets);
430
Initialize image structure.
432
image->matte=iris_info.depth == 4;
433
image->columns=iris_info.columns;
434
image->rows=iris_info.rows;
436
Convert SGI raster image to pixel packets.
438
if (image->storage_class == DirectClass)
441
Convert SGI image to DirectClass pixel packets.
443
if (bytes_per_pixel == 2)
445
for (y=0; y < (long) image->rows; y++)
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)
451
for (x=0; x < (long) image->columns; x++)
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)));
457
(MaxRGB-ScaleShortToQuantum((*(p+6) << 8) | (*(p+7))));
461
if (!SyncImagePixels(image))
463
if (image->previous == (Image *) NULL)
464
if (QuantumTick(y,image->rows))
465
if (!MagickMonitor(LoadImageText,y,image->rows,exception))
470
for (y=0; y < (long) image->rows; y++)
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)
476
for (x=0; x < (long) image->columns; x++)
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)));
485
if (!SyncImagePixels(image))
487
if (image->previous == (Image *) NULL)
488
if (QuantumTick(y,image->rows))
489
if (!MagickMonitor(LoadImageText,y,image->rows,exception))
496
Create grayscale map.
498
if (!AllocateImageColormap(image,image->colors))
499
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
502
Convert SGI image to PseudoClass pixel packets.
504
if (bytes_per_pixel == 2)
506
for (y=0; y < (long) image->rows; y++)
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)
512
indexes=GetIndexes(image);
513
for (x=0; x < (long) image->columns; x++)
515
indexes[x]=(*p << 8);
516
indexes[x]|=(*(p+1));
520
if (!SyncImagePixels(image))
522
if (image->previous == (Image *) NULL)
523
if (QuantumTick(y,image->rows))
524
if (!MagickMonitor(LoadImageText,y,image->rows,exception))
529
for (y=0; y < (long) image->rows; y++)
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)
535
indexes=GetIndexes(image);
536
for (x=0; x < (long) image->columns; x++)
542
if (!SyncImagePixels(image))
544
if (image->previous == (Image *) NULL)
545
if (QuantumTick(y,image->rows))
546
if (!MagickMonitor(LoadImageText,y,image->rows,exception))
551
MagickFreeMemory(iris_pixels);
554
ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
559
Proceed to next image.
561
if (image_info->subrange != 0)
562
if (image->scene >= (image_info->subimage+image_info->subrange-1))
564
iris_info.magic=ReadBlobMSBShort(image);
565
if (iris_info.magic == 0x01DA)
568
Allocate next image structure.
570
AllocateNextImage(image_info,image);
571
if (image->next == (Image *) NULL)
573
DestroyImageList(image);
574
return((Image *) NULL);
576
image=SyncNextImageInList(image);
577
if (!MagickMonitor(LoadImagesText,TellBlob(image),GetBlobSize(image),exception))
580
} while (iris_info.magic == 0x01DA);
581
while (image->previous != (Image *) NULL)
582
image=image->previous;
588
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592
% R e g i s t e r S G I I m a g e %
596
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
605
% The format of the RegisterSGIImage method is:
607
% RegisterSGIImage(void)
610
ModuleExport void RegisterSGIImage(void)
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);
626
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630
% U n r e g i s t e r S G I I m a g e %
634
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636
% Method UnregisterSGIImage removes format registrations made by the
637
% SGI module from the list of supported formats.
639
% The format of the UnregisterSGIImage method is:
641
% UnregisterSGIImage(void)
644
ModuleExport void UnregisterSGIImage(void)
646
(void) UnregisterMagickInfo("SGI");
650
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654
% W r i t e S G I I m a g e %
658
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
660
% Method WriteSGIImage writes an image in SGI RGB encoded image format.
662
% The format of the WriteSGIImage method is:
664
% unsigned int WriteSGIImage(const ImageInfo *image_info,Image *image)
666
% A description of each parameter follows.
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
672
% o image_info: Specifies a pointer to a ImageInfo structure.
674
% o image: A pointer to an Image structure.
679
static size_t SGIEncode(unsigned char *pixels,size_t count,
680
unsigned char *packets)
685
register unsigned char
700
while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
703
count=((p-mark) >> 2);
706
runlength=(short) (count > 126 ? 126 : count);
708
*q++=0x80 | runlength;
709
for ( ; runlength > 0; runlength--)
717
while ((p < limit) && (*p == *mark))
719
count=((p-mark) >> 2);
722
runlength=(short) (count > 126 ? 126 : count);
724
*q++=(unsigned char) runlength;
732
static unsigned int WriteSGIImage(const ImageInfo *image_info,Image *image)
741
register const PixelPacket
748
register unsigned char
763
Open output image file.
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);
773
ThrowWriterException(FileOpenError,UnableToOpenFile,image);
778
Initialize SGI raster file header.
780
TransformColorspace(image,RGBColorspace);
781
iris_info.magic=0x01DA;
782
if (image_info->compression == NoCompression)
783
iris_info.storage=0x00;
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)
794
if ((image_info->type != TrueColorType) &&
795
(IsGrayImage(image,&image->exception) != False))
797
iris_info.dimension=2;
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;
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);
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);
829
Convert image pixels to uncompressed SGI pixels.
831
for (y=0; y < (long) image->rows; y++)
833
p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
834
if (p == (const PixelPacket *) NULL)
836
q=iris_pixels+((iris_info.rows-1)-y)*(iris_info.columns*4);
837
for (x=0; x < (long) image->columns; x++)
839
*q++=ScaleQuantumToChar(p->red);
840
*q++=ScaleQuantumToChar(p->green);
841
*q++=ScaleQuantumToChar(p->blue);
842
*q++=ScaleQuantumToChar(MaxRGB-p->opacity);
845
if (image->previous == (Image *) NULL)
846
if (QuantumTick(y,image->rows))
847
if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
850
if (image_info->compression == NoCompression)
856
Write uncompressed SGI pixels.
858
scanline=MagickAllocateMemory(unsigned char *,iris_info.columns);
859
if (scanline == (unsigned char *) NULL)
860
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
862
for (z=0; z < (int) iris_info.depth; z++)
865
for (y=0; y < (long) iris_info.rows; y++)
867
for (x=0; x < (long) iris_info.columns; x++)
872
(void) WriteBlob(image,iris_info.columns,(char *) scanline);
875
MagickFreeMemory(scanline);
887
Convert SGI uncompressed pixels.
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,
900
offset=512+4*2*(iris_info.rows*iris_info.depth);
903
for (y=0; y < (long) iris_info.rows; y++)
905
for (z=0; z < (int) iris_info.depth; z++)
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;
914
q+=(iris_info.columns*4);
917
Write out line start and length tables and runlength-encoded pixels.
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);
927
MagickFreeMemory(runlength);
928
MagickFreeMemory(packets);
929
MagickFreeMemory(offsets);
931
MagickFreeMemory(iris_pixels);
932
if (image->next == (Image *) NULL)
934
image=SyncNextImageInList(image);
935
if (!MagickMonitor(SaveImagesText,scene++,GetImageListLength(image),&image->exception))
937
} while (image_info->adjoin);
938
if (image_info->adjoin)
939
while (image->previous != (Image *) NULL)
940
image=image->previous;