Coverage Report

Created: 2025-08-11 08:01

/src/graphicsmagick/coders/pnm.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
% Copyright (C) 2003-2023 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                            PPPP   N   N  M   M                              %
15
%                            P   P  NN  N  MM MM                              %
16
%                            PPPP   N N N  M M M                              %
17
%                            P      N  NN  M   M                              %
18
%                            P      N   N  M   M                              %
19
%                                                                             %
20
%                                                                             %
21
%              Read/Write PBMPlus Portable Anymap Image Format.               %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                                 July 1992                                   %
27
%                                                                             %
28
%                                                                             %
29
%                                                                             %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31
%
32
%
33
*/
34

35
/*
36
  Include declarations.
37
*/
38
#include "magick/studio.h"
39
#include "magick/analyze.h"
40
#include "magick/attribute.h"
41
#include "magick/blob.h"
42
#include "magick/color.h"
43
#include "magick/colormap.h"
44
#include "magick/constitute.h"
45
#include "magick/log.h"
46
#include "magick/magick.h"
47
#include "magick/monitor.h"
48
#include "magick/omp_data_view.h"
49
#include "magick/pixel_cache.h"
50
#include "magick/utility.h"
51

52
/*
53
  Forward declarations.
54
*/
55
static unsigned int
56
  WritePNMImage(const ImageInfo *,Image *);
57
58

59
/*
60
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61
%                                                                             %
62
%                                                                             %
63
%                                                                             %
64
%   I s P N M                                                                 %
65
%                                                                             %
66
%                                                                             %
67
%                                                                             %
68
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69
%
70
%  Method IsPNM returns True if the image format type, identified by the
71
%  magick string, is PNM.
72
%
73
%  The format of the IsPNM method is:
74
%
75
%      unsigned int IsPNM(const unsigned char *magick,const size_t length)
76
%
77
%  A description of each parameter follows:
78
%
79
%    o status:  Method IsPNM returns True if the image format type is PNM.
80
%
81
%    o magick: This string is generally the first few bytes of an image file
82
%      or blob.
83
%
84
%    o length: Specifies the length of the magick string.
85
%
86
%
87
*/
88
static unsigned int IsPNM(const unsigned char *magick,const size_t length)
89
0
{
90
0
  if (length < 2)
91
0
    return(False);
92
0
  if ((*magick == 'P') && isdigit((int) magick[1]))
93
0
    return(True);
94
0
  return(False);
95
0
}
96

97
/*
98
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99
%                                                                             %
100
%                                                                             %
101
%                                                                             %
102
%   R e a d P N M I m a g e                                                   %
103
%                                                                             %
104
%                                                                             %
105
%                                                                             %
106
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107
%
108
%  Method ReadPNMImage reads a Portable Anymap image file and returns it.
109
%  It allocates the memory necessary for the new Image structure and returns
110
%  a pointer to the new image.
111
%
112
%  The format of the ReadPNMImage method is:
113
%
114
%      Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
115
%
116
%  A description of each parameter follows:
117
%
118
%    o image:  Method ReadPNMImage returns a pointer to the image after
119
%      reading.  A null image is returned if there is a memory shortage or
120
%      if the image cannot be read.
121
%
122
%    o image_info: Specifies a pointer to a ImageInfo structure.
123
%
124
%    o exception: return any errors or warnings in this structure.
125
%
126
%
127
*/
128
129
static unsigned int PNMInteger(Image *image,const unsigned int base)
130
235k
{
131
235k
  int
132
235k
    c;
133
134
235k
  unsigned long
135
235k
    value;
136
137
  /*
138
    Skip any leading whitespace.
139
  */
140
235k
  do
141
5.51M
  {
142
5.51M
    c=ReadBlobByte(image);
143
5.51M
    if (c == EOF)
144
13.0k
      return(0);
145
5.51M
  } while (!isdigit(c));
146
222k
  c &= 0xff;
147
222k
  if (base == 2)
148
15.2k
    return(c-'0');
149
  /*
150
    Evaluate number.
151
  */
152
206k
  value=0;
153
338k
  while(1)
154
338k
  {
155
338k
    value*=10;
156
338k
    value+=c-'0';
157
338k
    c=ReadBlobByte(image);
158
338k
    if ((c == EOF) || !(isdigit(c)))
159
206k
      break;
160
131k
    c &= 0xff;
161
131k
  }
162
163
206k
  return(value);
164
222k
}
165
166
static unsigned int PNMIntegerOrComment(Image *image,const unsigned int base)
167
67.4k
{
168
67.4k
  int
169
67.4k
    c;
170
171
67.4k
  unsigned long
172
67.4k
    value;
173
174
67.4k
  static const char P7Comment[] = "END_OF_COMMENTS\n";
175
176
  /*
177
    Skip any leading whitespace.
178
  */
179
67.4k
  do
180
3.57M
  {
181
3.57M
    c=ReadBlobByte(image);
182
3.57M
    if (c == EOF)
183
2.82k
      return(0);
184
3.57M
    c &= 0xff;
185
3.57M
    if (c == '#')
186
80.8k
      {
187
80.8k
        char
188
80.8k
          *comment;
189
190
80.8k
        const ImageAttribute
191
80.8k
          *comment_attr;
192
193
80.8k
        ExtendedSignedIntegralType
194
80.8k
          offset;
195
196
80.8k
        register char
197
80.8k
          *p,
198
80.8k
          *q;
199
200
80.8k
        size_t
201
80.8k
          length;
202
203
        /*
204
          Read comment.
205
        */
206
80.8k
        if ((comment_attr=GetImageAttribute(image,"comment")) != (const ImageAttribute *) NULL)
207
78.4k
          {
208
            /*
209
              If existing comment text length exceeds arbitrary limit,
210
              then do no further comment processing for this file.
211
            */
212
78.4k
            if (comment_attr->length > MaxTextExtent*2)
213
4.36k
              {
214
5.87M
                for ( ; (c != EOF) && (c != '\n'); )
215
5.87M
                  c=ReadBlobByte(image);
216
4.36k
                return 0;
217
4.36k
              }
218
78.4k
          }
219
76.4k
        length=MaxTextExtent;
220
76.4k
        comment=MagickAllocateResourceLimitedMemory(char *,length+sizeof(P7Comment));
221
76.4k
        p=comment;
222
76.4k
        offset=p-comment;
223
76.4k
        if (comment != (char *) NULL)
224
243M
          for ( ; (c != EOF) && (c != '\n'); p++)
225
243M
          {
226
243M
            if ((size_t) (p-comment) >= length)
227
117k
              {
228
117k
                size_t
229
117k
                  text_length;
230
231
117k
                char
232
117k
                  *new_comment;
233
234
117k
                text_length=(size_t) (p-comment);
235
117k
                length+=MaxTextExtent;
236
117k
                new_comment=MagickReallocateResourceLimitedMemory(char *,comment,length+sizeof(P7Comment));
237
117k
                if (new_comment == (char *) NULL)
238
0
                  {
239
0
                    MagickFreeResourceLimitedMemory(comment);
240
0
                    break;
241
0
                  }
242
117k
                comment=new_comment;
243
117k
                p=comment+text_length;
244
117k
              }
245
243M
            c=ReadBlobByte(image);
246
243M
            *p=c;
247
243M
            *(p+1)='\0';
248
243M
          }
249
76.4k
        if (comment == (char *) NULL)
250
0
          return(0);
251
76.4k
        q=comment+offset;
252
76.4k
        if (LocaleCompare(q,P7Comment) == 0)
253
0
          *q='\0';
254
        /*
255
          FIXME:
256
          Implicitly extend existing comment attribute since comments
257
          can span multiple lines.
258
        */
259
76.4k
        (void) SetImageAttribute(image,"comment",comment);
260
76.4k
        MagickFreeResourceLimitedMemory(comment);
261
76.4k
        continue;
262
76.4k
      }
263
3.57M
  } while (!isdigit(c));
264
60.2k
  if (base == 2)
265
0
    return(c-'0');
266
  /*
267
    Evaluate number.
268
  */
269
60.2k
  value=0;
270
60.2k
  do
271
83.2k
  {
272
83.2k
    value*=10;
273
83.2k
    value+=c-'0';
274
83.2k
    c=ReadBlobByte(image);
275
83.2k
    if (c == EOF)
276
531
      return(value);
277
83.2k
  }
278
60.2k
  while (isdigit(c));
279
59.6k
  return(value);
280
60.2k
}
281
282
#define ValidateScalingIndex(image, index, max)                         \
283
60.9k
  do                                                                    \
284
60.9k
    {                                                                   \
285
60.9k
      if (index > max)                                                  \
286
60.9k
        ThrowReaderException(CorruptImageError,CorruptImage, image);    \
287
59.8k
    } while (0)
288
289
#define ValidateScalingPixel(image, pixel, max)         \
290
13.5k
  do                                                    \
291
13.5k
    {                                                   \
292
13.5k
      ValidateScalingIndex(image, pixel.red, max);      \
293
13.5k
      ValidateScalingIndex(image, pixel.green, max);    \
294
13.3k
      ValidateScalingIndex(image, pixel.blue, max);     \
295
13.1k
    } while (0)
296
297
typedef enum
298
  {
299
    Undefined_PNM_Format,
300
    PBM_ASCII_Format, /* P1 */
301
    PGM_ASCII_Format, /* P2 */
302
    PPM_ASCII_Format, /* P3 */
303
    PBM_RAW_Format, /* P4 */
304
    PGM_RAW_Format, /* P5 */
305
    PPM_RAW_Format, /* P6 */
306
    PAM_Format, /* P7 */
307
    XV_332_Format /* P7 332 */
308
  } PNMSubformat;
309
310
static const char *PNMSubformatToString(const PNMSubformat f)
311
16.2k
{
312
16.2k
  const char *s = "unknown";
313
314
16.2k
  switch (f)
315
16.2k
    {
316
0
    case Undefined_PNM_Format:
317
0
      s = "Undefined";
318
0
      break;
319
969
    case PBM_ASCII_Format: /* P1 */
320
969
      s = "PBM ASCII";
321
969
      break;
322
2.42k
    case PGM_ASCII_Format: /* P2 */
323
2.42k
      s = "PGM ASCII";
324
2.42k
      break;
325
2.25k
    case PPM_ASCII_Format: /* P3 */
326
2.25k
      s = "PPM ASCII";
327
2.25k
      break;
328
2.29k
    case PBM_RAW_Format: /* P4 */
329
2.29k
      s = "PBM RAW";
330
2.29k
      break;
331
1.55k
    case PGM_RAW_Format: /* P5 */
332
1.55k
      s = "PGM RAW";
333
1.55k
      break;
334
2.73k
    case PPM_RAW_Format: /* P6 */
335
2.73k
      s = "PPM RAW";
336
2.73k
      break;
337
3.95k
    case PAM_Format: /* P7 */
338
3.95k
      s = "PAM";
339
3.95k
      break;
340
103
    case XV_332_Format: /* P7 332 */
341
103
      s = "XV 332 icon";
342
103
      break;
343
16.2k
    }
344
16.2k
  return s;
345
16.2k
}
346
347
#if defined(HAVE_OPENMP)
348
#  define PNMReadUseOpenMP 1
349
350
static int PNMReadThreads(const Image* image, const size_t bytes_per_row)
351
{
352
  const int omp_max_threads = omp_get_max_threads();
353
  int threads;
354
  ARG_NOT_USED(image);
355
  threads=(int)(Min(bytes_per_row/4096U,(size_t) Max(0,omp_max_threads)));
356
  if (0 == threads)
357
    threads=1;
358
  return threads;
359
}
360
#endif /* defined(HAVE_OPENMP) */
361
362
static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
363
25.3k
{
364
25.3k
  char
365
25.3k
    c;
366
367
25.3k
  PNMSubformat
368
25.3k
    format;
369
370
25.3k
  Image
371
25.3k
    *image;
372
373
25.3k
  long
374
25.3k
    y;
375
376
25.3k
  LongPixelPacket
377
25.3k
    pixel;
378
379
25.3k
  register IndexPacket
380
25.3k
    *indexes;
381
382
25.3k
  register unsigned long
383
25.3k
    i;
384
385
25.3k
  size_t
386
25.3k
    count,
387
25.3k
    number_pixels;
388
389
25.3k
  unsigned int
390
25.3k
    index,
391
25.3k
    bits_per_sample;
392
393
25.3k
  MagickPassFail
394
25.3k
    status;
395
396
25.3k
  unsigned int
397
25.3k
    max_value,
398
25.3k
    samples_per_pixel;
399
400
  /*
401
    Open image file.
402
  */
403
25.3k
  assert(image_info != (const ImageInfo *) NULL);
404
25.3k
  assert(image_info->signature == MagickSignature);
405
25.3k
  assert(exception != (ExceptionInfo *) NULL);
406
25.3k
  assert(exception->signature == MagickSignature);
407
25.3k
  image=AllocateImage(image_info);
408
25.3k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
409
25.3k
  if (status == False)
410
25.3k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
411
  /*
412
    Read PNM image.
413
  */
414
25.3k
  count=ReadBlob(image,1,(char *) &c);
415
25.3k
  do
416
25.3k
    {
417
      /*
418
        Initialize image structure.
419
      */
420
25.3k
      max_value=0;
421
25.3k
      bits_per_sample=0;
422
25.3k
      samples_per_pixel=0;
423
424
25.3k
      if (count == 0)
425
25.3k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
426
427
25.3k
      if (c != 'P')
428
81
        {
429
81
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Read %c rather than expected 'P'!",c);
430
81
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
431
0
        }
432
433
25.2k
      c=ReadBlobByte(image);
434
25.2k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"PNM Format Id: P%c",
435
25.2k
                            c);
436
437
25.2k
      switch (c)
438
25.2k
        {
439
1.67k
        case '1': format=PBM_ASCII_Format; break;
440
2.56k
        case '2': format=PGM_ASCII_Format; break;
441
2.34k
        case '3': format=PPM_ASCII_Format; break;
442
2.78k
        case '4': format=PBM_RAW_Format; break;
443
1.74k
        case '5': format=PGM_RAW_Format; break;
444
4.40k
        case '6': format=PPM_RAW_Format; break;
445
8.65k
        case '7':
446
8.65k
          {
447
8.65k
            if ((ReadBlobByte(image) == ' ') &&
448
8.65k
                (PNMIntegerOrComment(image,10) == 332))
449
578
              format=XV_332_Format;
450
8.07k
            else
451
8.07k
              format=PAM_Format;
452
8.65k
            break;
453
0
          }
454
1.13k
        default:
455
1.13k
          {
456
1.13k
            format=Undefined_PNM_Format;
457
1.13k
          }
458
25.2k
        }
459
460
25.2k
      if (PAM_Format == format)
461
8.07k
        {
462
          /*
463
            PAM header format
464
465
            P7
466
            WIDTH 227
467
            HEIGHT 149
468
            DEPTH 3
469
            MAXVAL 255
470
            TUPLTYPE RGB
471
            ENDHDR
472
          */
473
474
8.07k
          char
475
8.07k
            keyword[MaxTextExtent];
476
477
8.07k
          register char
478
8.07k
            *p;
479
480
8.07k
          int
481
8.07k
            c;
482
483
576k
          while (1)
484
576k
            {
485
576k
              p=keyword;
486
576k
              c=ReadBlobByte(image);
487
576k
              do
488
1.91M
                {
489
1.91M
                  if (isalnum(c) || ('#' == c))
490
1.90M
                    if ((p-keyword) < (MaxTextExtent-1))
491
1.90M
                      {
492
1.90M
                        *p++=c;
493
1.90M
                        if ('#' == c)
494
345k
                          break;
495
1.90M
                      }
496
1.57M
                  c=ReadBlobByte(image);
497
1.57M
                } while (isalnum(c) || ('#' == c));
498
0
              *p='\0';
499
500
576k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
501
576k
                                    "Keyword \"%s\"",keyword);
502
576k
              if ((EOF == c) || (LocaleCompare(keyword,"ENDHDR") == 0))
503
3.17k
                {
504
3.17k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
505
3.17k
                                        "Exiting header!");
506
3.17k
                  break;
507
3.17k
                }
508
573k
              else if (LocaleCompare(keyword,"HEIGHT") == 0)
509
49.2k
                {
510
49.2k
                  image->rows=PNMIntegerOrComment(image,10);
511
49.2k
                }
512
524k
              else if (LocaleCompare(keyword,"WIDTH") == 0)
513
40.2k
                {
514
40.2k
                  image->columns=PNMInteger(image,10);
515
40.2k
                }
516
484k
              else if (LocaleCompare(keyword,"DEPTH") == 0)
517
47.5k
                {
518
47.5k
                  samples_per_pixel=PNMInteger(image,10);
519
47.5k
                }
520
436k
              else if (LocaleCompare(keyword,"MAXVAL") == 0)
521
35.1k
                {
522
35.1k
                  max_value=PNMInteger(image,10);
523
35.1k
                }
524
401k
              else if (LocaleCompare(keyword,"TUPLTYPE") == 0)
525
51.7k
                {
526
                  /* Skip white space */
527
51.7k
                  do
528
61.7k
                    {
529
61.7k
                      c=ReadBlobByte(image);
530
61.7k
                    } while (isspace(c) && (EOF != c));
531
51.7k
                  if (EOF == c)
532
83
                    break;
533
                  /* Tupletype argument */
534
51.6k
                  p=keyword;
535
51.6k
                  do
536
108M
                    {
537
108M
                      if ((p-keyword) < (MaxTextExtent-1))
538
17.1M
                        *p++=c;
539
108M
                      c=ReadBlobByte(image);
540
108M
                    } while (('\n' != c) && (EOF != c));
541
51.6k
                  *p='\0';
542
51.6k
                  if (EOF == c)
543
316
                    break;
544
51.3k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
545
51.3k
                                        "TUPLTYPE \"%s\"",keyword);
546
51.3k
                  if (LocaleNCompare(keyword,"BLACKANDWHITE",13) == 0)
547
1.25k
                    {
548
1.25k
                      image->colorspace=GRAYColorspace;
549
1.25k
                      image->is_monochrome=MagickTrue;
550
1.25k
                    }
551
50.0k
                  else if (LocaleNCompare(keyword,"CMYK",4) == 0)
552
16.0k
                    {
553
16.0k
                      image->colorspace=CMYKColorspace;
554
16.0k
                    }
555
34.0k
                  else if (LocaleNCompare(keyword,"GRAYSCALE",9) == 0)
556
1.61k
                    {
557
1.61k
                      image->colorspace=GRAYColorspace;
558
1.61k
                    }
559
32.4k
                  else if (LocaleNCompare(keyword,"RGB",3) == 0)
560
237
                    {
561
237
                    }
562
563
                  /*
564
                    Check for alpha flag.
565
                  */
566
51.3k
                  count=strlen(keyword);
567
51.3k
                  if ((count > 6) && (LocaleNCompare(keyword+count-6,"_ALPHA",6) == 0))
568
15.1k
                    {
569
15.1k
                      image->matte=MagickTrue;
570
15.1k
                    }
571
51.3k
                }
572
349k
              else if (LocaleNCompare(keyword,"#",1) == 0)
573
345k
                {
574
                  /* Skip leading white space */
575
345k
                  do
576
596k
                    {
577
596k
                      c=ReadBlobByte(image);
578
596k
                    } while (isspace(c) && (EOF != c));
579
345k
                  if (EOF == c)
580
181
                    break;
581
582
                  /* Comment */
583
345k
                  p=keyword;
584
143M
                  while ((p-keyword) < (MaxTextExtent-2))
585
142M
                    {
586
142M
                      *p++=c;
587
142M
                      c=ReadBlobByte(image);
588
142M
                      if (c == '\n')
589
280k
                        {
590
280k
                          *p++=c;
591
280k
                          break;
592
280k
                        }
593
142M
                      if (c == EOF)
594
512
                        break;
595
142M
                    }
596
345k
                  *p='\0';
597
                  /*
598
                    FIXME:
599
                    Implicitly extend existing comment attribute since comments
600
                    can span multiple lines.
601
                  */
602
345k
                  (void) SetImageAttribute(image,"comment",keyword);
603
345k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
604
345k
                                        "Comment: \"%s\"",keyword);
605
345k
                }
606
4.31k
              else
607
4.31k
                {
608
                  /* Unknown! */
609
4.31k
                  do
610
95.6M
                    {
611
95.6M
                      c=ReadBlobByte(image);
612
95.6M
                    } while (('\n' != c) && (EOF != c));
613
4.31k
                  break;
614
4.31k
                }
615
576k
            }
616
8.07k
        }
617
17.2k
      else
618
17.2k
        {
619
          /*
620
            PNM header type format
621
622
            P1
623
            # feep.pbm
624
            24 7
625
626
            P3
627
            # feep.ppm
628
            4 4
629
            15
630
          */
631
17.2k
          image->columns=PNMIntegerOrComment(image,10);
632
17.2k
          image->rows=PNMInteger(image,10);
633
634
17.2k
          if ((format == PBM_ASCII_Format) || (format == PBM_RAW_Format))
635
4.46k
            max_value=1;  /* bitmap */
636
12.7k
          else
637
12.7k
            max_value=PNMInteger(image,10);
638
639
17.2k
          switch (format)
640
17.2k
            {
641
1.67k
            case PBM_ASCII_Format:
642
4.46k
            case PBM_RAW_Format:
643
7.02k
            case PGM_ASCII_Format:
644
8.76k
            case PGM_RAW_Format:
645
9.34k
            case XV_332_Format:
646
9.34k
              {
647
9.34k
                samples_per_pixel=1;
648
9.34k
                break;
649
8.76k
              }
650
2.34k
            case PPM_ASCII_Format:
651
6.74k
            case PPM_RAW_Format:
652
6.74k
              {
653
6.74k
                samples_per_pixel=3;
654
6.74k
                break;
655
2.34k
              }
656
1.13k
            default:
657
1.13k
              {
658
1.13k
              }
659
17.2k
            }
660
17.2k
        }
661
662
25.2k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Dimensions: %lux%lu",
663
25.2k
                            image->columns,image->rows);
664
25.2k
      if ((image->columns == 0) || (image->rows == 0))
665
17.9k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
666
667
17.9k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Max Value: %u",
668
17.9k
                            max_value);
669
17.9k
      if ((max_value == 0) || (max_value > 4294967295U))
670
17.7k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
671
672
17.7k
      if ((format == XV_332_Format) && (max_value != 255))
673
17.3k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
674
675
17.3k
      bits_per_sample=0;
676
17.3k
      if (max_value <= 1)
677
7.77k
        bits_per_sample=1;
678
9.54k
      else if (max_value <= 255U)
679
5.66k
        bits_per_sample=8;
680
3.88k
      else if (max_value <= 65535U)
681
2.21k
        bits_per_sample=16;
682
1.67k
      else if (max_value <= 4294967295U)
683
1.67k
        bits_per_sample=32;
684
685
17.3k
      image->depth=Min(bits_per_sample,QuantumDepth);
686
687
17.3k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image Depth: %u",
688
17.3k
                            image->depth);
689
17.3k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Samples Per Pixel: %u",
690
17.3k
                            samples_per_pixel);
691
17.3k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Bits Per Sample: %u",
692
17.3k
                            bits_per_sample);
693
694
17.3k
      if (EOFBlob(image))
695
4.81k
        ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
696
17.3k
                       image->filename);
697
698
17.3k
      if ((1 == samples_per_pixel) && (max_value < MaxColormapSize) &&
699
17.3k
          ((size_t) image->columns*image->rows >= max_value))
700
7.23k
        {
701
7.23k
          image->storage_class=PseudoClass;
702
7.23k
          image->colors=
703
7.23k
            max_value >= MaxColormapSize ? MaxColormapSize : max_value+1;
704
7.23k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colors: %u",
705
7.23k
                                image->colors);
706
7.23k
        }
707
17.3k
      number_pixels=MagickArraySize(image->columns,image->rows);
708
17.3k
      if (number_pixels == 0)
709
17.3k
        ThrowReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
710
17.3k
      if (image->storage_class == PseudoClass)
711
7.23k
        {
712
          /*
713
            Create colormap.
714
          */
715
7.23k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
716
7.23k
                                "Allocating colormap with %u colors",
717
7.23k
                                image->colors);
718
7.23k
          if (!AllocateImageColormap(image,image->colors))
719
0
            ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
720
7.23k
                                 image);
721
7.23k
          if ((format == XV_332_Format) && (image->colors == 256))
722
97
            {
723
              /*
724
                Initialize 332 colormap.
725
              */
726
97
              i=0;
727
873
              for (pixel.red=0; pixel.red < 8; pixel.red++)
728
6.98k
                for (pixel.green=0; pixel.green < 8; pixel.green++)
729
31.0k
                  for (pixel.blue=0; pixel.blue < 4; pixel.blue++)
730
24.8k
                    {
731
24.8k
                      image->colormap[i].red=(Quantum)
732
24.8k
                        (((double) MaxRGB*pixel.red)/0x07+0.5);
733
24.8k
                      image->colormap[i].green=(Quantum)
734
24.8k
                        (((double) MaxRGB*pixel.green)/0x07+0.5);
735
24.8k
                      image->colormap[i].blue=(Quantum)
736
24.8k
                        (((double) MaxRGB*pixel.blue)/0x03+0.5);
737
24.8k
                      i++;
738
24.8k
                    }
739
97
            }
740
7.23k
        }
741
17.3k
      if (image_info->ping && (image_info->subrange != 0))
742
0
        if (image->scene >= (image_info->subimage+image_info->subrange-1))
743
0
          break;
744
745
17.3k
      if (CheckImagePixelLimits(image, exception) != MagickPass)
746
16.3k
        ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
747
748
      /*
749
        Convert PNM pixels to runlength-encoded MIFF packets.
750
      */
751
16.3k
      switch (format)
752
16.3k
        {
753
969
        case PBM_ASCII_Format:
754
969
          {
755
            /*
756
              Convert PBM image to pixel packets.
757
            */
758
969
            register unsigned long
759
969
              x;
760
761
969
            register PixelPacket
762
969
              *q;
763
764
969
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
765
969
                                  "Reading %s pixel data",PNMSubformatToString(format));
766
10.1k
            for (y=0; y < (long) image->rows; y++)
767
10.0k
              {
768
10.0k
                q=SetImagePixels(image,0,y,image->columns,1);
769
10.0k
                if (q == (PixelPacket *) NULL)
770
0
                  break;
771
10.0k
                indexes=AccessMutableIndexes(image);
772
25.2k
                for (x=0; x < image->columns; x++)
773
16.0k
                  {
774
16.0k
                    index=!PNMInteger(image,2);
775
16.0k
                    if (EOFBlob(image))
776
801
                      break;
777
15.2k
                    VerifyColormapIndex(image,index);
778
15.2k
                    indexes[x]=index;
779
15.2k
                    *q++=image->colormap[index];
780
15.2k
                  }
781
10.0k
                if (!SyncImagePixels(image))
782
0
                  break;
783
10.0k
                if (image->previous == (Image *) NULL)
784
10.0k
                  if (QuantumTick(y,image->rows))
785
6.27k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
786
6.27k
                                                LoadImageText,image->filename,
787
6.27k
                                                image->columns,image->rows))
788
0
                      break;
789
10.0k
                if (EOFBlob(image))
790
801
                  break;
791
10.0k
              }
792
969
            image->is_grayscale=MagickTrue;
793
969
            image->is_monochrome=MagickTrue;
794
969
            if (EOFBlob(image))
795
801
              ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
796
969
                             image->filename);
797
969
            break;
798
0
          }
799
2.42k
        case PGM_ASCII_Format:
800
2.42k
          {
801
            /*
802
              Convert PGM image to pixel packets.
803
            */
804
2.42k
            register unsigned long
805
2.42k
              x;
806
807
2.42k
            register PixelPacket
808
2.42k
              *q;
809
810
2.42k
            unsigned long
811
2.42k
              intensity;
812
813
2.42k
            MagickBool
814
2.42k
              is_grayscale,
815
2.42k
              is_monochrome;
816
817
2.42k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
818
2.42k
                                  "Reading %s pixel data",PNMSubformatToString(format));
819
2.42k
            is_grayscale=MagickTrue;
820
2.42k
            is_monochrome=MagickTrue;
821
11.4k
            for (y=0; y < (long) image->rows; y++)
822
11.3k
              {
823
11.3k
                q=SetImagePixels(image,0,y,image->columns,1);
824
11.3k
                if (q == (PixelPacket *) NULL)
825
0
                  break;
826
11.3k
                if (image->storage_class == PseudoClass)
827
7.52k
                  {
828
                    /*
829
                      PseudoClass
830
                    */
831
7.52k
                    indexes=AccessMutableIndexes(image);
832
18.4k
                    for (x=0; x < image->columns; x++)
833
12.1k
                      {
834
12.1k
                        intensity=PNMInteger(image,10);
835
12.1k
                        ValidateScalingIndex(image, intensity, max_value);
836
11.8k
                        if (EOFBlob(image))
837
983
                          break;
838
10.8k
                        index=intensity;
839
10.8k
                        VerifyColormapIndex(image,index);
840
10.8k
                        indexes[x]=index;
841
10.8k
                        *q=image->colormap[index];
842
10.8k
                        is_monochrome &= IsMonochrome(*q);
843
10.8k
                        q++;
844
10.8k
                      }
845
7.52k
                  }
846
3.82k
                else
847
3.82k
                  {
848
                    /*
849
                      DirectClass
850
                    */
851
11.6k
                    for (x=0; x < image->columns; x++)
852
8.83k
                      {
853
8.83k
                        intensity=PNMInteger(image,10);
854
8.83k
                        ValidateScalingIndex(image, intensity, max_value);
855
8.66k
                        if (EOFBlob(image))
856
850
                          break;
857
7.81k
                        intensity=ScaleAnyToQuantum(intensity, max_value);
858
7.81k
                        q->red=q->green=q->blue=intensity;
859
7.81k
                        is_monochrome &= IsMonochrome(*q);
860
7.81k
                        q++;
861
7.81k
                      }
862
3.82k
                  }
863
10.8k
                if (EOFBlob(image))
864
1.83k
                  break;
865
9.04k
                if (!SyncImagePixels(image))
866
0
                  break;
867
9.04k
                if (image->previous == (Image *) NULL)
868
9.04k
                  if (QuantumTick(y,image->rows))
869
6.27k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
870
6.27k
                                                LoadImageText,image->filename,
871
6.27k
                                                image->columns,image->rows))
872
0
                      break;
873
9.04k
              }
874
1.94k
            image->is_monochrome=is_monochrome;
875
1.94k
            image->is_grayscale=is_grayscale;
876
1.94k
            if (EOFBlob(image))
877
1.83k
              ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
878
1.94k
                             image->filename);
879
1.94k
            break;
880
2.42k
          }
881
2.25k
        case PPM_ASCII_Format:
882
2.25k
          {
883
            /*
884
              Convert PNM image to pixel packets.
885
            */
886
2.25k
            register unsigned long
887
2.25k
              x;
888
889
2.25k
            register PixelPacket
890
2.25k
              *q;
891
892
2.25k
            MagickBool
893
2.25k
              is_grayscale,
894
2.25k
              is_monochrome;
895
896
2.25k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
897
2.25k
                                  "Reading %s pixel data",PNMSubformatToString(format));
898
2.25k
            is_grayscale=MagickTrue;
899
2.25k
            is_monochrome=MagickTrue;
900
9.70k
            for (y=0; y < (long) image->rows; y++)
901
9.61k
              {
902
9.61k
                q=SetImagePixels(image,0,y,image->columns,1);
903
9.61k
                if (q == (PixelPacket *) NULL)
904
0
                  break;
905
22.5k
                for (x=0; x < image->columns; x++)
906
15.0k
                  {
907
15.0k
                    pixel.red=PNMInteger(image,10);
908
15.0k
                    pixel.green=PNMInteger(image,10);
909
15.0k
                    pixel.blue=PNMInteger(image,10);
910
15.0k
                    if (EOFBlob(image))
911
1.58k
                      break;
912
13.5k
                    ValidateScalingPixel(image, pixel, max_value);
913
12.9k
                    pixel.red=ScaleAnyToQuantum(pixel.red, max_value);
914
12.9k
                    pixel.green=ScaleAnyToQuantum(pixel.green, max_value);
915
12.9k
                    pixel.blue=ScaleAnyToQuantum(pixel.blue, max_value);
916
12.9k
                    q->red=(Quantum) pixel.red;
917
12.9k
                    q->green=(Quantum) pixel.green;
918
12.9k
                    q->blue=(Quantum) pixel.blue;
919
12.9k
                    is_monochrome &= IsMonochrome(*q);
920
12.9k
                    is_grayscale &= IsGray(*q);
921
12.9k
                    q++;
922
12.9k
                  }
923
9.02k
                if (EOFBlob(image))
924
1.58k
                  break;
925
7.44k
                if (!SyncImagePixels(image))
926
0
                  break;
927
7.44k
                if (image->previous == (Image *) NULL)
928
7.44k
                  if (QuantumTick(y,image->rows))
929
4.64k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
930
4.64k
                                                LoadImageText,image->filename,
931
4.64k
                                                image->columns,image->rows))
932
0
                      break;
933
7.44k
              }
934
1.67k
            image->is_monochrome=is_monochrome;
935
1.67k
            image->is_grayscale=is_grayscale;
936
1.67k
            if (EOFBlob(image))
937
1.58k
              ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
938
1.67k
                             image->filename);
939
1.67k
            break;
940
2.25k
          }
941
2.29k
        case PBM_RAW_Format:
942
3.84k
        case PGM_RAW_Format:
943
6.58k
        case PPM_RAW_Format:
944
10.5k
        case PAM_Format:
945
10.6k
        case XV_332_Format:
946
10.6k
          {
947
            /*
948
              Convert PBM/PGM/PPM/PAM/XV raw raster image to pixel packets.
949
            */
950
10.6k
            ImportPixelAreaOptions
951
10.6k
              import_options;
952
953
10.6k
            QuantumType
954
10.6k
              quantum_type;
955
956
10.6k
            size_t
957
10.6k
              bytes_per_row;
958
959
10.6k
            MagickBool
960
10.6k
              check_pixels,
961
10.6k
              is_grayscale,
962
10.6k
              is_monochrome,
963
10.6k
              use_scaling;
964
965
10.6k
            unsigned long
966
10.6k
              max_value_given_bits,
967
10.6k
              row_count=0;
968
969
10.6k
            ThreadViewDataSet
970
10.6k
              *scanline_set;
971
972
10.6k
            double
973
10.6k
              sample_scale;
974
975
10.6k
            unsigned int
976
10.6k
              sample_max;
977
978
#if defined(HAVE_OPENMP)
979
            int
980
              pnm_read_threads;
981
#endif
982
983
10.6k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
984
10.6k
                                  "Reading %s pixel data",PNMSubformatToString(format));
985
986
10.6k
            ImportPixelAreaOptionsInit(&import_options);
987
988
10.6k
            check_pixels=MagickTrue;
989
10.6k
            is_grayscale=MagickTrue;
990
10.6k
            is_monochrome=MagickTrue;
991
992
            /*
993
              Deduce correct import parameters.
994
            */
995
10.6k
            quantum_type=UndefinedQuantum;
996
10.6k
            import_options.grayscale_miniswhite=MagickFalse;
997
10.6k
            max_value_given_bits=MaxValueGivenBits(bits_per_sample);
998
10.6k
            if (max_value_given_bits == 0UL)
999
0
              {
1000
0
                ThrowException(exception,CorruptImageError,ImproperImageHeader,
1001
0
                               image->filename);
1002
0
                break;
1003
0
              }
1004
10.6k
            sample_max=RoundDoubleToQuantum((MaxRGBDouble*max_value)/max_value_given_bits);
1005
10.6k
            if (sample_max == 0U)
1006
0
              {
1007
0
                ThrowException(exception,CorruptImageError,ImproperImageHeader,
1008
0
                               image->filename);
1009
0
                break;
1010
0
              }
1011
10.6k
            sample_scale=MaxRGBDouble/sample_max;
1012
10.6k
            use_scaling=(MaxRGB != sample_max);
1013
10.6k
            bytes_per_row=0;
1014
1015
10.6k
            if (1 == samples_per_pixel)
1016
4.80k
              {
1017
4.80k
                if (1 == bits_per_sample)
1018
2.73k
                  {
1019
                    /* PBM */
1020
2.73k
                    import_options.grayscale_miniswhite=MagickTrue;
1021
2.73k
                    quantum_type=GrayQuantum;
1022
2.73k
                  }
1023
2.06k
                else
1024
2.06k
                  {
1025
                    /* PGM & XV_332 */
1026
2.06k
                    if ((XV_332_Format == format) && (image->storage_class == PseudoClass))
1027
97
                      {
1028
97
                        quantum_type=IndexQuantum;
1029
97
                      }
1030
1.96k
                    else
1031
1.96k
                      {
1032
1.96k
                        quantum_type=GrayQuantum;
1033
1.96k
                      }
1034
2.06k
                  }
1035
4.80k
              }
1036
5.84k
            else if (2 == samples_per_pixel && image->matte)
1037
650
              {
1038
650
                quantum_type=GrayAlphaQuantum;
1039
650
              }
1040
5.19k
            else if (3 == samples_per_pixel)
1041
2.83k
              {
1042
                /* PPM */
1043
2.83k
                quantum_type=RGBQuantum;
1044
2.83k
              }
1045
2.35k
            else if (4 == samples_per_pixel)
1046
1.24k
              {
1047
1.24k
                if (CMYKColorspace == image->colorspace)
1048
655
                  quantum_type=CMYKQuantum;
1049
594
                else
1050
594
                  quantum_type=RGBAQuantum;
1051
1.24k
              }
1052
1.11k
            else if (5 == samples_per_pixel)
1053
607
              {
1054
607
                if (CMYKColorspace == image->colorspace)
1055
593
                  quantum_type=CMYKAQuantum;
1056
607
              }
1057
1058
10.6k
            if (image->logging)
1059
10.6k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1060
10.6k
                                    "Import Quantum Type: %s",
1061
10.6k
                                    QuantumTypeToString(quantum_type));
1062
1063
10.6k
            samples_per_pixel=MagickGetQuantumSamplesPerPixel(quantum_type);
1064
10.6k
            if (image->logging)
1065
10.6k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1066
10.6k
                                    "Samples/Pixel: %u", samples_per_pixel);
1067
1068
10.6k
            if (1 == bits_per_sample)
1069
5.38k
              {
1070
                /* bytes_per_row=(((size_t) image->columns*samples_per_pixel+7) >> 3); */
1071
5.38k
                bytes_per_row=MagickArraySize(image->columns,samples_per_pixel);
1072
5.38k
                if (bytes_per_row)
1073
5.16k
                  bytes_per_row += 7;
1074
5.38k
                if (bytes_per_row)
1075
5.16k
                  bytes_per_row >>= 3;
1076
5.38k
              }
1077
5.25k
            else
1078
5.25k
              {
1079
5.25k
                bytes_per_row=MagickArraySize((((size_t) bits_per_sample+7)/8)*
1080
5.25k
                                              samples_per_pixel,image->columns);
1081
5.25k
              }
1082
1083
10.6k
            if (image->logging)
1084
10.6k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1085
10.6k
                                    "Bytes/Row: %" MAGICK_SIZE_T_F "u",
1086
10.6k
                                    (MAGICK_SIZE_T) bytes_per_row);
1087
1088
10.6k
            if (1 == samples_per_pixel)
1089
4.80k
              {
1090
4.80k
                check_pixels=MagickFalse;
1091
4.80k
              }
1092
10.6k
            if (GrayQuantum)
1093
10.6k
              {
1094
10.6k
                if (1 == bits_per_sample)
1095
5.38k
                  {
1096
5.38k
                    is_grayscale=MagickTrue;
1097
5.38k
                    is_monochrome=MagickTrue;
1098
5.38k
                  }
1099
5.25k
                else
1100
5.25k
                  {
1101
5.25k
                    is_grayscale=MagickTrue;
1102
5.25k
                    is_monochrome=MagickFalse;
1103
5.25k
                  }
1104
10.6k
              }
1105
1106
            /* Validate file size before allocating memory */
1107
10.6k
            if (BlobIsSeekable(image))
1108
10.6k
              {
1109
10.6k
                const magick_off_t file_size = GetBlobSize(image);
1110
10.6k
                const magick_off_t current_offset = TellBlob(image);
1111
10.6k
                if ((file_size > 0) &&
1112
10.6k
                    (current_offset > 0) &&
1113
10.6k
                    (file_size > current_offset))
1114
8.05k
                  {
1115
8.05k
                    const magick_off_t remaining = file_size-current_offset;
1116
8.05k
                    const magick_off_t needed = (magick_off_t) image->rows *
1117
8.05k
                      (magick_off_t) bytes_per_row;
1118
8.05k
                    if ((remaining < (magick_off_t) bytes_per_row) ||
1119
8.05k
                        (remaining < needed))
1120
228
                      {
1121
228
                        ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
1122
228
                                       image->filename);
1123
228
                        break;
1124
228
                      }
1125
8.05k
                  }
1126
10.6k
              }
1127
1128
#if defined(HAVE_OPENMP)
1129
            pnm_read_threads = PNMReadThreads(image,bytes_per_row);
1130
            if (image->logging)
1131
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1132
                                    "Using %d thread%s...", pnm_read_threads,
1133
                                    pnm_read_threads > 1 ? "s" : "");
1134
#endif
1135
10.4k
            scanline_set=AllocateThreadViewDataArray(image,exception,bytes_per_row,1);
1136
10.4k
            if (scanline_set == (ThreadViewDataSet *) NULL)
1137
9.89k
              ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1138
#if PNMReadUseOpenMP
1139
#  if defined(TUNE_OPENMP)
1140
#    pragma omp parallel for schedule(runtime) shared(is_grayscale,is_monochrome,row_count,status)
1141
#  else
1142
#    pragma omp parallel for num_threads(pnm_read_threads) schedule(static,1) shared(is_grayscale,is_monochrome,row_count,status)
1143
#  endif
1144
#endif
1145
833k
            for (y=0; y < (long) image->rows; y++)
1146
823k
              {
1147
823k
                register unsigned long
1148
823k
                  x;
1149
1150
823k
                register PixelPacket
1151
823k
                  *q = (PixelPacket *) NULL;
1152
1153
823k
                void
1154
823k
                  *pixels;
1155
1156
823k
                MagickBool
1157
823k
                  thread_status;
1158
1159
823k
                MagickBool
1160
823k
                  thread_is_grayscale,
1161
823k
                  thread_is_monochrome;
1162
1163
823k
                unsigned long
1164
823k
                  thread_row_count;
1165
1166
823k
                ImportPixelAreaInfo
1167
823k
                  import_info;
1168
1169
#if PNMReadUseOpenMP
1170
#  pragma omp critical (GM_ReadPNMImage)
1171
#endif
1172
823k
                thread_status=status;
1173
823k
                if (thread_status == MagickFail)
1174
196k
                  continue;
1175
1176
627k
                pixels=AccessThreadViewData(scanline_set);
1177
1178
#if PNMReadUseOpenMP
1179
#  pragma omp critical (GM_ReadPNMImage)
1180
#endif
1181
627k
                {
1182
627k
                  thread_is_grayscale=is_grayscale;
1183
627k
                  thread_is_monochrome=is_monochrome;
1184
1185
627k
                  if (ReadBlobZC(image,bytes_per_row,&pixels) != bytes_per_row)
1186
2.16k
                    thread_status=MagickFail;
1187
1188
627k
                  thread_row_count=row_count;
1189
627k
                  row_count++;
1190
1191
627k
                  if (image->previous == (Image *) NULL)
1192
627k
                    if (QuantumTick(thread_row_count,image->rows))
1193
171k
                      if (!MagickMonitorFormatted(thread_row_count,image->rows,
1194
171k
                                                  exception,LoadImageText,
1195
171k
                                                  image->filename,
1196
171k
                                                  image->columns,image->rows))
1197
0
                        thread_status=MagickFail;
1198
627k
                }
1199
1200
627k
                if (thread_status != MagickFail)
1201
625k
                  if ((q=SetImagePixels(image,0,thread_row_count,image->columns,1)) ==
1202
625k
                      (PixelPacket *) NULL)
1203
0
                    thread_status=MagickFail;
1204
1205
627k
                if (thread_status != MagickFail)
1206
625k
                  if (!ImportImagePixelArea(image,quantum_type,bits_per_sample,pixels,
1207
625k
                                            &import_options,&import_info))
1208
0
                    thread_status=MagickFail;
1209
                /*
1210
                  Scale sub-ranged pixels up to full range if necessary
1211
                */
1212
627k
                if ((thread_status != MagickFail) && (use_scaling))
1213
6.85M
                  for (x=0; x < image->columns; x++)
1214
6.75M
                    {
1215
6.75M
                      SetRedSample(&q[x],
1216
6.75M
                                   RoundDoubleToQuantum(sample_scale*
1217
6.75M
                                                        GetRedSample(&q[x])));
1218
6.75M
                      SetGreenSample(&q[x],
1219
6.75M
                                     RoundDoubleToQuantum(sample_scale*
1220
6.75M
                                                          GetGreenSample(&q[x])));
1221
6.75M
                      SetBlueSample(&q[x],
1222
6.75M
                                    RoundDoubleToQuantum(sample_scale*
1223
6.75M
                                                         GetBlueSample(&q[x])));
1224
6.75M
                      if (image->matte)
1225
711k
                        SetOpacitySample(&q[x],
1226
6.75M
                                         MaxRGB-
1227
6.75M
                                         RoundDoubleToQuantum(sample_scale*
1228
6.75M
                                                              (MaxRGB-
1229
6.75M
                                                               GetOpacitySample(&q[x]))));
1230
6.75M
                    }
1231
                /*
1232
                  For a DirectClass image, check all pixels for
1233
                  gray/monochrome status since this format is often
1234
                  used for input from Ghostscript, which may output
1235
                  bilevel or gray in an RGB format.  It is easier to
1236
                  check now while the pixels are still "hot" in
1237
                  memory.
1238
                */
1239
627k
                if (thread_status != MagickFail)
1240
625k
                  if (check_pixels)
1241
54.7k
                    if (thread_is_grayscale || thread_is_monochrome)
1242
208k
                      for (x=0; x < image->columns; x++)
1243
194k
                        {
1244
194k
                          thread_is_grayscale = thread_is_grayscale && IsGray(q[x]);
1245
194k
                          thread_is_monochrome = thread_is_monochrome && IsMonochrome(q[x]);
1246
194k
                          if (!thread_is_grayscale && !thread_is_monochrome)
1247
2.43k
                            break;
1248
194k
                        }
1249
1250
627k
                if (thread_status != MagickFail)
1251
625k
                  if (!SyncImagePixels(image))
1252
0
                    thread_status=MagickFail;
1253
1254
#if PNMReadUseOpenMP
1255
#  pragma omp critical (GM_ReadPNMImage)
1256
#endif
1257
627k
                {
1258
627k
                  if (thread_status == MagickFail)
1259
2.16k
                    status=MagickFail;
1260
1261
627k
                  if (!thread_is_grayscale)
1262
40.8k
                    is_grayscale=thread_is_grayscale;
1263
1264
627k
                  if (!thread_is_monochrome)
1265
128k
                    is_monochrome=thread_is_monochrome;
1266
627k
                }
1267
627k
              }
1268
9.89k
            DestroyThreadViewDataSet(scanline_set);
1269
9.89k
            image->is_monochrome=is_monochrome;
1270
9.89k
            image->is_grayscale=is_grayscale;
1271
9.89k
            if ((status == MagickFail) && (image->exception.severity))
1272
95
              CopyException(exception,&image->exception);
1273
9.89k
            if (EOFBlob(image))
1274
7.49k
              ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1275
7.49k
            break;
1276
9.89k
          }
1277
82
        default:
1278
82
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1279
16.3k
        }
1280
12.3k
      StopTimer(&image->timer);
1281
12.3k
      if (status ==MagickFail)
1282
0
        break;
1283
      /*
1284
        Proceed to next image.
1285
      */
1286
12.3k
      if (image_info->subrange != 0)
1287
12.3k
        if (image->scene >= (image_info->subimage+image_info->subrange-1))
1288
12.3k
          break;
1289
0
      if ((format == PBM_ASCII_Format) || (format == PGM_ASCII_Format) || (format == PPM_ASCII_Format))
1290
0
        do
1291
0
          {
1292
            /*
1293
              Skip to end of line.
1294
            */
1295
0
            count=ReadBlob(image,1,&c);
1296
0
            if (count == 0)
1297
0
              break;
1298
0
          } while (c != '\n');
1299
0
      count=ReadBlob(image,1,&c);
1300
0
      if ((count != 0) && (c == 'P'))
1301
0
        {
1302
          /*
1303
            Allocate next image structure.
1304
          */
1305
0
          AllocateNextImage(image_info,image);
1306
0
          if (image->next == (Image *) NULL)
1307
0
            {
1308
0
              DestroyImageList(image);
1309
0
              return((Image *) NULL);
1310
0
            }
1311
0
          image=SyncNextImageInList(image);
1312
0
          if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),
1313
0
                                      exception,LoadImagesText,
1314
0
                                      image->filename))
1315
0
            break;
1316
0
        }
1317
0
    } while ((count != 0) && (c == 'P'));
1318
12.3k
  while (image->previous != (Image *) NULL)
1319
0
    image=image->previous;
1320
12.3k
  CloseBlob(image);
1321
12.3k
  return(image);
1322
25.3k
}
1323

1324
/*
1325
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1326
%                                                                             %
1327
%                                                                             %
1328
%                                                                             %
1329
%   R e g i s t e r P N M I m a g e                                           %
1330
%                                                                             %
1331
%                                                                             %
1332
%                                                                             %
1333
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334
%
1335
%  Method RegisterPNMImage adds attributes for the PNM image format to
1336
%  the list of supported formats.  The attributes include the image format
1337
%  tag, a method to read and/or write the format, whether the format
1338
%  supports the saving of more than one frame to the same file or blob,
1339
%  whether the format supports native in-memory I/O, and a brief
1340
%  description of the format.
1341
%
1342
%  The format of the RegisterPNMImage method is:
1343
%
1344
%      RegisterPNMImage(void)
1345
%
1346
*/
1347
ModuleExport void RegisterPNMImage(void)
1348
10
{
1349
10
  MagickInfo
1350
10
    *entry;
1351
1352
10
  entry=SetMagickInfo("P7");
1353
10
  entry->decoder=(DecoderHandler) ReadPNMImage;
1354
10
  entry->encoder=(EncoderHandler) WritePNMImage;
1355
10
  entry->description="Xv thumbnail format";
1356
10
  entry->extension_treatment=IgnoreExtensionTreatment;
1357
10
  entry->module="PNM";
1358
10
  (void) RegisterMagickInfo(entry);
1359
1360
10
  entry=SetMagickInfo("PAM");
1361
10
  entry->decoder=(DecoderHandler) ReadPNMImage;
1362
10
  entry->encoder=(EncoderHandler) WritePNMImage;
1363
10
  entry->description="Portable Arbitrary Map format";
1364
10
  entry->module="PNM";
1365
10
  entry->coder_class=PrimaryCoderClass;
1366
10
  (void) RegisterMagickInfo(entry);
1367
1368
10
  entry=SetMagickInfo("PBM");
1369
10
  entry->decoder=(DecoderHandler) ReadPNMImage;
1370
10
  entry->encoder=(EncoderHandler) WritePNMImage;
1371
10
  entry->description="Portable bitmap format (black/white)";
1372
10
  entry->module="PNM";
1373
10
  entry->coder_class=PrimaryCoderClass;
1374
10
  (void) RegisterMagickInfo(entry);
1375
1376
10
  entry=SetMagickInfo("PGM");
1377
10
  entry->decoder=(DecoderHandler) ReadPNMImage;
1378
10
  entry->encoder=(EncoderHandler) WritePNMImage;
1379
10
  entry->description="Portable graymap format (gray scale)";
1380
10
  entry->module="PNM";
1381
10
  entry->coder_class=PrimaryCoderClass;
1382
10
  (void) RegisterMagickInfo(entry);
1383
1384
10
  entry=SetMagickInfo("PNM");
1385
10
  entry->decoder=(DecoderHandler) ReadPNMImage;
1386
10
  entry->encoder=(EncoderHandler) WritePNMImage;
1387
10
  entry->magick=(MagickHandler) IsPNM;
1388
10
  entry->description="Portable anymap";
1389
10
  entry->module="PNM";
1390
10
  entry->coder_class=PrimaryCoderClass;
1391
10
  (void) RegisterMagickInfo(entry);
1392
1393
10
  entry=SetMagickInfo("PPM");
1394
10
  entry->decoder=(DecoderHandler) ReadPNMImage;
1395
10
  entry->encoder=(EncoderHandler) WritePNMImage;
1396
10
  entry->description="Portable pixmap format (color)";
1397
10
  entry->module="PNM";
1398
10
  entry->coder_class=PrimaryCoderClass;
1399
10
  (void) RegisterMagickInfo(entry);
1400
1401
10
}
1402

1403
/*
1404
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1405
%                                                                             %
1406
%                                                                             %
1407
%                                                                             %
1408
%   U n r e g i s t e r P N M I m a g e                                       %
1409
%                                                                             %
1410
%                                                                             %
1411
%                                                                             %
1412
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413
%
1414
%  Method UnregisterPNMImage removes format registrations made by the
1415
%  PNM module from the list of supported formats.
1416
%
1417
%  The format of the UnregisterPNMImage method is:
1418
%
1419
%      UnregisterPNMImage(void)
1420
%
1421
*/
1422
ModuleExport void UnregisterPNMImage(void)
1423
0
{
1424
0
  (void) UnregisterMagickInfo("P7");
1425
0
  (void) UnregisterMagickInfo("PAM");
1426
0
  (void) UnregisterMagickInfo("PBM");
1427
0
  (void) UnregisterMagickInfo("PGM");
1428
0
  (void) UnregisterMagickInfo("PNM");
1429
0
  (void) UnregisterMagickInfo("PPM");
1430
0
}
1431

1432
/*
1433
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434
%                                                                             %
1435
%                                                                             %
1436
%                                                                             %
1437
%   W r i t e P N M I m a g e                                                 %
1438
%                                                                             %
1439
%                                                                             %
1440
%                                                                             %
1441
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1442
%
1443
%  Procedure WritePNMImage writes an image to a file in the PNM rasterfile
1444
%  format.
1445
%
1446
%  The format of the WritePNMImage method is:
1447
%
1448
%      unsigned int WritePNMImage(const ImageInfo *image_info,Image *image)
1449
%
1450
%  A description of each parameter follows.
1451
%
1452
%    o status: Method WritePNMImage return True if the image is written.
1453
%      False is returned is there is a memory shortage or if the image file
1454
%      fails to write.
1455
%
1456
%    o image_info: Specifies a pointer to a ImageInfo structure.
1457
%
1458
%    o image:  A pointer to an Image structure.
1459
%
1460
%
1461
*/
1462
static const char lut_255[][4] =
1463
{
1464
  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14",
1465
  "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27",
1466
  "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40",
1467
  "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53",
1468
  "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66",
1469
  "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1470
  "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92",
1471
  "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104",
1472
  "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115",
1473
  "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126",
1474
  "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137",
1475
  "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148",
1476
  "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1477
  "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170",
1478
  "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181",
1479
  "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192",
1480
  "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203",
1481
  "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214",
1482
  "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225",
1483
  "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236",
1484
  "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247",
1485
  "248", "249", "250", "251", "252", "253", "254", "255"
1486
};
1487
1488
0
#define AppendUnsignedCharValueToString(j,buffer,value) \
1489
0
{ \
1490
0
  const char *lut_entry=lut_255[value]; \
1491
0
  while(*lut_entry != '\0') \
1492
0
    { \
1493
0
      buffer[j++]=*lut_entry; \
1494
0
      lut_entry++; \
1495
0
    } \
1496
0
}
1497
1498
static unsigned int WritePNMImage(const ImageInfo *image_info,Image *image)
1499
6.87k
{
1500
6.87k
  char
1501
6.87k
    buffer[MaxTextExtent];
1502
1503
6.87k
  const ImageAttribute
1504
6.87k
    *attribute;
1505
1506
6.87k
  IndexPacket
1507
6.87k
    index;
1508
1509
6.87k
  PNMSubformat
1510
6.87k
    format;
1511
1512
6.87k
  unsigned int
1513
6.87k
    depth;
1514
1515
6.87k
  unsigned long
1516
6.87k
    y;
1517
1518
6.87k
  register const PixelPacket
1519
6.87k
    *p;
1520
1521
6.87k
  register const IndexPacket
1522
6.87k
    *indexes;
1523
1524
6.87k
  register unsigned long
1525
6.87k
    i,
1526
6.87k
    x;
1527
1528
6.87k
  unsigned int
1529
6.87k
    scene,
1530
6.87k
    status;
1531
1532
6.87k
  size_t
1533
6.87k
    image_list_length;
1534
1535
  /*
1536
    Open output image file.
1537
  */
1538
6.87k
  assert(image_info != (const ImageInfo *) NULL);
1539
6.87k
  assert(image_info->signature == MagickSignature);
1540
6.87k
  assert(image != (Image *) NULL);
1541
6.87k
  assert(image->signature == MagickSignature);
1542
6.87k
  image_list_length=GetImageListLength(image);
1543
6.87k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1544
6.87k
  if (status == MagickFail)
1545
6.87k
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
1546
6.87k
  scene=0;
1547
6.87k
  do
1548
6.87k
    {
1549
6.87k
      depth=(image->depth <= 8 ? 8 : image->depth <= 16 ? 16 : 32);
1550
1551
      /*
1552
        Write PNM file header.
1553
      */
1554
6.87k
      format=Undefined_PNM_Format;
1555
6.87k
      if (LocaleCompare(image_info->magick,"P7") == 0)
1556
1.05k
        {
1557
1.05k
          format=XV_332_Format;
1558
1.05k
        }
1559
5.82k
      else if (LocaleCompare(image_info->magick,"PPM") == 0)
1560
1.06k
        {
1561
1.06k
          format=PPM_RAW_Format;
1562
1.06k
        }
1563
4.75k
      else if (LocaleCompare(image_info->magick,"PGM") == 0)
1564
1.09k
        {
1565
1.09k
          format=PGM_RAW_Format;
1566
1.09k
        }
1567
3.66k
      else if (LocaleCompare(image_info->magick,"PBM") == 0)
1568
1.14k
        {
1569
1.14k
          format=PBM_RAW_Format;
1570
1.14k
        }
1571
2.52k
      else if (LocaleCompare(image_info->magick,"PAM") == 0)
1572
1.30k
        {
1573
1.30k
          format=PAM_Format;
1574
1.30k
        }
1575
1.22k
      else /* PNM auto format */
1576
1.22k
        {
1577
1.22k
          ImageCharacteristics
1578
1.22k
            characteristics;
1579
1580
          /*
1581
            Make sure that image is in an RGB type space.
1582
          */
1583
1.22k
          (void) TransformColorspace(image,RGBColorspace);
1584
1585
          /*
1586
            Analyze image to be written.
1587
          */
1588
1.22k
          if (!GetImageCharacteristics(image,&characteristics,
1589
1.22k
                                       (OptimizeType == image_info->type),
1590
1.22k
                                       &image->exception))
1591
0
            {
1592
0
              CloseBlob(image);
1593
0
              return MagickFail;
1594
0
            }
1595
1596
1.22k
          if ((characteristics.monochrome) &&
1597
1.22k
              (image_info->type != GrayscaleType) &&
1598
1.22k
              (image_info->type != GrayscaleMatteType) &&
1599
1.22k
              (image_info->type != TrueColorType) &&
1600
1.22k
              (image_info->type != TrueColorMatteType))
1601
333
            {
1602
              /* PBM */
1603
333
              format=PBM_RAW_Format;
1604
333
            }
1605
890
          else if ((characteristics.grayscale) &&
1606
890
                   (image_info->type != TrueColorType) &&
1607
890
                   (image_info->type != TrueColorMatteType))
1608
236
            {
1609
              /* PGM */
1610
236
              format=PGM_RAW_Format;
1611
236
            }
1612
654
          else
1613
654
            {
1614
              /* PPM */
1615
654
              format=PPM_RAW_Format;
1616
654
            }
1617
1.22k
        }
1618
1619
      /*
1620
        Check if ASCII subformat is requested.
1621
      */
1622
6.87k
      if ((PBM_RAW_Format == format) || (PGM_RAW_Format == format) | (PPM_RAW_Format == format))
1623
4.51k
        {
1624
4.51k
          MagickBool
1625
4.51k
            ascii = MagickFalse;
1626
1627
          /*
1628
            If quality is set to zero or "pnm:ascii" is defined, then
1629
            select an ASCII subformat.
1630
          */
1631
4.51k
          if (image_info->quality == 0)
1632
0
            ascii=MagickTrue;
1633
4.51k
          else if ((AccessDefinition(image_info,"pnm","ascii")))
1634
0
            ascii=MagickTrue;
1635
1636
4.51k
          if (ascii)
1637
0
            {
1638
0
              if (PBM_RAW_Format == format)
1639
0
                format=PBM_ASCII_Format;
1640
0
              else if (PGM_RAW_Format == format)
1641
0
                format=PGM_ASCII_Format;
1642
0
              else if (PPM_RAW_Format == format)
1643
0
                format=PPM_ASCII_Format;
1644
0
            }
1645
4.51k
        }
1646
1647
6.87k
      {
1648
6.87k
        const char *header = "";
1649
6.87k
        switch (format)
1650
6.87k
          {
1651
0
          case Undefined_PNM_Format: break;
1652
0
          case PBM_ASCII_Format: header="P1"; break;
1653
0
          case PGM_ASCII_Format: header="P2"; break;
1654
0
          case PPM_ASCII_Format: header="P3"; break;
1655
1.47k
          case PBM_RAW_Format:   header="P4"; break;
1656
1.32k
          case PGM_RAW_Format:   header="P5"; break;
1657
1.71k
          case PPM_RAW_Format:   header="P6"; break;
1658
1.30k
          case PAM_Format:       header="P7"; break;
1659
1.05k
          case XV_332_Format:    header="P7 332"; break;
1660
6.87k
          }
1661
6.87k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Format Id: %s",
1662
6.87k
                              header);
1663
6.87k
        (void) WriteBlobString(image,header);
1664
6.87k
        (void) WriteBlobByte(image,'\n');
1665
6.87k
      }
1666
1667
0
      attribute=GetImageAttribute(image,"comment");
1668
6.87k
      if (attribute != (const ImageAttribute *) NULL)
1669
1.65k
        {
1670
1.65k
          register char
1671
1.65k
            *av;
1672
1673
          /*
1674
            Write comments to file.
1675
          */
1676
1.65k
          (void) WriteBlobByte(image,'#');
1677
114M
          for (av=attribute->value; *av != '\0'; av++)
1678
114M
            {
1679
114M
              (void) WriteBlobByte(image,*av);
1680
114M
              if ((*av == '\n') && (*(av+1) != '\0'))
1681
48.7k
                (void) WriteBlobByte(image,'#');
1682
114M
            }
1683
1.65k
          (void) WriteBlobByte(image,'\n');
1684
1.65k
        }
1685
6.87k
      if ((PAM_Format != format) && (XV_332_Format != format))
1686
4.51k
        {
1687
4.51k
          FormatString(buffer,"%lu %lu\n",image->columns,image->rows);
1688
4.51k
          (void) WriteBlobString(image,buffer);
1689
4.51k
        }
1690
      /*
1691
        Write PNM raster pixels.
1692
      */
1693
6.87k
      switch (format)
1694
6.87k
        {
1695
0
        case PBM_ASCII_Format:
1696
0
          {
1697
0
            unsigned int
1698
0
              polarity;
1699
1700
0
            size_t
1701
0
              j;
1702
1703
            /*
1704
              Convert image to a PBM ASCII image.
1705
            */
1706
0
            (void) SetImageType(image,BilevelType);
1707
0
            polarity=PixelIntensityToQuantum(&image->colormap[0]) < (MaxRGB/2);
1708
0
            if (image->colors == 2)
1709
0
              polarity=PixelIntensityToQuantum(&image->colormap[0]) <
1710
0
                PixelIntensityToQuantum(&image->colormap[1]);
1711
0
            i=0;
1712
0
            j=0;
1713
0
            for (y=0; y < image->rows; y++)
1714
0
              {
1715
0
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1716
0
                if (p == (const PixelPacket *) NULL)
1717
0
                  {
1718
0
                    status=MagickFail;
1719
0
                    break;
1720
0
                  }
1721
0
                indexes=AccessImmutableIndexes(image);
1722
0
                for (x=0; x < image->columns; x++)
1723
0
                  {
1724
0
                    buffer[j++] = (indexes[x] == polarity ? '0' : '1');
1725
0
                    buffer[j++] = ' ';
1726
0
                    i++;
1727
0
                    if (i == 36)
1728
0
                      {
1729
0
                        buffer[j++] = '\n';
1730
0
                        i=0;
1731
0
                      }
1732
0
                    if (j+4 > sizeof(buffer))
1733
0
                      {
1734
0
                        status=(WriteBlob(image,j,buffer) == j);
1735
0
                        j=0;
1736
0
                        if (MagickFail == status)
1737
0
                          break;
1738
0
                      }
1739
0
                  }
1740
0
                if (image->previous == (Image *) NULL)
1741
0
                  if (QuantumTick(y,image->rows))
1742
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1743
0
                                                SaveImageText,image->filename,
1744
0
                                                image->columns,image->rows))
1745
0
                      {
1746
0
                        status=MagickFail;
1747
0
                        break;
1748
0
                      }
1749
0
                if (MagickFail == status)
1750
0
                  break;
1751
0
              }
1752
0
            if (MagickFail != status)
1753
0
              {
1754
0
                if (i != 0)
1755
0
                  buffer[j++] = '\n';
1756
0
                if (j > 0)
1757
0
                  status=(WriteBlob(image,j,buffer) == j);
1758
0
              }
1759
0
            break;
1760
0
          }
1761
0
        case PGM_ASCII_Format:
1762
0
          {
1763
            /*
1764
              Convert image to a PGM ASCII image.
1765
            */
1766
0
            size_t
1767
0
              j;
1768
1769
0
            unsigned int
1770
0
              value;
1771
1772
            /*
1773
              Make sure that image is in an RGB type space.
1774
            */
1775
0
            (void) TransformColorspace(image,RGBColorspace);
1776
1777
0
            i=0;
1778
0
            j=0;
1779
1780
0
            value=(depth <=8 ? 255U : depth <= 16 ? 65535U : 4294967295U);
1781
1782
0
            j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u\n",value);
1783
0
            for (y=0; y < image->rows; y++)
1784
0
              {
1785
0
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1786
0
                if (p == (const PixelPacket *) NULL)
1787
0
                  {
1788
0
                    status=MagickFail;
1789
0
                    break;
1790
0
                  }
1791
0
                for (x=0; x < image->columns; x++)
1792
0
                  {
1793
0
                    if (image->is_grayscale)
1794
0
                      index=p->red;
1795
0
                    else
1796
0
                      index=PixelIntensityToQuantum(p);
1797
0
                    if (depth <= 8)
1798
0
                      {
1799
                        /* Use LUT for speed */
1800
0
                        value=ScaleQuantumToChar(index);
1801
0
                        AppendUnsignedCharValueToString(j,buffer,value);
1802
0
                        buffer[j++] = ' ';
1803
0
                      }
1804
0
                    else if (depth <= 16)
1805
0
                      {
1806
0
                        value=ScaleQuantumToShort(index);
1807
0
                        j += snprintf(&buffer[j],(sizeof(buffer)-j)," %u",value);
1808
0
                      }
1809
0
                    else
1810
0
                      {
1811
0
                        value=ScaleQuantumToLong(index);
1812
0
                        j += snprintf(&buffer[j],(sizeof(buffer)-j)," %u",value);
1813
0
                      }
1814
1815
0
                    i++;
1816
0
                    if (i == 12)
1817
0
                      {
1818
0
                        buffer[j++] = '\n';
1819
0
                        i=0;
1820
0
                      }
1821
0
                    if (j+8 > sizeof(buffer))
1822
0
                      {
1823
0
                        status=(WriteBlob(image,j,buffer) == j);
1824
0
                        j=0;
1825
0
                        if (MagickFail == status)
1826
0
                          break;
1827
0
                      }
1828
0
                    p++;
1829
0
                  }
1830
0
                if (image->previous == (Image *) NULL)
1831
0
                  if (QuantumTick(y,image->rows))
1832
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1833
0
                                                SaveImageText,image->filename,
1834
0
                                                image->columns,image->rows))
1835
0
                      {
1836
0
                        status=MagickFail;
1837
0
                        break;
1838
0
                      }
1839
0
                if (MagickFail == status)
1840
0
                  break;
1841
0
              }
1842
0
            if (MagickFail != status)
1843
0
              {
1844
0
                if (i != 0)
1845
0
                  buffer[j++] = '\n';
1846
0
                if (j > 0)
1847
0
                  status=(WriteBlob(image,j,buffer) == j);
1848
0
              }
1849
0
            break;
1850
0
          }
1851
0
        case PPM_ASCII_Format:
1852
0
          {
1853
            /*
1854
              Convert image to a PPM ASCII image.
1855
            */
1856
0
            size_t
1857
0
              j;
1858
1859
0
            unsigned int
1860
0
              value;
1861
1862
            /*
1863
              Make sure that image is in an RGB type space.
1864
            */
1865
0
            (void) TransformColorspace(image,RGBColorspace);
1866
1867
0
            i=0;
1868
0
            j=0;
1869
1870
0
            value=(depth <=8 ? 255U : (depth <= 16 ? 65535U : 4294967295U));
1871
1872
0
            j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u\n",value);
1873
0
            for (y=0; y < image->rows; y++)
1874
0
              {
1875
0
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1876
0
                if (p == (const PixelPacket *) NULL)
1877
0
                  {
1878
0
                    status=MagickFail;
1879
0
                    break;
1880
0
                  }
1881
0
                for (x=0; x < image->columns; x++)
1882
0
                  {
1883
0
                    if (depth <= 8)
1884
0
                      {
1885
                        /* Use LUT for speed */
1886
0
                        value=ScaleQuantumToChar(p->red);
1887
0
                        AppendUnsignedCharValueToString(j,buffer,value);
1888
0
                        buffer[j++] = ' ';
1889
0
                        value=ScaleQuantumToChar(p->green);
1890
0
                        AppendUnsignedCharValueToString(j,buffer,value);
1891
0
                        buffer[j++] = ' ';
1892
0
                        value=ScaleQuantumToChar(p->blue);
1893
0
                        AppendUnsignedCharValueToString(j,buffer,value);
1894
0
                        buffer[j++] = ' ';
1895
0
                      }
1896
0
                    else if (depth <= 16)
1897
0
                      {
1898
0
                        j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u %u %u ",
1899
0
                                     ScaleQuantumToShort(p->red),
1900
0
                                     ScaleQuantumToShort(p->green),
1901
0
                                     ScaleQuantumToShort(p->blue));
1902
0
                      }
1903
0
                    else
1904
0
                      {
1905
0
                        j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u %u %u ",
1906
0
                                     (unsigned int) ScaleQuantumToLong(p->red),
1907
0
                                     (unsigned int) ScaleQuantumToLong(p->green),
1908
0
                                     (unsigned int) ScaleQuantumToLong(p->blue));
1909
0
                      }
1910
0
                    i++;
1911
0
                    if (i == 4)
1912
0
                      {
1913
0
                        buffer[j++] = '\n';
1914
0
                        i=0;
1915
0
                      }
1916
0
                    if (j+(8*3) > sizeof(buffer))
1917
0
                      {
1918
0
                        status=(WriteBlob(image,j,buffer) == j);
1919
0
                        j=0;
1920
0
                        if (MagickFail == status)
1921
0
                          break;
1922
0
                      }
1923
0
                    p++;
1924
0
                  }
1925
0
                if (image->previous == (Image *) NULL)
1926
0
                  if (QuantumTick(y,image->rows))
1927
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1928
0
                                                SaveImageText,image->filename,
1929
0
                                                image->columns,image->rows))
1930
0
                      {
1931
0
                        status=MagickFail;
1932
0
                        break;
1933
0
                      }
1934
0
                if (MagickFail == status)
1935
0
                  break;
1936
0
              }
1937
0
            if (MagickFail != status)
1938
0
              {
1939
0
                if (i != 0)
1940
0
                  buffer[j++] = '\n';
1941
0
                if (j > 0)
1942
0
                  status=(WriteBlob(image,j,buffer) == j);
1943
0
              }
1944
0
            break;
1945
0
          }
1946
1.47k
        case PBM_RAW_Format:
1947
2.80k
        case PGM_RAW_Format:
1948
4.51k
        case PPM_RAW_Format:
1949
5.82k
        case PAM_Format:
1950
5.82k
          {
1951
5.82k
            ExportPixelAreaOptions
1952
5.82k
              export_options;
1953
1954
5.82k
            size_t
1955
5.82k
              bytes_per_row;
1956
1957
5.82k
            QuantumType
1958
5.82k
              quantum_type;
1959
1960
5.82k
            unsigned int
1961
5.82k
              bits_per_sample,
1962
5.82k
              samples_per_pixel;
1963
1964
5.82k
            MagickBool
1965
5.82k
              grayscale_miniswhite=MagickFalse;
1966
1967
5.82k
            unsigned char
1968
5.82k
              *pixels;
1969
1970
            /*
1971
              Deduce correct export parameters.
1972
            */
1973
5.82k
            bits_per_sample=(depth <=8 ? 8 : (depth <= 16 ? 16 : 32));
1974
5.82k
            quantum_type=RGBQuantum;
1975
5.82k
            if (PBM_RAW_Format == format)
1976
1.47k
              {
1977
1.47k
                bits_per_sample=1;
1978
1.47k
                grayscale_miniswhite=MagickTrue;
1979
1.47k
                quantum_type=GrayQuantum;
1980
1.47k
              }
1981
4.34k
            else if (PGM_RAW_Format == format)
1982
1.32k
              {
1983
1.32k
                quantum_type=GrayQuantum;
1984
1.32k
              }
1985
3.02k
            else if (PPM_RAW_Format == format)
1986
1.71k
              {
1987
1.71k
                quantum_type=RGBQuantum;
1988
1.71k
              }
1989
1.30k
            else if (PAM_Format == format)
1990
1.30k
              {
1991
1.30k
                ImageCharacteristics
1992
1.30k
                  characteristics;
1993
1994
                /*
1995
                  Make sure image is of desired type.
1996
                */
1997
1.30k
                if (UndefinedType != image_info->type)
1998
0
                  SetImageType(image,image_info->type);
1999
2000
                /*
2001
                  Analyze the image to get its characteristics.
2002
                */
2003
1.30k
                if (!GetImageCharacteristics(image,&characteristics,
2004
1.30k
                                             (OptimizeType == image_info->type),
2005
1.30k
                                             &image->exception))
2006
0
                  {
2007
0
                    CloseBlob(image);
2008
0
                    return MagickFail;
2009
0
                  }
2010
2011
                /*
2012
                  Choose best encoding based on image characteristics.
2013
                */
2014
1.30k
                if (characteristics.cmyk)
2015
401
                  {
2016
401
                    if (image->matte)
2017
152
                      quantum_type=CMYKAQuantum;
2018
249
                    else
2019
249
                      quantum_type=CMYKQuantum;
2020
401
                  }
2021
901
                else if (characteristics.monochrome)
2022
344
                  {
2023
344
                    bits_per_sample=1;
2024
344
                    grayscale_miniswhite=MagickTrue;
2025
2026
344
                    if (image->matte)
2027
46
                      quantum_type=GrayAlphaQuantum;
2028
298
                    else
2029
298
                      quantum_type=GrayQuantum;
2030
344
                  }
2031
557
                else if (characteristics.grayscale)
2032
284
                  {
2033
284
                    if (image->matte)
2034
120
                      quantum_type=GrayAlphaQuantum;
2035
164
                    else
2036
164
                      quantum_type=GrayQuantum;
2037
284
                  }
2038
273
                else
2039
273
                  {
2040
273
                    if (image->matte)
2041
43
                      quantum_type=RGBAQuantum;
2042
230
                    else
2043
230
                      quantum_type=RGBQuantum;
2044
273
                  }
2045
1.30k
              }
2046
5.82k
            if (image->logging)
2047
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2048
0
                                    "Export Quantum Type: %s",
2049
0
                                    QuantumTypeToString(quantum_type));
2050
2051
5.82k
            samples_per_pixel=MagickGetQuantumSamplesPerPixel(quantum_type);
2052
5.82k
            if (image->logging)
2053
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2054
0
                                    "Samples/Pixel: %u", samples_per_pixel);
2055
2056
5.82k
            if (1 == bits_per_sample)
2057
1.81k
              {
2058
                /* bytes_per_row=(((size_t) image->columns*samples_per_pixel+7) >> 3); */
2059
1.81k
                bytes_per_row=MagickArraySize(image->columns,samples_per_pixel);
2060
1.81k
                if (bytes_per_row)
2061
1.81k
                  bytes_per_row += 7;
2062
1.81k
                if (bytes_per_row)
2063
1.81k
                  bytes_per_row >>= 3;
2064
1.81k
              }
2065
4.00k
            else
2066
4.00k
              {
2067
4.00k
                bytes_per_row=MagickArraySize((((size_t) bits_per_sample+7)/8)*
2068
4.00k
                                              samples_per_pixel,image->columns);
2069
4.00k
              }
2070
2071
5.82k
            if (image->logging)
2072
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2073
0
                                    "Bytes/Row: %" MAGICK_SIZE_T_F "u",
2074
0
                                    (MAGICK_SIZE_T) bytes_per_row);
2075
2076
5.82k
            ExportPixelAreaOptionsInit(&export_options);
2077
5.82k
            export_options.grayscale_miniswhite=grayscale_miniswhite;
2078
2079
            /*
2080
              Allocate memory for pixels.
2081
            */
2082
5.82k
            pixels=MagickAllocateResourceLimitedMemory(unsigned char *,bytes_per_row);
2083
5.82k
            if (pixels == (unsigned char *) NULL)
2084
0
              ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
2085
5.82k
                                   image);
2086
2087
            /*
2088
              Output header details
2089
            */
2090
5.82k
            if (PAM_Format == format)
2091
1.30k
              {
2092
                /*
2093
                  PAM header
2094
                */
2095
1.30k
                const char *tuple_type=NULL;
2096
2097
1.30k
                if (GrayQuantum == quantum_type)
2098
462
                  {
2099
462
                    if (1 == bits_per_sample)
2100
298
                      tuple_type="BLACKANDWHITE";
2101
164
                    else
2102
164
                      tuple_type="GRAYSCALE";
2103
462
                  }
2104
840
                else if (GrayAlphaQuantum == quantum_type)
2105
166
                  {
2106
166
                    if (1 == bits_per_sample)
2107
46
                      tuple_type="BLACKANDWHITE_ALPHA";
2108
120
                    else
2109
120
                      tuple_type="GRAYSCALE_ALPHA";
2110
166
                  }
2111
674
                else if (RGBQuantum == quantum_type)
2112
230
                  tuple_type="RGB";
2113
444
                else if (RGBAQuantum == quantum_type)
2114
43
                  tuple_type="RGB_ALPHA";
2115
401
                else if (CMYKQuantum == quantum_type)
2116
249
                  tuple_type="CMYK";
2117
152
                else if (CMYKAQuantum == quantum_type)
2118
152
                  tuple_type="CMYK_ALPHA";
2119
2120
1.30k
                FormatString(buffer,"WIDTH %lu\nHEIGHT %lu\nDEPTH %u"
2121
1.30k
                             "\nMAXVAL %lu\nTUPLTYPE %s\n",
2122
1.30k
                             image->columns,image->rows,samples_per_pixel,
2123
1.30k
                             MaxValueGivenBits(bits_per_sample),tuple_type);
2124
1.30k
                if (image->logging)
2125
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2126
0
                                        "PAM Header: WIDTH %lu, HEIGHT %lu, "
2127
0
                                        "DEPTH %u, MAXVAL %lu, TUPLTYPE %s",
2128
0
                                        image->columns,
2129
0
                                        image->rows,samples_per_pixel,
2130
0
                                        MaxValueGivenBits(bits_per_sample),
2131
0
                                        tuple_type);
2132
1.30k
                WriteBlobString(image,buffer);
2133
2134
1.30k
                (void) WriteBlobString(image,"ENDHDR\n");
2135
1.30k
              }
2136
4.51k
            else if ((PGM_RAW_Format == format) || (PPM_RAW_Format == format))
2137
3.04k
              {
2138
                /*
2139
                  PGM, PPM header
2140
                */
2141
3.04k
                FormatString(buffer,"%lu\n",MaxValueGivenBits(bits_per_sample));
2142
3.04k
                WriteBlobString(image,buffer);
2143
3.04k
              }
2144
2145
            /*
2146
              Output pixels
2147
            */
2148
436k
            for (y=0; y < image->rows; y++)
2149
431k
              {
2150
431k
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2151
431k
                if (p == (const PixelPacket *) NULL)
2152
0
                  break;
2153
431k
                if (ExportImagePixelArea(image,quantum_type,bits_per_sample,pixels,&export_options,0) == MagickFail)
2154
0
                  break;
2155
431k
                if (WriteBlob(image,bytes_per_row,(char *) pixels) != bytes_per_row)
2156
171
                  break;
2157
430k
                if (image->previous == (Image *) NULL)
2158
430k
                  if (QuantumTick(y,image->rows))
2159
118k
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2160
118k
                                                SaveImageText,image->filename,
2161
118k
                                                image->columns,image->rows))
2162
0
                      break;
2163
430k
              }
2164
5.82k
            MagickFreeResourceLimitedMemory(pixels);
2165
2166
5.82k
            break;
2167
5.82k
          }
2168
1.05k
        case XV_332_Format:
2169
1.05k
          {
2170
1.05k
            static const short int
2171
1.05k
              dither_red[2][16]=
2172
1.05k
              {
2173
1.05k
                {-16,  4, -1, 11,-14,  6, -3,  9,-15,  5, -2, 10,-13,  7, -4,  8},
2174
1.05k
                { 15, -5,  0,-12, 13, -7,  2,-10, 14, -6,  1,-11, 12, -8,  3, -9}
2175
1.05k
              },
2176
1.05k
              dither_green[2][16]=
2177
1.05k
                {
2178
1.05k
                  { 11,-15,  7, -3,  8,-14,  4, -2, 10,-16,  6, -4,  9,-13,  5, -1},
2179
1.05k
                  {-12, 14, -8,  2, -9, 13, -5,  1,-11, 15, -7,  3,-10, 12, -6,  0}
2180
1.05k
                },
2181
1.05k
                dither_blue[2][16]=
2182
1.05k
                  {
2183
1.05k
                    { -3,  9,-13,  7, -1, 11,-15,  5, -4,  8,-14,  6, -2, 10,-16,  4},
2184
1.05k
                    {  2,-10, 12, -8,  0,-12, 14, -6,  3, -9, 13, -7,  1,-11, 15, -5}
2185
1.05k
                  };
2186
2187
1.05k
                long
2188
1.05k
                  value;
2189
2190
1.05k
                Quantum
2191
1.05k
                  pixel;
2192
2193
1.05k
                unsigned short
2194
1.05k
                  *blue_map[2][16],
2195
1.05k
                  *green_map[2][16],
2196
1.05k
                  *red_map[2][16];
2197
2198
1.05k
                unsigned int
2199
1.05k
                  j;
2200
2201
                /*
2202
                  Allocate and initialize dither maps.
2203
                */
2204
1.05k
                memset(blue_map,0,sizeof(blue_map));
2205
1.05k
                memset(green_map,0,sizeof(green_map));
2206
1.05k
                memset(red_map,0,sizeof(red_map));
2207
3.17k
                for (i=0; i < 2; i++)
2208
36.0k
                  for (j=0; j < 16; j++)
2209
33.8k
                    {
2210
33.8k
                      red_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *,
2211
33.8k
                                                         256*sizeof(unsigned short));
2212
33.8k
                      green_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *,
2213
33.8k
                                                           256*sizeof(unsigned short));
2214
33.8k
                      blue_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *,
2215
33.8k
                                                          256*sizeof(unsigned short));
2216
33.8k
                      if ((red_map[i][j] == (unsigned short *) NULL) ||
2217
33.8k
                          (green_map[i][j] == (unsigned short *) NULL) ||
2218
33.8k
                          (blue_map[i][j] == (unsigned short *) NULL))
2219
0
                        {
2220
0
                          for (i=0; i < 2; i++)
2221
0
                            for (j=0; j < 16; j++)
2222
0
                              {
2223
0
                                MagickFreeResourceLimitedMemory(green_map[i][j]);
2224
0
                                MagickFreeResourceLimitedMemory(blue_map[i][j]);
2225
0
                                MagickFreeResourceLimitedMemory(red_map[i][j]);
2226
0
                              }
2227
0
                          ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
2228
0
                                               image);
2229
0
                        }
2230
33.8k
                    }
2231
                /*
2232
                  Initialize dither tables.
2233
                */
2234
3.17k
                for (i=0; i < 2; i++)
2235
36.0k
                  for (j=0; j < 16; j++)
2236
8.70M
                    for (x=0; x < 256; x++)
2237
8.67M
                      {
2238
8.67M
                        value=x-16;
2239
8.67M
                        if (x < 48)
2240
1.62M
                          value=x/2+8;
2241
8.67M
                        value+=dither_red[i][j];
2242
8.67M
                        red_map[i][j][x]=(unsigned short)
2243
8.67M
                          ((value < 0) ? 0 : (value > 255) ? 255 : value);
2244
8.67M
                        value=x-16;
2245
8.67M
                        if (x < 48)
2246
1.62M
                          value=x/2+8;
2247
8.67M
                        value+=dither_green[i][j];
2248
8.67M
                        green_map[i][j][x]=(unsigned short)
2249
8.67M
                          ((value < 0) ? 0 : (value > 255) ? 255 : value);
2250
8.67M
                        value=x-32;
2251
8.67M
                        if (x < 112)
2252
3.79M
                          value=x/2+24;
2253
8.67M
                        value+=2*dither_blue[i][j];
2254
8.67M
                        blue_map[i][j][x]=(unsigned short)
2255
8.67M
                          ((value < 0) ? 0 : (value > 255) ? 255 : value);
2256
8.67M
                      }
2257
                /*
2258
                  Write pixels.
2259
                */
2260
1.05k
                (void) WriteBlobString(image,"#END_OF_COMMENTS\n");
2261
1.05k
                FormatString(buffer,"%lu %lu 255\n",image->columns,image->rows);
2262
1.05k
                (void) WriteBlobString(image,buffer);
2263
1.05k
                i=0;
2264
1.05k
                j=0;
2265
123k
                for (y=0; y < image->rows; y++)
2266
122k
                  {
2267
122k
                    p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2268
122k
                    if (p == (const PixelPacket *) NULL)
2269
0
                      break;
2270
71.5M
                    for (x=0; x < image->columns; x++)
2271
71.3M
                      {
2272
71.3M
                        if (!image_info->dither)
2273
0
                          pixel=(Quantum) ((ScaleQuantumToChar(p->red) & 0xe0) |
2274
0
                                           ((ScaleQuantumToChar(p->green) & 0xe0) >> 3) |
2275
0
                                           ((ScaleQuantumToChar(p->blue) & 0xc0) >> 6));
2276
71.3M
                        else
2277
71.3M
                          pixel=(Quantum)
2278
71.3M
                            ((red_map[i][j][ScaleQuantumToChar(p->red)] & 0xe0) |
2279
71.3M
                             ((green_map[i][j][ScaleQuantumToChar(p->green)] & 0xe0) >> 3) |
2280
71.3M
                             ((blue_map[i][j][ScaleQuantumToChar(p->blue)] & 0xc0) >> 6));
2281
71.3M
                        (void) WriteBlobByte(image,pixel);
2282
71.3M
                        p++;
2283
71.3M
                        j++;
2284
71.3M
                        if (j == 16)
2285
4.46M
                          j=0;
2286
71.3M
                      }
2287
122k
                    i++;
2288
122k
                    if (i == 2)
2289
60.9k
                      i=0;
2290
122k
                    if (QuantumTick(y,image->rows))
2291
26.8k
                      if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2292
26.8k
                                                  SaveImageText,image->filename,
2293
26.8k
                                                  image->columns,image->rows))
2294
0
                        break;
2295
122k
                  }
2296
                /*
2297
                  Free allocated memory.
2298
                */
2299
3.17k
                for (i=0; i < 2; i++)
2300
36.0k
                  for (j=0; j < 16; j++)
2301
33.8k
                    {
2302
33.8k
                      MagickFreeResourceLimitedMemory(green_map[i][j]);
2303
33.8k
                      MagickFreeResourceLimitedMemory(blue_map[i][j]);
2304
33.8k
                      MagickFreeResourceLimitedMemory(red_map[i][j]);
2305
33.8k
                    }
2306
1.05k
                break;
2307
1.05k
          }
2308
0
        case Undefined_PNM_Format:
2309
0
          break;
2310
6.87k
        }
2311
6.87k
      if (image->next == (Image *) NULL)
2312
6.87k
        break;
2313
0
      image=SyncNextImageInList(image);
2314
0
      if (status != MagickFail)
2315
0
        status=MagickMonitorFormatted(scene++,image_list_length,
2316
0
                                      &image->exception,SaveImagesText,
2317
0
                                      image->filename);
2318
0
      if (status == MagickFail)
2319
0
        break;
2320
0
    } while (image_info->adjoin);
2321
6.87k
  if (image_info->adjoin)
2322
6.87k
    while (image->previous != (Image *) NULL)
2323
0
      image=image->previous;
2324
6.87k
  status &= CloseBlob(image);
2325
6.87k
  return(status);
2326
6.87k
}