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 Sun Rasterfile 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"
50
WriteSUNImage(const ImageInfo *,Image *);
53
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63
% Method IsSUN returns True if the image format type, identified by the
64
% magick string, is SUN.
66
% The format of the IsSUN method is:
68
% unsigned int IsSUN(const unsigned char *magick,const size_t length)
70
% A description of each parameter follows:
72
% o status: Method IsSUN returns True if the image format type is SUN.
74
% o magick: This string is generally the first few bytes of an image file
77
% o length: Specifies the length of the magick string.
81
static unsigned int IsSUN(const unsigned char *magick,const size_t length)
85
if (memcmp(magick,"\131\246\152\225",4) == 0)
91
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95
% D e c o d e I m a g e %
99
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101
% Method DecodeImage unpacks the packed image pixels into
102
% runlength-encoded pixel packets.
104
% The format of the DecodeImage method is:
106
% unsigned int DecodeImage(const unsigned char *compressed_pixels,
107
% const size_t length,unsigned char *pixels)
109
% A description of each parameter follows:
111
% o status: Method DecodeImage returns True if all the pixels are
112
% uncompressed without error, otherwise False.
114
% o compressed_pixels: The address of a byte (8 bits) array of compressed
117
% o length: An integer value that is the total number of bytes of the
118
% source image (as just read by ReadBlob)
120
% o pixels: The address of a byte (8 bits) array of pixel data created by
121
% the uncompression process. The number of bytes in this array
122
% must be at least equal to the number columns times the number of rows
123
% of the source pixels.
127
static unsigned int DecodeImage(const unsigned char *compressed_pixels,
128
const size_t length,unsigned char *pixels)
130
register const unsigned char
136
register unsigned char
142
assert(compressed_pixels != (unsigned char *) NULL);
143
assert(pixels != (unsigned char *) NULL);
146
while ((size_t) (p-compressed_pixels) < length)
154
Runlength-encoded packet: <count><byte>
170
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
174
% R e a d S U N I m a g e %
178
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180
% Method ReadSUNImage reads a SUN image file and returns it. It allocates
181
% the memory necessary for the new Image structure and returns a pointer to
184
% The format of the ReadSUNImage method is:
186
% Image *ReadSUNImage(const ImageInfo *image_info,ExceptionInfo *exception)
188
% A description of each parameter follows:
190
% o image: Method ReadSUNImage returns a pointer to the image after
191
% reading. A null image is returned if there is a memory shortage or
192
% if the image cannot be read.
194
% o image_info: Specifies a pointer to a ImageInfo structure.
196
% o exception: return any errors or warnings in this structure.
200
static Image *ReadSUNImage(const ImageInfo *image_info,ExceptionInfo *exception)
202
#define RMT_EQUAL_RGB 1
205
#define RT_STANDARD 1
207
#define RT_FORMAT_RGB 3
209
typedef struct _SUNInfo
243
register unsigned char
265
assert(image_info != (const ImageInfo *) NULL);
266
assert(image_info->signature == MagickSignature);
267
assert(exception != (ExceptionInfo *) NULL);
268
assert(exception->signature == MagickSignature);
269
image=AllocateImage(image_info);
270
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
272
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
274
Read SUN raster header.
276
sun_info.magic=ReadBlobMSBLong(image);
280
Verify SUN identifier.
282
if (sun_info.magic != 0x59a66a95)
283
ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
284
sun_info.width=ReadBlobMSBLong(image);
285
sun_info.height=ReadBlobMSBLong(image);
286
sun_info.depth=ReadBlobMSBLong(image);
287
sun_info.length=ReadBlobMSBLong(image);
288
sun_info.type=ReadBlobMSBLong(image);
289
sun_info.maptype=ReadBlobMSBLong(image);
290
sun_info.maplength=ReadBlobMSBLong(image);
291
image->columns= sun_info.width;
292
image->rows= sun_info.height;
293
image->depth=sun_info.depth <= 8 ? 8 : QuantumDepth;
294
if (sun_info.depth < 24)
296
image->storage_class=PseudoClass;
297
image->colors=sun_info.maplength;
298
if (sun_info.maptype == RMT_NONE)
299
image->colors=1 << sun_info.depth;
300
if (sun_info.maptype == RMT_EQUAL_RGB)
301
image->colors=sun_info.maplength/3;
303
switch (sun_info.maptype)
307
if (sun_info.depth < 24)
310
Create linear color ramp.
312
if (!AllocateImageColormap(image,image->colors))
313
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
324
Read SUN raster colormap.
326
if (!AllocateImageColormap(image,image->colors))
327
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
329
sun_colormap=MagickAllocateMemory(unsigned char *,image->colors);
330
if (sun_colormap == (unsigned char *) NULL)
331
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
333
(void) ReadBlob(image,image->colors,(char *) sun_colormap);
334
for (i=0; i < (long) image->colors; i++)
335
image->colormap[i].red=ScaleCharToQuantum(sun_colormap[i]);
336
(void) ReadBlob(image,image->colors,(char *) sun_colormap);
337
for (i=0; i < (long) image->colors; i++)
338
image->colormap[i].green=ScaleCharToQuantum(sun_colormap[i]);
339
(void) ReadBlob(image,image->colors,(char *) sun_colormap);
340
for (i=0; i < (long) image->colors; i++)
341
image->colormap[i].blue=ScaleCharToQuantum(sun_colormap[i]);
342
MagickFreeMemory(sun_colormap);
351
Read SUN raster colormap.
353
sun_colormap=MagickAllocateMemory(unsigned char *,sun_info.maplength);
354
if (sun_colormap == (unsigned char *) NULL)
355
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
357
(void) ReadBlob(image,sun_info.maplength,(char *) sun_colormap);
358
MagickFreeMemory(sun_colormap);
362
ThrowReaderException(CoderError,ColormapTypeNotSupported,image)
364
image->matte=(sun_info.depth == 32);
365
image->columns=sun_info.width;
366
image->rows=sun_info.height;
367
if (image_info->ping)
372
sun_data=MagickAllocateMemory(unsigned char *,sun_info.length);
373
if (sun_data == (unsigned char *) NULL)
374
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
375
count=ReadBlob(image,sun_info.length,(char *) sun_data);
376
if ((count == 0) && (sun_info.type != RT_ENCODED))
377
ThrowReaderException(CorruptImageError,UnableToReadImageData,image);
379
if (sun_info.type == RT_ENCODED)
385
Read run-length encoded raster pixels.
387
height=sun_info.height;
388
bytes_per_line=2*(sun_info.width*sun_info.depth+15)/16;
389
sun_pixels=MagickAllocateMemory(unsigned char *,bytes_per_line*height);
390
if (sun_pixels == (unsigned char *) NULL)
391
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
393
(void) DecodeImage(sun_data,sun_info.length,sun_pixels);
394
MagickFreeMemory(sun_data);
397
Convert SUN raster image to pixel packets.
400
if (sun_info.depth == 1)
401
for (y=0; y < (long) image->rows; y++)
403
q=SetImagePixels(image,0,y,image->columns,1);
404
if (q == (PixelPacket *) NULL)
406
indexes=GetIndexes(image);
407
for (x=0; x < ((long) image->columns-7); x+=8)
409
for (bit=7; bit >= 0; bit--)
410
indexes[x+7-bit]=((*p) & (0x01 << bit) ? 0x01 : 0x00);
413
if ((image->columns % 8) != 0)
415
for (bit=7; bit >= (long) (8-(image->columns % 8)); bit--)
416
indexes[x+7-bit]=((*p) & (0x01 << bit) ? 0x01 : 0x00);
419
if ((((image->columns/8)+(image->columns % 8 ? 1 : 0)) % 2) != 0)
421
if (!SyncImagePixels(image))
423
if (image->previous == (Image *) NULL)
424
if (QuantumTick(y,image->rows))
425
if (!MagickMonitor(LoadImageText,y,image->rows,exception))
429
if (image->storage_class == PseudoClass)
430
for (y=0; y < (long) image->rows; y++)
432
q=SetImagePixels(image,0,y,image->columns,1);
433
if (q == (PixelPacket *) NULL)
435
indexes=GetIndexes(image);
436
for (x=0; x < (long) image->columns; x++)
438
if ((image->columns % 2) != 0)
440
if (!SyncImagePixels(image))
442
if (image->previous == (Image *) NULL)
443
if (QuantumTick(y,image->rows))
444
if (!MagickMonitor(LoadImageText,y,image->rows,exception))
448
for (y=0; y < (long) image->rows; y++)
450
q=SetImagePixels(image,0,y,image->columns,1);
451
if (q == (PixelPacket *) NULL)
453
for (x=0; x < (long) image->columns; x++)
456
q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*p++));
457
if (sun_info.type == RT_STANDARD)
459
q->blue=ScaleCharToQuantum(*p++);
460
q->green=ScaleCharToQuantum(*p++);
461
q->red=ScaleCharToQuantum(*p++);
465
q->red=ScaleCharToQuantum(*p++);
466
q->green=ScaleCharToQuantum(*p++);
467
q->blue=ScaleCharToQuantum(*p++);
469
if (image->colors != 0)
471
q->red=image->colormap[q->red].red;
472
q->green=image->colormap[q->green].green;
473
q->blue=image->colormap[q->blue].blue;
477
if (((image->columns % 2) != 0) && (image->matte == False))
479
if (!SyncImagePixels(image))
481
if (image->previous == (Image *) NULL)
482
if (QuantumTick(y,image->rows))
483
if (!MagickMonitor(LoadImageText,y,image->rows,exception))
486
if (image->storage_class == PseudoClass)
488
MagickFreeMemory(sun_pixels);
491
ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
496
Proceed to next image.
498
if (image_info->subrange != 0)
499
if (image->scene >= (image_info->subimage+image_info->subrange-1))
501
sun_info.magic=ReadBlobMSBLong(image);
502
if (sun_info.magic == 0x59a66a95)
505
Allocate next image structure.
507
AllocateNextImage(image_info,image);
508
if (image->next == (Image *) NULL)
510
DestroyImageList(image);
511
return((Image *) NULL);
513
image=SyncNextImageInList(image);
514
if (!MagickMonitor(LoadImagesText,TellBlob(image),GetBlobSize(image),exception))
517
} while (sun_info.magic == 0x59a66a95);
518
while (image->previous != (Image *) NULL)
519
image=image->previous;
525
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
529
% R e g i s t e r S U N I m a g e %
533
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
535
% Method RegisterSUNImage adds attributes for the SUN image format to
536
% the list of supported formats. The attributes include the image format
537
% tag, a method to read and/or write the format, whether the format
538
% supports the saving of more than one frame to the same file or blob,
539
% whether the format supports native in-memory I/O, and a brief
540
% description of the format.
542
% The format of the RegisterSUNImage method is:
544
% RegisterSUNImage(void)
547
ModuleExport void RegisterSUNImage(void)
552
entry=SetMagickInfo("RAS");
553
entry->decoder=(DecoderHandler) ReadSUNImage;
554
entry->encoder=(EncoderHandler) WriteSUNImage;
555
entry->magick=(MagickHandler) IsSUN;
556
entry->description=AcquireString("SUN Rasterfile");
557
entry->module=AcquireString("SUN");
558
(void) RegisterMagickInfo(entry);
559
entry=SetMagickInfo("SUN");
560
entry->decoder=(DecoderHandler) ReadSUNImage;
561
entry->encoder=(EncoderHandler) WriteSUNImage;
562
entry->description=AcquireString("SUN Rasterfile");
563
entry->module=AcquireString("SUN");
564
(void) RegisterMagickInfo(entry);
568
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
572
% U n r e g i s t e r S U N I m a g e %
576
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578
% Method UnregisterSUNImage removes format registrations made by the
579
% SUN module from the list of supported formats.
581
% The format of the UnregisterSUNImage method is:
583
% UnregisterSUNImage(void)
586
ModuleExport void UnregisterSUNImage(void)
588
(void) UnregisterMagickInfo("RAS");
589
(void) UnregisterMagickInfo("SUN");
593
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
597
% W r i t e S U N I m a g e %
601
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603
% Method WriteSUNImage writes an image in the SUN rasterfile format.
605
% The format of the WriteSUNImage method is:
607
% unsigned int WriteSUNImage(const ImageInfo *image_info,Image *image)
609
% A description of each parameter follows.
611
% o status: Method WriteSUNImage return True if the image is written.
612
% False is returned is there is a memory shortage or if the image file
615
% o image_info: Specifies a pointer to a ImageInfo structure.
617
% o image: A pointer to an Image structure.
621
static unsigned int WriteSUNImage(const ImageInfo *image_info,Image *image)
623
#define RMT_EQUAL_RGB 1
626
#define RT_STANDARD 1
627
#define RT_FORMAT_RGB 3
629
typedef struct _SUNInfo
645
register const PixelPacket
668
Open output image file.
670
assert(image_info != (const ImageInfo *) NULL);
671
assert(image_info->signature == MagickSignature);
672
assert(image != (Image *) NULL);
673
assert(image->signature == MagickSignature);
674
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
676
ThrowWriterException(FileOpenError,UnableToOpenFile,image);
681
Initialize SUN raster file header.
683
TransformColorspace(image,RGBColorspace);
684
sun_info.magic=0x59a66a95;
685
sun_info.width=image->columns;
686
sun_info.height=image->rows;
688
(image->storage_class == DirectClass ? RT_FORMAT_RGB : RT_STANDARD);
689
sun_info.maptype=RMT_NONE;
690
sun_info.maplength=0;
691
number_pixels=image->columns*image->rows;
692
if (image->storage_class == DirectClass)
695
Full color SUN raster.
697
sun_info.depth=(image->matte ? 32 : 24);
698
sun_info.length=(image->matte ? 4 : 3)*number_pixels;
699
sun_info.length+=image->columns & 0x01 ? image->rows : 0;
702
if (IsMonochromeImage(image,&image->exception))
705
Monochrome SUN raster.
708
sun_info.length=((image->columns+7) >> 3)*image->rows;
709
sun_info.length+=((image->columns/8)+(image->columns % 8 ? 1 : 0)) %
715
Colormapped SUN raster.
718
sun_info.length=number_pixels;
719
sun_info.length+=image->columns & 0x01 ? image->rows : 0;
720
sun_info.maptype=RMT_EQUAL_RGB;
721
sun_info.maplength=image->colors*3;
726
(void) WriteBlobMSBLong(image,sun_info.magic);
727
(void) WriteBlobMSBLong(image,sun_info.width);
728
(void) WriteBlobMSBLong(image,sun_info.height);
729
(void) WriteBlobMSBLong(image,sun_info.depth);
730
(void) WriteBlobMSBLong(image,sun_info.length);
731
(void) WriteBlobMSBLong(image,sun_info.type);
732
(void) WriteBlobMSBLong(image,sun_info.maptype);
733
(void) WriteBlobMSBLong(image,sun_info.maplength);
735
Convert MIFF to SUN raster pixels.
739
if (image->storage_class == DirectClass)
741
register unsigned char
751
Allocate memory for pixels.
753
length=image->columns*sizeof(PixelPacket);
754
pixels=MagickAllocateMemory(unsigned char *,length);
755
if (pixels == (unsigned char *) NULL)
756
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
759
Convert DirectClass packet to SUN RGB pixel.
761
for (y=0; y < (long) image->rows; y++)
763
p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
764
if (p == (const PixelPacket *) NULL)
767
for (x=0; x < (long) image->columns; x++)
770
*q++=ScaleQuantumToChar(MaxRGB-p->opacity);
771
*q++=ScaleQuantumToChar(p->red);
772
*q++=ScaleQuantumToChar(p->green);
773
*q++=ScaleQuantumToChar(p->blue);
776
if (image->columns & 0x01)
777
*q++=0; /* pad scanline */
778
(void) WriteBlob(image,q-pixels,(char *) pixels);
779
if (image->previous == (Image *) NULL)
780
if (QuantumTick(y,image->rows))
781
if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
784
MagickFreeMemory(pixels);
787
if (IsMonochromeImage(image,&image->exception))
789
register unsigned char
795
Convert PseudoClass image to a SUN monochrome image.
797
SetImageType(image,BilevelType);
798
polarity=PixelIntensityToQuantum(&image->colormap[0]) < (MaxRGB/2);
799
if (image->colors == 2)
800
polarity=PixelIntensityToQuantum(&image->colormap[0]) <
801
PixelIntensityToQuantum(&image->colormap[1]);
802
for (y=0; y < (long) image->rows; y++)
804
p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
805
if (p == (const PixelPacket *) NULL)
807
indexes=GetIndexes(image);
810
for (x=0; x < (long) image->columns; x++)
813
if (indexes[x] == polarity)
818
(void) WriteBlobByte(image,byte);
825
(void) WriteBlobByte(image,byte << (8-bit));
826
if ((((image->columns/8)+
827
(image->columns % 8 ? 1 : 0)) % 2) != 0)
828
(void) WriteBlobByte(image,0); /* pad scanline */
829
if (image->previous == (Image *) NULL)
830
if (QuantumTick(y,image->rows))
831
if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
838
Dump colormap to file.
840
for (i=0; i < (long) image->colors; i++)
841
(void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
842
for (i=0; i < (long) image->colors; i++)
843
(void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].green));
844
for (i=0; i < (long) image->colors; i++)
845
(void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
847
Convert PseudoClass packet to SUN colormapped pixel.
849
for (y=0; y < (long) image->rows; y++)
851
p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
852
if (p == (const PixelPacket *) NULL)
854
indexes=GetIndexes(image);
855
for (x=0; x < (long) image->columns; x++)
857
(void) WriteBlobByte(image,indexes[x]);
860
if (image->columns & 0x01)
861
(void) WriteBlobByte(image,0); /* pad scanline */
862
if (image->previous == (Image *) NULL)
863
if (QuantumTick(y,image->rows))
864
if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
868
if (image->next == (Image *) NULL)
870
image=SyncNextImageInList(image);
871
if (!MagickMonitor(SaveImagesText,scene++,GetImageListLength(image),&image->exception))
873
} while (image_info->adjoin);
874
if (image_info->adjoin)
875
while (image->previous != (Image *) NULL)
876
image=image->previous;