• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            SSSSS  U   U  N   N                              %
7 %                            SS     U   U  NN  N                              %
8 %                             SSS   U   U  N N N                              %
9 %                               SS  U   U  N  NN                              %
10 %                            SSSSS   UUU   N   N                              %
11 %                                                                             %
12 %                                                                             %
13 %                    Read/Write Sun Rasterfile Image Format                   %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colormap-private.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/colorspace-private.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/image.h"
56 #include "MagickCore/image-private.h"
57 #include "MagickCore/list.h"
58 #include "MagickCore/magick.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/memory-private.h"
61 #include "MagickCore/monitor.h"
62 #include "MagickCore/monitor-private.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/quantum-private.h"
65 #include "MagickCore/static.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/module.h"
68 
69 /*
70   Forward declarations.
71 */
72 static MagickBooleanType
73   WriteSUNImage(const ImageInfo *,Image *,ExceptionInfo *);
74 
75 /*
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %                                                                             %
78 %                                                                             %
79 %                                                                             %
80 %   I s S U N                                                                 %
81 %                                                                             %
82 %                                                                             %
83 %                                                                             %
84 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 %
86 %  IsSUN() returns MagickTrue if the image format type, identified by the
87 %  magick string, is SUN.
88 %
89 %  The format of the IsSUN method is:
90 %
91 %      MagickBooleanType IsSUN(const unsigned char *magick,const size_t length)
92 %
93 %  A description of each parameter follows:
94 %
95 %    o magick: compare image format pattern against these bytes.
96 %
97 %    o length: Specifies the length of the magick string.
98 %
99 */
IsSUN(const unsigned char * magick,const size_t length)100 static MagickBooleanType IsSUN(const unsigned char *magick,const size_t length)
101 {
102   if (length < 4)
103     return(MagickFalse);
104   if (memcmp(magick,"\131\246\152\225",4) == 0)
105     return(MagickTrue);
106   return(MagickFalse);
107 }
108 
109 /*
110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111 %                                                                             %
112 %                                                                             %
113 %                                                                             %
114 %   D e c o d e I m a g e                                                     %
115 %                                                                             %
116 %                                                                             %
117 %                                                                             %
118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119 %
120 %  DecodeImage unpacks the packed image pixels into  runlength-encoded pixel
121 %  packets.
122 %
123 %  The format of the DecodeImage method is:
124 %
125 %      MagickBooleanType DecodeImage(const unsigned char *compressed_pixels,
126 %        const size_t length,unsigned char *pixels)
127 %
128 %  A description of each parameter follows:
129 %
130 %    o compressed_pixels:  The address of a byte (8 bits) array of compressed
131 %      pixel data.
132 %
133 %    o length:  An integer value that is the total number of bytes of the
134 %      source image (as just read by ReadBlob)
135 %
136 %    o pixels:  The address of a byte (8 bits) array of pixel data created by
137 %      the uncompression process.  The number of bytes in this array
138 %      must be at least equal to the number columns times the number of rows
139 %      of the source pixels.
140 %
141 */
DecodeImage(const unsigned char * compressed_pixels,const size_t length,unsigned char * pixels,size_t extent)142 static MagickBooleanType DecodeImage(const unsigned char *compressed_pixels,
143   const size_t length,unsigned char *pixels,size_t extent)
144 {
145   register const unsigned char
146     *p;
147 
148   register unsigned char
149     *q;
150 
151   ssize_t
152     count;
153 
154   unsigned char
155     byte;
156 
157   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
158   assert(compressed_pixels != (unsigned char *) NULL);
159   assert(pixels != (unsigned char *) NULL);
160   p=compressed_pixels;
161   q=pixels;
162   while (((size_t) (p-compressed_pixels) < length) &&
163          ((size_t) (q-pixels) < extent))
164   {
165     byte=(*p++);
166     if (byte != 128U)
167       *q++=byte;
168     else
169       {
170         /*
171           Runlength-encoded packet: <count><byte>.
172         */
173         if (((size_t) (p-compressed_pixels) >= length))
174           break;
175         count=(*p++);
176         if (count > 0)
177           {
178             if (((size_t) (p-compressed_pixels) >= length))
179               break;
180             byte=(*p++);
181           }
182         while ((count >= 0) && ((size_t) (q-pixels) < extent))
183         {
184           *q++=byte;
185           count--;
186         }
187      }
188   }
189   return(((size_t) (q-pixels) == extent) ? MagickTrue : MagickFalse);
190 }
191 
192 /*
193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 %                                                                             %
195 %                                                                             %
196 %                                                                             %
197 %   R e a d S U N I m a g e                                                   %
198 %                                                                             %
199 %                                                                             %
200 %                                                                             %
201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202 %
203 %  ReadSUNImage() reads a SUN image file and returns it.  It allocates
204 %  the memory necessary for the new Image structure and returns a pointer to
205 %  the new image.
206 %
207 %  The format of the ReadSUNImage method is:
208 %
209 %      Image *ReadSUNImage(const ImageInfo *image_info,ExceptionInfo *exception)
210 %
211 %  A description of each parameter follows:
212 %
213 %    o image_info: the image info.
214 %
215 %    o exception: return any errors or warnings in this structure.
216 %
217 */
ReadSUNImage(const ImageInfo * image_info,ExceptionInfo * exception)218 static Image *ReadSUNImage(const ImageInfo *image_info,ExceptionInfo *exception)
219 {
220 #define RMT_EQUAL_RGB  1
221 #define RMT_NONE  0
222 #define RMT_RAW  2
223 #define RT_STANDARD  1
224 #define RT_ENCODED  2
225 #define RT_FORMAT_RGB  3
226 
227   typedef struct _SUNInfo
228   {
229     unsigned int
230       magic,
231       width,
232       height,
233       depth,
234       length,
235       type,
236       maptype,
237       maplength;
238   } SUNInfo;
239 
240   Image
241     *image;
242 
243   int
244     bit;
245 
246   MagickBooleanType
247     status;
248 
249   MagickSizeType
250     number_pixels;
251 
252   register Quantum
253     *q;
254 
255   register ssize_t
256     i,
257     x;
258 
259   register unsigned char
260     *p;
261 
262   size_t
263     bytes_per_line,
264     extent,
265     height,
266     pixels_length;
267 
268   ssize_t
269     count,
270     y;
271 
272   SUNInfo
273     sun_info;
274 
275   unsigned char
276     *sun_data,
277     *sun_pixels;
278 
279   /*
280     Open image file.
281   */
282   assert(image_info != (const ImageInfo *) NULL);
283   assert(image_info->signature == MagickCoreSignature);
284   if (image_info->debug != MagickFalse)
285     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
286       image_info->filename);
287   assert(exception != (ExceptionInfo *) NULL);
288   assert(exception->signature == MagickCoreSignature);
289   image=AcquireImage(image_info,exception);
290   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
291   if (status == MagickFalse)
292     {
293       image=DestroyImageList(image);
294       return((Image *) NULL);
295     }
296   /*
297     Read SUN raster header.
298   */
299   (void) ResetMagickMemory(&sun_info,0,sizeof(sun_info));
300   sun_info.magic=ReadBlobMSBLong(image);
301   do
302   {
303     /*
304       Verify SUN identifier.
305     */
306     if (sun_info.magic != 0x59a66a95)
307       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
308     sun_info.width=ReadBlobMSBLong(image);
309     sun_info.height=ReadBlobMSBLong(image);
310     sun_info.depth=ReadBlobMSBLong(image);
311     sun_info.length=ReadBlobMSBLong(image);
312     sun_info.type=ReadBlobMSBLong(image);
313     sun_info.maptype=ReadBlobMSBLong(image);
314     sun_info.maplength=ReadBlobMSBLong(image);
315     extent=sun_info.height*sun_info.width;
316     if ((sun_info.height != 0) && (sun_info.width != extent/sun_info.height))
317       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
318     if ((sun_info.type != RT_STANDARD) && (sun_info.type != RT_ENCODED) &&
319         (sun_info.type != RT_FORMAT_RGB))
320       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
321     if ((sun_info.maptype == RMT_NONE) && (sun_info.maplength != 0))
322       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
323     if ((sun_info.depth != 1) && (sun_info.depth != 8) &&
324         (sun_info.depth != 24) && (sun_info.depth != 32))
325       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
326     if ((sun_info.maptype != RMT_NONE) && (sun_info.maptype != RMT_EQUAL_RGB) &&
327         (sun_info.maptype != RMT_RAW))
328       ThrowReaderException(CoderError,"ColormapTypeNotSupported");
329     image->columns=sun_info.width;
330     image->rows=sun_info.height;
331     image->depth=sun_info.depth <= 8 ? sun_info.depth :
332       MAGICKCORE_QUANTUM_DEPTH;
333     if (sun_info.depth < 24)
334       {
335         size_t
336           one;
337 
338         image->colors=sun_info.maplength;
339         one=1;
340         if (sun_info.maptype == RMT_NONE)
341           image->colors=one << sun_info.depth;
342         if (sun_info.maptype == RMT_EQUAL_RGB)
343           image->colors=sun_info.maplength/3;
344         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
345           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
346       }
347     switch (sun_info.maptype)
348     {
349       case RMT_NONE:
350         break;
351       case RMT_EQUAL_RGB:
352       {
353         unsigned char
354           *sun_colormap;
355 
356         /*
357           Read SUN raster colormap.
358         */
359         sun_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
360           sizeof(*sun_colormap));
361         if (sun_colormap == (unsigned char *) NULL)
362           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
363         count=ReadBlob(image,image->colors,sun_colormap);
364         if (count != (ssize_t) image->colors)
365           ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
366         for (i=0; i < (ssize_t) image->colors; i++)
367           image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(
368             sun_colormap[i]);
369         count=ReadBlob(image,image->colors,sun_colormap);
370         if (count != (ssize_t) image->colors)
371           ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
372         for (i=0; i < (ssize_t) image->colors; i++)
373           image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(
374             sun_colormap[i]);
375         count=ReadBlob(image,image->colors,sun_colormap);
376         if (count != (ssize_t) image->colors)
377           ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
378         for (i=0; i < (ssize_t) image->colors; i++)
379           image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(
380             sun_colormap[i]);
381         sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap);
382         break;
383       }
384       case RMT_RAW:
385       {
386         unsigned char
387           *sun_colormap;
388 
389         /*
390           Read SUN raster colormap.
391         */
392         sun_colormap=(unsigned char *) AcquireQuantumMemory(sun_info.maplength,
393           sizeof(*sun_colormap));
394         if (sun_colormap == (unsigned char *) NULL)
395           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
396         count=ReadBlob(image,sun_info.maplength,sun_colormap);
397         if (count != (ssize_t) sun_info.maplength)
398           ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
399         sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap);
400         break;
401       }
402       default:
403         ThrowReaderException(CoderError,"ColormapTypeNotSupported");
404     }
405     image->alpha_trait=sun_info.depth == 32 ? BlendPixelTrait :
406       UndefinedPixelTrait;
407     image->columns=sun_info.width;
408     image->rows=sun_info.height;
409     if (image_info->ping != MagickFalse)
410       {
411         (void) CloseBlob(image);
412         return(GetFirstImageInList(image));
413       }
414     status=SetImageExtent(image,image->columns,image->rows,exception);
415     if (status == MagickFalse)
416       return(DestroyImageList(image));
417     if (sun_info.length == 0)
418       ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
419     number_pixels=(MagickSizeType) (image->columns*image->rows);
420     if ((sun_info.type != RT_ENCODED) &&
421         ((number_pixels*sun_info.depth) > (8UL*sun_info.length)))
422       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
423     if (HeapOverflowSanityCheck(sun_info.width,sun_info.depth) != MagickFalse)
424       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
425     bytes_per_line=sun_info.width*sun_info.depth;
426     sun_data=(unsigned char *) AcquireQuantumMemory(sun_info.length,
427       sizeof(*sun_data));
428     if (sun_data == (unsigned char *) NULL)
429       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
430     count=(ssize_t) ReadBlob(image,sun_info.length,sun_data);
431     if (count != (ssize_t) sun_info.length)
432       {
433         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
434         ThrowReaderException(CorruptImageError,"UnableToReadImageData");
435       }
436     height=sun_info.height;
437     if ((height == 0) || (sun_info.width == 0) || (sun_info.depth == 0) ||
438         ((bytes_per_line/sun_info.depth) != sun_info.width))
439       {
440         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
441         ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
442       }
443     bytes_per_line+=15;
444     bytes_per_line<<=1;
445     if ((bytes_per_line >> 1) != (sun_info.width*sun_info.depth+15))
446       {
447         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
448         ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
449       }
450     bytes_per_line>>=4;
451     if (HeapOverflowSanityCheck(height,bytes_per_line) != MagickFalse)
452       {
453         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
454         ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
455       }
456     pixels_length=height*bytes_per_line;
457     sun_pixels=(unsigned char *) AcquireQuantumMemory(pixels_length,
458       sizeof(*sun_pixels));
459     if (sun_pixels == (unsigned char *) NULL)
460       {
461         sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
462         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
463       }
464     ResetMagickMemory(sun_pixels,0,pixels_length*sizeof(*sun_pixels));
465     if (sun_info.type == RT_ENCODED)
466       {
467         status=DecodeImage(sun_data,sun_info.length,sun_pixels,pixels_length);
468         if (status == MagickFalse)
469           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
470       }
471     else
472       {
473         if (sun_info.length > pixels_length)
474           {
475             sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
476             sun_pixels=(unsigned char *) RelinquishMagickMemory(sun_pixels);
477             ThrowReaderException(ResourceLimitError,"ImproperImageHeader");
478           }
479         (void) CopyMagickMemory(sun_pixels,sun_data,sun_info.length);
480       }
481     sun_data=(unsigned char *) RelinquishMagickMemory(sun_data);
482     /*
483       Convert SUN raster image to pixel packets.
484     */
485     p=sun_pixels;
486     if (sun_info.depth == 1)
487       for (y=0; y < (ssize_t) image->rows; y++)
488       {
489         q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
490         if (q == (Quantum *) NULL)
491           break;
492         for (x=0; x < ((ssize_t) image->columns-7); x+=8)
493         {
494           for (bit=7; bit >= 0; bit--)
495           {
496             SetPixelIndex(image,(Quantum) ((*p) & (0x01 << bit) ? 0x00 : 0x01),
497               q);
498             q+=GetPixelChannels(image);
499           }
500           p++;
501         }
502         if ((image->columns % 8) != 0)
503           {
504             for (bit=7; bit >= (int) (8-(image->columns % 8)); bit--)
505             {
506               SetPixelIndex(image,(Quantum) ((*p) & (0x01 << bit) ? 0x00 :
507                 0x01),q);
508               q+=GetPixelChannels(image);
509             }
510             p++;
511           }
512         if ((((image->columns/8)+(image->columns % 8 ? 1 : 0)) % 2) != 0)
513           p++;
514         if (SyncAuthenticPixels(image,exception) == MagickFalse)
515           break;
516         if (image->previous == (Image *) NULL)
517           {
518             status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
519               image->rows);
520             if (status == MagickFalse)
521               break;
522           }
523       }
524     else
525       if (image->storage_class == PseudoClass)
526         {
527           for (y=0; y < (ssize_t) image->rows; y++)
528           {
529             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
530             if (q == (Quantum *) NULL)
531               break;
532             for (x=0; x < (ssize_t) image->columns; x++)
533             {
534               SetPixelIndex(image,ConstrainColormapIndex(image,*p,exception),q);
535               p++;
536               q+=GetPixelChannels(image);
537             }
538             if ((image->columns % 2) != 0)
539               p++;
540             if (SyncAuthenticPixels(image,exception) == MagickFalse)
541               break;
542             if (image->previous == (Image *) NULL)
543               {
544                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
545                 image->rows);
546                 if (status == MagickFalse)
547                   break;
548               }
549           }
550         }
551       else
552         {
553           size_t
554             bytes_per_pixel;
555 
556           bytes_per_pixel=3;
557           if (image->alpha_trait != UndefinedPixelTrait)
558             bytes_per_pixel++;
559           if (bytes_per_line == 0)
560             bytes_per_line=bytes_per_pixel*image->columns;
561           for (y=0; y < (ssize_t) image->rows; y++)
562           {
563             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
564             if (q == (Quantum *) NULL)
565               break;
566             for (x=0; x < (ssize_t) image->columns; x++)
567             {
568               if (image->alpha_trait != UndefinedPixelTrait)
569                 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
570               if (sun_info.type == RT_STANDARD)
571                 {
572                   SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
573                   SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
574                   SetPixelRed(image,ScaleCharToQuantum(*p++),q);
575                 }
576               else
577                 {
578                   SetPixelRed(image,ScaleCharToQuantum(*p++),q);
579                   SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
580                   SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
581                 }
582               if (image->colors != 0)
583                 {
584                   SetPixelRed(image,ClampToQuantum(image->colormap[(ssize_t)
585                     GetPixelRed(image,q)].red),q);
586                   SetPixelGreen(image,ClampToQuantum(image->colormap[(ssize_t)
587                     GetPixelGreen(image,q)].green),q);
588                   SetPixelBlue(image,ClampToQuantum(image->colormap[(ssize_t)
589                     GetPixelBlue(image,q)].blue),q);
590                 }
591               q+=GetPixelChannels(image);
592             }
593             if (((bytes_per_pixel*image->columns) % 2) != 0)
594               p++;
595             if (SyncAuthenticPixels(image,exception) == MagickFalse)
596               break;
597             if (image->previous == (Image *) NULL)
598               {
599                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
600                 image->rows);
601                 if (status == MagickFalse)
602                   break;
603               }
604           }
605         }
606     if (image->storage_class == PseudoClass)
607       (void) SyncImage(image,exception);
608     sun_pixels=(unsigned char *) RelinquishMagickMemory(sun_pixels);
609     if (EOFBlob(image) != MagickFalse)
610       {
611         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
612           image->filename);
613         break;
614       }
615     /*
616       Proceed to next image.
617     */
618     if (image_info->number_scenes != 0)
619       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
620         break;
621     sun_info.magic=ReadBlobMSBLong(image);
622     if (sun_info.magic == 0x59a66a95)
623       {
624         /*
625           Allocate next image structure.
626         */
627         AcquireNextImage(image_info,image,exception);
628         if (GetNextImageInList(image) == (Image *) NULL)
629           {
630             image=DestroyImageList(image);
631             return((Image *) NULL);
632           }
633         image=SyncNextImageInList(image);
634         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
635           GetBlobSize(image));
636         if (status == MagickFalse)
637           break;
638       }
639   } while (sun_info.magic == 0x59a66a95);
640   (void) CloseBlob(image);
641   return(GetFirstImageInList(image));
642 }
643 
644 /*
645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646 %                                                                             %
647 %                                                                             %
648 %                                                                             %
649 %   R e g i s t e r S U N I m a g e                                           %
650 %                                                                             %
651 %                                                                             %
652 %                                                                             %
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654 %
655 %  RegisterSUNImage() adds attributes for the SUN image format to
656 %  the list of supported formats.  The attributes include the image format
657 %  tag, a method to read and/or write the format, whether the format
658 %  supports the saving of more than one frame to the same file or blob,
659 %  whether the format supports native in-memory I/O, and a brief
660 %  description of the format.
661 %
662 %  The format of the RegisterSUNImage method is:
663 %
664 %      size_t RegisterSUNImage(void)
665 %
666 */
RegisterSUNImage(void)667 ModuleExport size_t RegisterSUNImage(void)
668 {
669   MagickInfo
670     *entry;
671 
672   entry=AcquireMagickInfo("SUN","RAS","SUN Rasterfile");
673   entry->decoder=(DecodeImageHandler *) ReadSUNImage;
674   entry->encoder=(EncodeImageHandler *) WriteSUNImage;
675   entry->magick=(IsImageFormatHandler *) IsSUN;
676   (void) RegisterMagickInfo(entry);
677   entry=AcquireMagickInfo("SUN","SUN","SUN Rasterfile");
678   entry->decoder=(DecodeImageHandler *) ReadSUNImage;
679   entry->encoder=(EncodeImageHandler *) WriteSUNImage;
680   (void) RegisterMagickInfo(entry);
681   return(MagickImageCoderSignature);
682 }
683 
684 /*
685 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 %                                                                             %
687 %                                                                             %
688 %                                                                             %
689 %   U n r e g i s t e r S U N I m a g e                                       %
690 %                                                                             %
691 %                                                                             %
692 %                                                                             %
693 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
694 %
695 %  UnregisterSUNImage() removes format registrations made by the
696 %  SUN module from the list of supported formats.
697 %
698 %  The format of the UnregisterSUNImage method is:
699 %
700 %      UnregisterSUNImage(void)
701 %
702 */
UnregisterSUNImage(void)703 ModuleExport void UnregisterSUNImage(void)
704 {
705   (void) UnregisterMagickInfo("RAS");
706   (void) UnregisterMagickInfo("SUN");
707 }
708 
709 /*
710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
711 %                                                                             %
712 %                                                                             %
713 %                                                                             %
714 %   W r i t e S U N I m a g e                                                 %
715 %                                                                             %
716 %                                                                             %
717 %                                                                             %
718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
719 %
720 %  WriteSUNImage() writes an image in the SUN rasterfile format.
721 %
722 %  The format of the WriteSUNImage method is:
723 %
724 %      MagickBooleanType WriteSUNImage(const ImageInfo *image_info,
725 %        Image *image,ExceptionInfo *exception)
726 %
727 %  A description of each parameter follows.
728 %
729 %    o image_info: the image info.
730 %
731 %    o image:  The image.
732 %
733 %    o exception: return any errors or warnings in this structure.
734 %
735 */
WriteSUNImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)736 static MagickBooleanType WriteSUNImage(const ImageInfo *image_info,Image *image,
737   ExceptionInfo *exception)
738 {
739 #define RMT_EQUAL_RGB  1
740 #define RMT_NONE  0
741 #define RMT_RAW  2
742 #define RT_STANDARD  1
743 #define RT_FORMAT_RGB  3
744 
745   typedef struct _SUNInfo
746   {
747     unsigned int
748       magic,
749       width,
750       height,
751       depth,
752       length,
753       type,
754       maptype,
755       maplength;
756   } SUNInfo;
757 
758   MagickBooleanType
759     status;
760 
761   MagickOffsetType
762     scene;
763 
764   MagickSizeType
765     number_pixels;
766 
767   register const Quantum
768     *p;
769 
770   register ssize_t
771     i,
772     x;
773 
774   ssize_t
775     y;
776 
777   SUNInfo
778     sun_info;
779 
780   /*
781     Open output image file.
782   */
783   assert(image_info != (const ImageInfo *) NULL);
784   assert(image_info->signature == MagickCoreSignature);
785   assert(image != (Image *) NULL);
786   assert(image->signature == MagickCoreSignature);
787   if (image->debug != MagickFalse)
788     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
789   assert(exception != (ExceptionInfo *) NULL);
790   assert(exception->signature == MagickCoreSignature);
791   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
792   if (status == MagickFalse)
793     return(status);
794   scene=0;
795   do
796   {
797     /*
798       Initialize SUN raster file header.
799     */
800     (void) TransformImageColorspace(image,sRGBColorspace,exception);
801     sun_info.magic=0x59a66a95;
802     if ((image->columns != (unsigned int) image->columns) ||
803         (image->rows != (unsigned int) image->rows))
804       ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
805     sun_info.width=(unsigned int) image->columns;
806     sun_info.height=(unsigned int) image->rows;
807     sun_info.type=(unsigned int)
808       (image->storage_class == DirectClass ? RT_FORMAT_RGB : RT_STANDARD);
809     sun_info.maptype=RMT_NONE;
810     sun_info.maplength=0;
811     number_pixels=(MagickSizeType) image->columns*image->rows;
812     if ((4*number_pixels) != (size_t) (4*number_pixels))
813       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
814     if (image->storage_class == DirectClass)
815       {
816         /*
817           Full color SUN raster.
818         */
819         sun_info.depth=(unsigned int) image->alpha_trait != UndefinedPixelTrait ?
820           32U : 24U;
821         sun_info.length=(unsigned int) ((image->alpha_trait != UndefinedPixelTrait ?
822           4 : 3)*number_pixels);
823         sun_info.length+=sun_info.length & 0x01 ? (unsigned int) image->rows :
824           0;
825       }
826     else
827       if (SetImageMonochrome(image,exception) != MagickFalse)
828         {
829           /*
830             Monochrome SUN raster.
831           */
832           sun_info.depth=1;
833           sun_info.length=(unsigned int) (((image->columns+7) >> 3)*
834             image->rows);
835           sun_info.length+=(unsigned int) (((image->columns/8)+(image->columns %
836             8 ? 1 : 0)) % 2 ? image->rows : 0);
837         }
838       else
839         {
840           /*
841             Colormapped SUN raster.
842           */
843           sun_info.depth=8;
844           sun_info.length=(unsigned int) number_pixels;
845           sun_info.length+=(unsigned int) (image->columns & 0x01 ? image->rows :
846             0);
847           sun_info.maptype=RMT_EQUAL_RGB;
848           sun_info.maplength=(unsigned int) (3*image->colors);
849         }
850     /*
851       Write SUN header.
852     */
853     (void) WriteBlobMSBLong(image,sun_info.magic);
854     (void) WriteBlobMSBLong(image,sun_info.width);
855     (void) WriteBlobMSBLong(image,sun_info.height);
856     (void) WriteBlobMSBLong(image,sun_info.depth);
857     (void) WriteBlobMSBLong(image,sun_info.length);
858     (void) WriteBlobMSBLong(image,sun_info.type);
859     (void) WriteBlobMSBLong(image,sun_info.maptype);
860     (void) WriteBlobMSBLong(image,sun_info.maplength);
861     /*
862       Convert MIFF to SUN raster pixels.
863     */
864     x=0;
865     y=0;
866     if (image->storage_class == DirectClass)
867       {
868         register unsigned char
869           *q;
870 
871         size_t
872           bytes_per_pixel,
873           length;
874 
875         unsigned char
876           *pixels;
877 
878         /*
879           Allocate memory for pixels.
880         */
881         bytes_per_pixel=3;
882         if (image->alpha_trait != UndefinedPixelTrait)
883           bytes_per_pixel++;
884         length=image->columns;
885         pixels=(unsigned char *) AcquireQuantumMemory(length,4*sizeof(*pixels));
886         if (pixels == (unsigned char *) NULL)
887           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
888         /*
889           Convert DirectClass packet to SUN RGB pixel.
890         */
891         for (y=0; y < (ssize_t) image->rows; y++)
892         {
893           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
894           if (p == (const Quantum *) NULL)
895             break;
896           q=pixels;
897           for (x=0; x < (ssize_t) image->columns; x++)
898           {
899             if (image->alpha_trait != UndefinedPixelTrait)
900               *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
901             *q++=ScaleQuantumToChar(GetPixelRed(image,p));
902             *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
903             *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
904             p+=GetPixelChannels(image);
905           }
906           if (((bytes_per_pixel*image->columns) & 0x01) != 0)
907             *q++='\0';  /* pad scanline */
908           (void) WriteBlob(image,(size_t) (q-pixels),pixels);
909           if (image->previous == (Image *) NULL)
910             {
911               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
912                 image->rows);
913               if (status == MagickFalse)
914                 break;
915             }
916         }
917         pixels=(unsigned char *) RelinquishMagickMemory(pixels);
918       }
919     else
920       if (SetImageMonochrome(image,exception) != MagickFalse)
921         {
922           register unsigned char
923             bit,
924             byte;
925 
926           /*
927             Convert PseudoClass image to a SUN monochrome image.
928           */
929           (void) SetImageType(image,BilevelType,exception);
930           for (y=0; y < (ssize_t) image->rows; y++)
931           {
932             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
933             if (p == (const Quantum *) NULL)
934               break;
935             bit=0;
936             byte=0;
937             for (x=0; x < (ssize_t) image->columns; x++)
938             {
939               byte<<=1;
940               if (GetPixelLuma(image,p) < (QuantumRange/2.0))
941                 byte|=0x01;
942               bit++;
943               if (bit == 8)
944                 {
945                   (void) WriteBlobByte(image,byte);
946                   bit=0;
947                   byte=0;
948                 }
949               p+=GetPixelChannels(image);
950             }
951             if (bit != 0)
952               (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit)));
953             if ((((image->columns/8)+
954                 (image->columns % 8 ? 1 : 0)) % 2) != 0)
955               (void) WriteBlobByte(image,0);  /* pad scanline */
956             if (image->previous == (Image *) NULL)
957               {
958                 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
959                 image->rows);
960                 if (status == MagickFalse)
961                   break;
962               }
963           }
964         }
965       else
966         {
967           /*
968             Dump colormap to file.
969           */
970           for (i=0; i < (ssize_t) image->colors; i++)
971             (void) WriteBlobByte(image,ScaleQuantumToChar(
972               ClampToQuantum(image->colormap[i].red)));
973           for (i=0; i < (ssize_t) image->colors; i++)
974             (void) WriteBlobByte(image,ScaleQuantumToChar(
975               ClampToQuantum(image->colormap[i].green)));
976           for (i=0; i < (ssize_t) image->colors; i++)
977             (void) WriteBlobByte(image,ScaleQuantumToChar(
978               ClampToQuantum(image->colormap[i].blue)));
979           /*
980             Convert PseudoClass packet to SUN colormapped pixel.
981           */
982           for (y=0; y < (ssize_t) image->rows; y++)
983           {
984             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
985             if (p == (const Quantum *) NULL)
986               break;
987             for (x=0; x < (ssize_t) image->columns; x++)
988             {
989               (void) WriteBlobByte(image,(unsigned char)
990                 GetPixelIndex(image,p));
991               p+=GetPixelChannels(image);
992             }
993             if (image->columns & 0x01)
994               (void) WriteBlobByte(image,0);  /* pad scanline */
995             if (image->previous == (Image *) NULL)
996               {
997                 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
998                   image->rows);
999                 if (status == MagickFalse)
1000                   break;
1001               }
1002           }
1003         }
1004     if (GetNextImageInList(image) == (Image *) NULL)
1005       break;
1006     image=SyncNextImageInList(image);
1007     status=SetImageProgress(image,SaveImagesTag,scene++,
1008       GetImageListLength(image));
1009     if (status == MagickFalse)
1010       break;
1011   } while (image_info->adjoin != MagickFalse);
1012   (void) CloseBlob(image);
1013   return(MagickTrue);
1014 }
1015