Coverage Report

Created: 2026-11-12 07:35

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