source: ImageMagick/trunk/coders/sun.c @ 3783

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