Coverage Report

Created: 2026-04-01 07:49

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