Coverage Report

Created: 2026-07-25 07:06

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
494k
{
132
494k
  unsigned int
133
494k
    value;
134
135
494k
  int
136
494k
    c;
137
138
  /*
139
    Skip any leading whitespace.
140
  */
141
494k
  do
142
7.54M
    {
143
7.54M
      c=ReadBlobByte(image);
144
7.54M
      if (c == EOF)
145
59.3k
        {
146
59.3k
          *status=MagickFail;
147
59.3k
          return(0);
148
59.3k
        }
149
7.54M
    } while (!isdigit(c));
150
435k
  c &= 0xff;
151
435k
  if (base == 2)
152
12.2k
    {
153
12.2k
      if (c > '1')
154
3.06k
        {
155
3.06k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
156
3.06k
                                "ERROR: Unexpected character '%c' @%"
157
3.06k
                                MAGICK_OFF_F "d", c, TellBlob(image));
158
3.06k
          *status=MagickFail;
159
3.06k
          return(0);
160
3.06k
        }
161
9.16k
      return(c-'0');
162
12.2k
    }
163
  /*
164
    Evaluate number.
165
  */
166
423k
  value=0;
167
819k
  while(1)
168
819k
    {
169
819k
      unsigned int
170
819k
        old_value = value;
171
172
819k
      old_value=value;
173
819k
      value*=10;
174
819k
      value+=c-'0';
175
819k
      if (value < old_value)
176
6.82k
        {
177
6.82k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
178
6.82k
                                "ERROR: integer overflow (%u > %u) @%"
179
6.82k
                                MAGICK_OFF_F "d", old_value, value,
180
6.82k
                                TellBlob(image));
181
6.82k
          *status=MagickFail;
182
6.82k
          return(0);
183
6.82k
        }
184
812k
      c=ReadBlobByte(image);
185
812k
      if ((c == EOF) || !(isdigit(c)))
186
416k
        break;
187
396k
      c &= 0xff;
188
396k
    }
189
190
416k
  return(value);
191
423k
}
192
193
static unsigned int PNMIntegerOrComment(Image *image,const unsigned int base,MagickPassFail *status)
194
219k
{
195
219k
  unsigned int
196
219k
    value;
197
198
219k
  unsigned int
199
219k
    count = 0;
200
201
219k
  int
202
219k
    c;
203
204
219k
  static const char P7Comment[] = "END_OF_COMMENTS\n";
205
206
  /*
207
    Skip any leading whitespace.
208
  */
209
219k
  do
210
3.22M
    {
211
3.22M
      c=ReadBlobByte(image);
212
3.22M
      if (c == EOF)
213
15.9k
        return(0);
214
3.21M
      c &= 0xff;
215
3.21M
      if (c == '#')
216
83.8k
        {
217
83.8k
          char
218
83.8k
            *comment;
219
220
83.8k
          const ImageAttribute
221
83.8k
            *comment_attr;
222
223
83.8k
          ExtendedSignedIntegralType
224
83.8k
            offset;
225
226
83.8k
          register char
227
83.8k
            *p,
228
83.8k
            *q;
229
230
83.8k
          size_t
231
83.8k
            length;
232
233
          /*
234
            Read comment.
235
          */
236
83.8k
          if ((comment_attr=GetImageAttribute(image,"comment")) != (const ImageAttribute *) NULL)
237
79.0k
            {
238
              /*
239
                If existing comment text length exceeds arbitrary limit,
240
                then do no further comment processing for this file.
241
              */
242
79.0k
              if (comment_attr->length > MaxTextExtent*2)
243
3.21k
                {
244
7.22M
                  for ( ; (c != EOF) && (c != '\n'); )
245
7.22M
                    c=ReadBlobByte(image);
246
3.21k
                  return 0;
247
3.21k
                }
248
79.0k
            }
249
80.6k
          length=MaxTextExtent;
250
80.6k
          comment=MagickAllocateResourceLimitedMemory(char *,length+sizeof(P7Comment));
251
80.6k
          p=comment;
252
80.6k
          offset=p-comment;
253
80.6k
          if (comment != (char *) NULL)
254
171M
            for ( ; (c != EOF) && (c != '\n'); p++)
255
171M
              {
256
171M
                if ((size_t) (p-comment) >= length)
257
82.4k
                  {
258
82.4k
                    size_t
259
82.4k
                      text_length;
260
261
82.4k
                    char
262
82.4k
                      *new_comment;
263
264
82.4k
                    text_length=(size_t) (p-comment);
265
82.4k
                    length+=MaxTextExtent;
266
82.4k
                    new_comment=MagickReallocateResourceLimitedMemory(char *,comment,length+sizeof(P7Comment));
267
82.4k
                    if (new_comment == (char *) NULL)
268
0
                      {
269
0
                        MagickFreeResourceLimitedMemory(char *,comment);
270
0
                        break;
271
0
                      }
272
82.4k
                    comment=new_comment;
273
82.4k
                    p=comment+text_length;
274
82.4k
                  }
275
171M
                c=ReadBlobByte(image);
276
171M
                *p=c;
277
171M
                *(p+1)='\0';
278
171M
              }
279
80.6k
          if (comment == (char *) NULL)
280
0
            return(0);
281
80.6k
          q=comment+offset;
282
80.6k
          if (LocaleCompare(q,P7Comment) == 0)
283
208
            *q='\0';
284
          /*
285
            FIXME:
286
            Implicitly extend existing comment attribute since comments
287
            can span multiple lines.
288
          */
289
80.6k
          (void) SetImageAttribute(image,"comment",comment);
290
80.6k
          MagickFreeResourceLimitedMemory(char *,comment);
291
80.6k
          continue;
292
80.6k
        }
293
3.21M
    } 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
684k
  while(1)
312
684k
    {
313
684k
      unsigned int
314
684k
        old_value = value;
315
316
684k
      old_value=value;
317
684k
      value*=10;
318
684k
      value+=c-'0';
319
684k
      if (value < old_value)
320
3.43k
        {
321
3.43k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
322
3.43k
                                "ERROR: integer overflow (%u > %u) @%"
323
3.43k
                                MAGICK_OFF_F "d", old_value, value,
324
3.43k
                                TellBlob(image));
325
3.43k
          *status=MagickFail;
326
3.43k
          return(0);
327
3.43k
        }
328
681k
      c=ReadBlobByte(image);
329
681k
      if ((c == EOF) || !(isdigit(c)))
330
196k
        break;
331
484k
      count++;
332
484k
      c &= 0xff;
333
484k
    }
334
196k
  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
196k
  return(value);
352
200k
}
353
354
#define ValidateScalingIndex(image, index, max)                         \
355
81.6k
  do                                                                    \
356
81.6k
    {                                                                   \
357
81.6k
      if (index > max)                                                  \
358
81.6k
        ThrowReaderException(CorruptImageError,CorruptImage, image);    \
359
72.8k
    } while (0)
360
361
#define ValidateScalingPixel(image, pixel, max)         \
362
21.1k
  do                                                    \
363
21.1k
    {                                                   \
364
21.1k
      ValidateScalingIndex(image, pixel.red, max);      \
365
21.1k
      ValidateScalingIndex(image, pixel.green, max);    \
366
19.0k
      ValidateScalingIndex(image, pixel.blue, max);     \
367
16.5k
    } 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
60.2k
{
384
60.2k
  const char *s = "unknown";
385
386
60.2k
  switch (f)
387
60.2k
    {
388
0
    case Undefined_PNM_Format:
389
0
      s = "Undefined";
390
0
      break;
391
6.73k
    case PBM_ASCII_Format: /* P1 */
392
6.73k
      s = "PBM ASCII";
393
6.73k
      break;
394
9.60k
    case PGM_ASCII_Format: /* P2 */
395
9.60k
      s = "PGM ASCII";
396
9.60k
      break;
397
16.2k
    case PPM_ASCII_Format: /* P3 */
398
16.2k
      s = "PPM ASCII";
399
16.2k
      break;
400
3.27k
    case PBM_RAW_Format: /* P4 */
401
3.27k
      s = "PBM RAW";
402
3.27k
      break;
403
3.96k
    case PGM_RAW_Format: /* P5 */
404
3.96k
      s = "PGM RAW";
405
3.96k
      break;
406
16.3k
    case PPM_RAW_Format: /* P6 */
407
16.3k
      s = "PPM RAW";
408
16.3k
      break;
409
3.91k
    case PAM_Format: /* P7 */
410
3.91k
      s = "PAM";
411
3.91k
      break;
412
111
    case XV_332_Format: /* P7 332 */
413
111
      s = "XV 332 icon";
414
111
      break;
415
60.2k
    }
416
60.2k
  return s;
417
60.2k
}
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
207k
{
436
207k
  char
437
207k
    c;
438
439
207k
  PNMSubformat
440
207k
    format;
441
442
207k
  Image
443
207k
    *image;
444
445
207k
  long
446
207k
    y;
447
448
207k
  LongPixelPacket
449
207k
    pixel;
450
451
207k
  register IndexPacket
452
207k
    *indexes;
453
454
207k
  register unsigned long
455
207k
    i;
456
457
207k
  size_t
458
207k
    count,
459
207k
    number_pixels;
460
461
207k
  unsigned int
462
207k
    index,
463
207k
    bits_per_sample;
464
465
207k
  MagickPassFail
466
207k
    status;
467
468
207k
  unsigned int
469
207k
    max_value,
470
207k
    samples_per_pixel;
471
472
  /*
473
    Open image file.
474
  */
475
207k
  assert(image_info != (const ImageInfo *) NULL);
476
207k
  assert(image_info->signature == MagickSignature);
477
207k
  assert(exception != (ExceptionInfo *) NULL);
478
207k
  assert(exception->signature == MagickSignature);
479
207k
  image=AllocateImage(image_info);
480
207k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
481
207k
  if (status == MagickFail)
482
207k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
483
  /*
484
    Read PNM image.
485
  */
486
207k
  count=ReadBlob(image,1,(char *) &c);
487
207k
  do
488
207k
    {
489
      /*
490
        Initialize image structure.
491
      */
492
207k
      max_value=0;
493
207k
      bits_per_sample=0;
494
207k
      samples_per_pixel=0;
495
496
207k
      if (count == 0)
497
207k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
498
499
207k
      if (c != 'P')
500
66
        {
501
66
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Read %c rather than expected 'P'!",c);
502
66
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
503
0
        }
504
505
207k
      c=ReadBlobByte(image);
506
207k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"PNM Format Id: P%c",
507
207k
                            c);
508
509
207k
      switch (c)
510
207k
        {
511
19.4k
        case '1': format=PBM_ASCII_Format; break;
512
38.5k
        case '2': format=PGM_ASCII_Format; break;
513
27.3k
        case '3': format=PPM_ASCII_Format; break;
514
19.6k
        case '4': format=PBM_RAW_Format; break;
515
24.1k
        case '5': format=PGM_RAW_Format; break;
516
48.6k
        case '6': format=PPM_RAW_Format; break;
517
27.9k
        case '7':
518
27.9k
          {
519
27.9k
            if ((ReadBlobByte(image) == ' ') &&
520
9.50k
                (PNMIntegerOrComment(image,10,&status) == 332))
521
6.47k
              format=XV_332_Format;
522
21.4k
            else
523
21.4k
              format=PAM_Format;
524
27.9k
            break;
525
0
          }
526
1.38k
        default:
527
1.38k
          {
528
1.38k
            format=Undefined_PNM_Format;
529
1.38k
          }
530
207k
        }
531
532
207k
      if (status == MagickFail)
533
206k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
534
535
206k
      if (PAM_Format == format)
536
21.3k
        {
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.3k
          char
550
21.3k
            keyword[MaxTextExtent];
551
552
21.3k
          register char
553
21.3k
            *p;
554
555
21.3k
          int
556
21.3k
            c;
557
558
334k
          while (1)
559
334k
            {
560
334k
              p=keyword;
561
334k
              c=ReadBlobByte(image);
562
334k
              do
563
1.18M
                {
564
1.18M
                  if (isalnum(c) || ('#' == c))
565
1.15M
                    if ((p-keyword) < (MaxTextExtent-1))
566
1.14M
                      {
567
1.14M
                        *p++=c;
568
1.14M
                        if ('#' == c)
569
208k
                          break;
570
1.14M
                      }
571
974k
                  c=ReadBlobByte(image);
572
974k
                } while (isalnum(c) || ('#' == c));
573
334k
              *p='\0';
574
575
334k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
576
334k
                                    "Keyword \"%s\"",keyword);
577
334k
              if ((EOF == c) || (LocaleCompare(keyword,"ENDHDR") == 0))
578
4.62k
                {
579
4.62k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
580
4.62k
                                        "Exiting header!");
581
4.62k
                  break;
582
4.62k
                }
583
329k
              else if (LocaleCompare(keyword,"HEIGHT") == 0)
584
24.2k
                {
585
24.2k
                  image->rows=PNMIntegerOrComment(image,10,&status);
586
24.2k
                  if (status == MagickFail)
587
24.2k
                    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
588
24.2k
                }
589
305k
              else if (LocaleCompare(keyword,"WIDTH") == 0)
590
19.0k
                {
591
19.0k
                  image->columns=PNMInteger(image,10,&status);
592
19.0k
                  if (status == MagickFail)
593
19.0k
                    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
594
19.0k
                }
595
286k
              else if (LocaleCompare(keyword,"DEPTH") == 0)
596
18.2k
                {
597
18.2k
                  samples_per_pixel=PNMInteger(image,10,&status);
598
18.2k
                  if (status == MagickFail)
599
18.2k
                    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
600
18.2k
                }
601
268k
              else if (LocaleCompare(keyword,"MAXVAL") == 0)
602
14.0k
                {
603
14.0k
                  max_value=PNMInteger(image,10,&status);
604
14.0k
                  if (status == MagickFail)
605
13.9k
                    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
606
13.9k
                }
607
254k
              else if (LocaleCompare(keyword,"TUPLTYPE") == 0)
608
31.4k
                {
609
                  /* Skip white space */
610
31.4k
                  do
611
38.7k
                    {
612
38.7k
                      c=ReadBlobByte(image);
613
38.7k
                    } while (isspace(c) && (EOF != c));
614
31.4k
                  if (EOF == c)
615
99
                    break;
616
                  /* Tupletype argument */
617
31.3k
                  p=keyword;
618
31.3k
                  do
619
59.2M
                    {
620
59.2M
                      if ((p-keyword) < (MaxTextExtent-1))
621
6.11M
                        *p++=c;
622
59.2M
                      c=ReadBlobByte(image);
623
59.2M
                    } while (('\n' != c) && (EOF != c));
624
31.3k
                  *p='\0';
625
31.3k
                  if (EOF == c)
626
554
                    break;
627
30.7k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
628
30.7k
                                        "TUPLTYPE \"%s\"",keyword);
629
30.7k
                  if (LocaleNCompare(keyword,"BLACKANDWHITE",13) == 0)
630
1.60k
                    {
631
1.60k
                      image->colorspace=GRAYColorspace;
632
1.60k
                      image->is_monochrome=MagickTrue;
633
1.60k
                    }
634
29.1k
                  else if (LocaleNCompare(keyword,"CMYK",4) == 0)
635
7.52k
                    {
636
7.52k
                      image->colorspace=CMYKColorspace;
637
7.52k
                    }
638
21.6k
                  else if (LocaleNCompare(keyword,"GRAYSCALE",9) == 0)
639
4.05k
                    {
640
4.05k
                      image->colorspace=GRAYColorspace;
641
4.05k
                    }
642
17.5k
                  else if (LocaleNCompare(keyword,"RGB",3) == 0)
643
33
                    {
644
33
                    }
645
646
                  /*
647
                    Check for alpha flag.
648
                  */
649
30.7k
                  count=strlen(keyword);
650
30.7k
                  if ((count > 6) && (LocaleNCompare(keyword+count-6,"_ALPHA",6) == 0))
651
6.17k
                    {
652
6.17k
                      image->matte=MagickTrue;
653
6.17k
                    }
654
30.7k
                }
655
222k
              else if (LocaleNCompare(keyword,"#",1) == 0)
656
208k
                {
657
                  /* Skip leading white space */
658
208k
                  do
659
305k
                    {
660
305k
                      c=ReadBlobByte(image);
661
305k
                    } while (isspace(c) && (EOF != c));
662
208k
                  if (EOF == c)
663
1.35k
                    break;
664
665
                  /* Comment */
666
206k
                  p=keyword;
667
92.0M
                  while ((p-keyword) < (MaxTextExtent-2))
668
92.0M
                    {
669
92.0M
                      *p++=c;
670
92.0M
                      c=ReadBlobByte(image);
671
92.0M
                      if (c == '\n')
672
162k
                        {
673
162k
                          *p++=c;
674
162k
                          break;
675
162k
                        }
676
91.8M
                      if (c == EOF)
677
2.25k
                        break;
678
91.8M
                    }
679
206k
                  *p='\0';
680
                  /*
681
                    FIXME:
682
                    Implicitly extend existing comment attribute since comments
683
                    can span multiple lines.
684
                  */
685
206k
                  (void) SetImageAttribute(image,"comment",keyword);
686
206k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
687
206k
                                        "Comment: \"%s\"",keyword);
688
206k
                }
689
14.6k
              else
690
14.6k
                {
691
                  /* Unknown! */
692
14.6k
                  do
693
28.0M
                    {
694
28.0M
                      c=ReadBlobByte(image);
695
28.0M
                    } while (('\n' != c) && (EOF != c));
696
14.6k
                  break;
697
14.6k
                }
698
334k
            }
699
21.3k
        }
700
185k
      else
701
185k
        {
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
185k
          image->columns=PNMIntegerOrComment(image,10,&status);
715
185k
          image->rows=PNMInteger(image,10,&status);
716
717
185k
          if ((format == PBM_ASCII_Format) || (format == PBM_RAW_Format))
718
39.1k
            max_value=1;  /* bitmap */
719
146k
          else
720
146k
            max_value=PNMInteger(image,10,&status);
721
722
185k
          if (status == MagickFail)
723
142k
            ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
724
725
142k
          switch (format)
726
142k
            {
727
15.6k
            case PBM_ASCII_Format:
728
32.1k
            case PBM_RAW_Format:
729
63.7k
            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.5k
            case PPM_ASCII_Format:
737
58.4k
            case PPM_RAW_Format:
738
58.4k
              {
739
58.4k
                samples_per_pixel=3;
740
58.4k
                break;
741
22.5k
              }
742
99
            default:
743
99
              {
744
99
              }
745
142k
            }
746
142k
        }
747
748
164k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Dimensions: %lux%lu",
749
164k
                            image->columns,image->rows);
750
164k
      if ((image->columns == 0) || (image->rows == 0))
751
142k
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
752
753
142k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Max Value: %u",
754
142k
                            max_value);
755
142k
      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
51.3k
        bits_per_sample=1;
764
86.2k
      else if (max_value <= 255U)
765
59.7k
        bits_per_sample=8;
766
26.4k
      else if (max_value <= 65535U)
767
14.6k
        bits_per_sample=16;
768
11.8k
      else if (max_value <= 4294967295U)
769
11.8k
        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
14.5k
        ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
782
137k
                       image->filename);
783
784
137k
      if ((1 == samples_per_pixel) && (max_value < MaxColormapSize) &&
785
70.2k
          ((size_t) image->columns*image->rows >= max_value))
786
52.9k
        {
787
52.9k
          image->storage_class=PseudoClass;
788
52.9k
          image->colors=
789
52.9k
            max_value >= MaxColormapSize ? MaxColormapSize : max_value+1;
790
52.9k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colors: %u",
791
52.9k
                                image->colors);
792
52.9k
        }
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
52.9k
        {
798
          /*
799
            Create colormap.
800
          */
801
52.9k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
802
52.9k
                                "Allocating colormap with %u colors",
803
52.9k
                                image->colors);
804
52.9k
          if (!AllocateImageColormap(image,image->colors))
805
0
            ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
806
52.9k
                                 image);
807
52.9k
          if ((format == XV_332_Format) && (image->colors == 256))
808
556
            {
809
              /*
810
                Initialize 332 colormap.
811
              */
812
556
              i=0;
813
5.00k
              for (pixel.red=0; pixel.red < 8; pixel.red++)
814
40.0k
                for (pixel.green=0; pixel.green < 8; pixel.green++)
815
177k
                  for (pixel.blue=0; pixel.blue < 4; pixel.blue++)
816
142k
                    {
817
142k
                      image->colormap[i].red=(Quantum)
818
142k
                        (((double) MaxRGB*pixel.red)/0x07+0.5);
819
142k
                      image->colormap[i].green=(Quantum)
820
142k
                        (((double) MaxRGB*pixel.green)/0x07+0.5);
821
142k
                      image->colormap[i].blue=(Quantum)
822
142k
                        (((double) MaxRGB*pixel.blue)/0x03+0.5);
823
142k
                      i++;
824
142k
                    }
825
556
            }
826
52.9k
        }
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
77.2k
        ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
833
834
      /*
835
        Decode PNM pixels to Image pixel packets.
836
      */
837
60.3k
      switch (format)
838
60.3k
        {
839
6.73k
        case PBM_ASCII_Format:
840
6.73k
          {
841
            /*
842
              Convert PBM image to pixel packets.
843
            */
844
6.73k
            register unsigned long
845
6.73k
              x=0;
846
847
6.73k
            register PixelPacket
848
6.73k
              *q;
849
850
6.73k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
851
6.73k
                                  "Reading %s pixel data",PNMSubformatToString(format));
852
14.5k
            for (y=0; y < (long) image->rows; y++)
853
14.0k
              {
854
14.0k
                q=SetImagePixels(image,0,y,image->columns,1);
855
14.0k
                if (q == (PixelPacket *) NULL)
856
2.03k
                  break;
857
12.0k
                indexes=AccessMutableIndexes(image);
858
21.2k
                for (x=0; x < image->columns; x++)
859
13.3k
                  {
860
13.3k
                    index=!PNMInteger(image,2,&status);
861
13.3k
                    if (status == MagickFail)
862
4.21k
                      break;
863
9.16k
                    VerifyColormapIndex(status,image,index);
864
9.16k
                    indexes[x]=index;
865
9.16k
                    *q++=image->colormap[index];
866
9.16k
                  }
867
12.0k
                if (!SyncImagePixels(image))
868
0
                  break;
869
12.0k
                if (image->previous == (Image *) NULL)
870
12.0k
                  if (QuantumTick(y,image->rows))
871
8.65k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
872
8.65k
                                                LoadImageText,image->filename,
873
8.65k
                                                image->columns,image->rows))
874
0
                      break;
875
12.0k
                if (status == MagickFail)
876
4.21k
                  break;
877
12.0k
              }
878
6.73k
            image->is_grayscale=MagickTrue;
879
6.73k
            image->is_monochrome=MagickTrue;
880
881
882
6.73k
            if (status == MagickFail)
883
4.21k
              {
884
4.21k
                if (EOFBlob(image))
885
1.15k
                  {
886
1.15k
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
887
1.15k
                                          "PBM raw (P1) reader EOF at x=%lu, y=%lu", x, y);
888
1.15k
                    ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
889
1.15k
                                   image->filename);
890
1.15k
                  }
891
3.06k
                else
892
3.06k
                  {
893
3.06k
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
894
3.06k
                                          "PBM raw (P1) corrupt data at x=%lu, y=%lu", x, y);
895
3.06k
                    ThrowException(exception,CorruptImageError,CorruptImage,image->filename);
896
3.06k
                  }
897
4.21k
              }
898
6.73k
            break;
899
0
          }
900
9.60k
        case PGM_ASCII_Format:
901
9.60k
          {
902
            /*
903
              Convert PGM image to pixel packets.
904
            */
905
9.60k
            register unsigned long
906
9.60k
              x=0;
907
908
9.60k
            register PixelPacket
909
9.60k
              *q;
910
911
9.60k
            unsigned long
912
9.60k
              intensity;
913
914
9.60k
            MagickBool
915
9.60k
              is_grayscale,
916
9.60k
              is_monochrome;
917
918
9.60k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
919
9.60k
                                  "Reading %s pixel data",PNMSubformatToString(format));
920
9.60k
            is_grayscale=MagickTrue;
921
9.60k
            is_monochrome=MagickTrue;
922
21.4k
            for (y=0; y < (long) image->rows; y++)
923
19.5k
              {
924
19.5k
                q=SetImagePixels(image,0,y,image->columns,1);
925
19.5k
                if (q == (PixelPacket *) NULL)
926
3.06k
                  break;
927
16.4k
                if (image->storage_class == PseudoClass)
928
10.9k
                  {
929
                    /*
930
                      PseudoClass
931
                    */
932
10.9k
                    indexes=AccessMutableIndexes(image);
933
26.0k
                    for (x=0; x < image->columns; x++)
934
17.7k
                      {
935
17.7k
                        intensity=PNMInteger(image,10,&status);
936
17.7k
                        if (status == MagickFail)
937
1.00k
                          break;
938
16.7k
                        ValidateScalingIndex(image, intensity, max_value);
939
15.0k
                        index=intensity;
940
15.0k
                        VerifyColormapIndex(status,image,index);
941
15.0k
                        if (status == MagickFail)
942
0
                          break;
943
15.0k
                        indexes[x]=index;
944
15.0k
                        *q=image->colormap[index];
945
15.0k
                        is_monochrome &= IsMonochrome(*q);
946
15.0k
                        q++;
947
15.0k
                      }
948
10.9k
                  }
949
5.51k
                else
950
5.51k
                  {
951
                    /*
952
                      DirectClass
953
                    */
954
13.2k
                    for (x=0; x < image->columns; x++)
955
9.73k
                      {
956
9.73k
                        intensity=PNMInteger(image,10,&status);
957
9.73k
                        if (status == MagickFail)
958
1.56k
                          break;
959
8.17k
                        ValidateScalingIndex(image, intensity, max_value);
960
7.75k
                        intensity=ScaleAnyToQuantum(intensity, max_value);
961
7.75k
                        q->red=q->green=q->blue=intensity;
962
7.75k
                        is_monochrome &= IsMonochrome(*q);
963
7.75k
                        q++;
964
7.75k
                      }
965
5.51k
                  }
966
14.4k
                if (status == MagickFail)
967
2.57k
                  break;
968
11.8k
                if (!SyncImagePixels(image))
969
0
                  break;
970
11.8k
                if (image->previous == (Image *) NULL)
971
11.8k
                  if (QuantumTick(y,image->rows))
972
8.90k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
973
8.90k
                                                LoadImageText,image->filename,
974
8.90k
                                                image->columns,image->rows))
975
0
                      break;
976
11.8k
              }
977
7.53k
            image->is_monochrome=is_monochrome;
978
7.53k
            image->is_grayscale=is_grayscale;
979
7.53k
            if (status == MagickFail)
980
2.57k
              {
981
2.57k
                if (EOFBlob(image))
982
2.49k
                  {
983
2.49k
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
984
2.49k
                                          "PGM raw (P2) reader EOF at x=%lu, y=%lu", x, y);
985
2.49k
                    ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
986
2.49k
                                   image->filename);
987
2.49k
                  }
988
81
                else
989
81
                  {
990
81
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
991
81
                                          "PGM raw (P2) corrupt data at x=%lu, y=%lu", x, y);
992
81
                    ThrowException(exception,CorruptImageError,CorruptImage,image->filename);
993
81
                  }
994
2.57k
              }
995
7.53k
            break;
996
9.60k
          }
997
16.2k
        case PPM_ASCII_Format:
998
16.2k
          {
999
            /*
1000
              Convert PPM image to pixel packets.
1001
            */
1002
16.2k
            register unsigned long
1003
16.2k
              x=0;
1004
1005
16.2k
            register PixelPacket
1006
16.2k
              *q;
1007
1008
16.2k
            MagickBool
1009
16.2k
              is_grayscale,
1010
16.2k
              is_monochrome;
1011
1012
16.2k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1013
16.2k
                                  "Reading %s pixel data",PNMSubformatToString(format));
1014
16.2k
            is_grayscale=MagickTrue;
1015
16.2k
            is_monochrome=MagickTrue;
1016
24.6k
            for (y=0; y < (long) image->rows; y++)
1017
23.5k
              {
1018
23.5k
                q=SetImagePixels(image,0,y,image->columns,1);
1019
23.5k
                if (q == (PixelPacket *) NULL)
1020
4.52k
                  break;
1021
33.4k
                for (x=0; x < image->columns; x++)
1022
25.1k
                  {
1023
25.1k
                    pixel.red=PNMInteger(image,10,&status);
1024
25.1k
                    if (status == MagickFail)
1025
2.19k
                      break;
1026
22.9k
                    pixel.green=PNMInteger(image,10,&status);
1027
22.9k
                    if (status == MagickFail)
1028
617
                      break;
1029
22.2k
                    pixel.blue=PNMInteger(image,10,&status);
1030
22.2k
                    if (status == MagickFail)
1031
1.12k
                      break;
1032
21.1k
                    ValidateScalingPixel(image, pixel, max_value);
1033
14.3k
                    pixel.red=ScaleAnyToQuantum(pixel.red, max_value);
1034
14.3k
                    pixel.green=ScaleAnyToQuantum(pixel.green, max_value);
1035
14.3k
                    pixel.blue=ScaleAnyToQuantum(pixel.blue, max_value);
1036
14.3k
                    q->red=(Quantum) pixel.red;
1037
14.3k
                    q->green=(Quantum) pixel.green;
1038
14.3k
                    q->blue=(Quantum) pixel.blue;
1039
14.3k
                    is_monochrome &= IsMonochrome(*q);
1040
14.3k
                    is_grayscale &= IsGray(*q);
1041
14.3k
                    q++;
1042
14.3k
                  }
1043
12.2k
                if (status == MagickFail)
1044
3.93k
                  break;
1045
8.32k
                if (!SyncImagePixels(image))
1046
0
                  break;
1047
8.32k
                if (image->previous == (Image *) NULL)
1048
8.32k
                  if (QuantumTick(y,image->rows))
1049
5.37k
                    if (!MagickMonitorFormatted(y,image->rows,exception,
1050
5.37k
                                                LoadImageText,image->filename,
1051
5.37k
                                                image->columns,image->rows))
1052
0
                      break;
1053
8.32k
              }
1054
9.47k
            image->is_monochrome=is_monochrome;
1055
9.47k
            image->is_grayscale=is_grayscale;
1056
9.47k
            if (status == MagickFail)
1057
3.93k
              {
1058
3.93k
                if (EOFBlob(image))
1059
3.78k
                  {
1060
3.78k
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1061
3.78k
                                          "PNM raw (P3) reader EOF at x=%lu, y=%lu", x, y);
1062
3.78k
                    ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
1063
3.78k
                                   image->filename);
1064
3.78k
                  }
1065
153
                else
1066
153
                  {
1067
153
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1068
153
                                          "PNM raw (P3) corrupt data at x=%lu, y=%lu", x, y);
1069
153
                    ThrowException(exception,CorruptImageError,CorruptImage,image->filename);
1070
153
                  }
1071
3.93k
              }
1072
9.47k
            break;
1073
16.2k
          }
1074
3.27k
        case PBM_RAW_Format:
1075
7.23k
        case PGM_RAW_Format:
1076
23.5k
        case PPM_RAW_Format:
1077
27.4k
        case PAM_Format:
1078
27.6k
        case XV_332_Format:
1079
27.6k
          {
1080
            /*
1081
              Convert PBM/PGM/PPM/PAM/XV raw raster image to pixel packets.
1082
            */
1083
27.6k
            ImportPixelAreaOptions
1084
27.6k
              import_options;
1085
1086
27.6k
            QuantumType
1087
27.6k
              quantum_type;
1088
1089
27.6k
            size_t
1090
27.6k
              bytes_per_row;
1091
1092
27.6k
            MagickBool
1093
27.6k
              check_pixels,
1094
27.6k
              is_grayscale,
1095
27.6k
              is_monochrome,
1096
27.6k
              use_scaling;
1097
1098
27.6k
            unsigned long
1099
27.6k
              max_value_given_bits,
1100
27.6k
              row_count=0;
1101
1102
27.6k
            ThreadViewDataSet
1103
27.6k
              *scanline_set;
1104
1105
27.6k
            double
1106
27.6k
              sample_scale;
1107
1108
27.6k
            unsigned int
1109
27.6k
              sample_max;
1110
1111
#if defined(HAVE_OPENMP)
1112
            int
1113
              pnm_read_threads;
1114
#endif
1115
1116
27.6k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1117
27.6k
                                  "Reading %s pixel data",PNMSubformatToString(format));
1118
1119
27.6k
            ImportPixelAreaOptionsInit(&import_options);
1120
1121
27.6k
            check_pixels=MagickTrue;
1122
27.6k
            is_grayscale=MagickTrue;
1123
27.6k
            is_monochrome=MagickTrue;
1124
1125
            /*
1126
              Deduce correct import parameters.
1127
            */
1128
27.6k
            quantum_type=UndefinedQuantum;
1129
27.6k
            import_options.grayscale_miniswhite=MagickFalse;
1130
27.6k
            max_value_given_bits=MaxValueGivenBits(bits_per_sample);
1131
27.6k
            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.6k
            sample_max=RoundDoubleToQuantum((MaxRGBDouble*max_value)/max_value_given_bits);
1138
27.6k
            if (sample_max == 0U)
1139
0
              {
1140
0
                ThrowException(exception,CorruptImageError,ImproperImageHeader,
1141
0
                               image->filename);
1142
0
                break;
1143
0
              }
1144
27.6k
            sample_scale=MaxRGBDouble/sample_max;
1145
27.6k
            use_scaling=(MaxRGB != sample_max);
1146
27.6k
            bytes_per_row=0;
1147
1148
27.6k
            if (1 == samples_per_pixel)
1149
7.93k
              {
1150
7.93k
                if (1 == bits_per_sample)
1151
3.65k
                  {
1152
                    /* PBM */
1153
3.65k
                    import_options.grayscale_miniswhite=MagickTrue;
1154
3.65k
                    quantum_type=GrayQuantum;
1155
3.65k
                  }
1156
4.28k
                else
1157
4.28k
                  {
1158
                    /* PGM & XV_332 */
1159
4.28k
                    if ((XV_332_Format == format) && (image->storage_class == PseudoClass))
1160
99
                      {
1161
99
                        quantum_type=IndexQuantum;
1162
99
                      }
1163
4.18k
                    else
1164
4.18k
                      {
1165
4.18k
                        quantum_type=GrayQuantum;
1166
4.18k
                      }
1167
4.28k
                  }
1168
7.93k
              }
1169
19.6k
            else if (2 == samples_per_pixel && image->matte)
1170
663
              {
1171
663
                quantum_type=GrayAlphaQuantum;
1172
663
              }
1173
19.0k
            else if (3 == samples_per_pixel)
1174
16.4k
              {
1175
                /* PPM */
1176
16.4k
                quantum_type=RGBQuantum;
1177
16.4k
              }
1178
2.54k
            else if (4 == samples_per_pixel)
1179
1.37k
              {
1180
1.37k
                if (CMYKColorspace == image->colorspace)
1181
652
                  quantum_type=CMYKQuantum;
1182
727
                else
1183
727
                  quantum_type=RGBAQuantum;
1184
1.37k
              }
1185
1.16k
            else if (5 == samples_per_pixel)
1186
647
              {
1187
647
                if (CMYKColorspace == image->colorspace)
1188
627
                  quantum_type=CMYKAQuantum;
1189
647
              }
1190
1191
27.6k
            if (image->logging)
1192
27.6k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1193
27.6k
                                    "Import Quantum Type: %s",
1194
27.6k
                                    QuantumTypeToString(quantum_type));
1195
1196
27.6k
            samples_per_pixel=MagickGetQuantumSamplesPerPixel(quantum_type);
1197
27.6k
            if (image->logging)
1198
27.6k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1199
27.6k
                                    "Samples/Pixel: %u", samples_per_pixel);
1200
1201
27.6k
            if (1 == bits_per_sample)
1202
5.83k
              {
1203
                /* bytes_per_row=(((size_t) image->columns*samples_per_pixel+7) >> 3); */
1204
5.83k
                bytes_per_row=MagickArraySize(image->columns,samples_per_pixel);
1205
5.83k
                if (bytes_per_row)
1206
5.60k
                  bytes_per_row += 7;
1207
5.83k
                if (bytes_per_row)
1208
5.60k
                  bytes_per_row >>= 3;
1209
5.83k
              }
1210
21.7k
            else
1211
21.7k
              {
1212
21.7k
                bytes_per_row=MagickArraySize((((size_t) bits_per_sample+7)/8)*
1213
21.7k
                                              samples_per_pixel,image->columns);
1214
21.7k
              }
1215
1216
27.6k
            if (image->logging)
1217
27.6k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1218
27.6k
                                    "Bytes/Row: %" MAGICK_SIZE_T_F "u",
1219
27.6k
                                    (MAGICK_SIZE_T) bytes_per_row);
1220
1221
27.6k
            if (1 == samples_per_pixel)
1222
7.93k
              {
1223
7.93k
                check_pixels=MagickFalse;
1224
7.93k
              }
1225
27.6k
            if (GrayQuantum == quantum_type)
1226
7.83k
              {
1227
7.83k
                if (1 == bits_per_sample)
1228
3.65k
                  {
1229
3.65k
                    is_grayscale=MagickTrue;
1230
3.65k
                    is_monochrome=MagickTrue;
1231
3.65k
                  }
1232
4.18k
                else
1233
4.18k
                  {
1234
4.18k
                    is_grayscale=MagickTrue;
1235
4.18k
                    is_monochrome=MagickFalse;
1236
4.18k
                  }
1237
7.83k
              }
1238
1239
            /* Validate file size before allocating memory */
1240
27.6k
            if (BlobIsSeekable(image))
1241
27.6k
              {
1242
27.6k
                const magick_off_t file_size = GetBlobSize(image);
1243
27.6k
                const magick_off_t current_offset = TellBlob(image);
1244
27.6k
                if ((file_size > 0) &&
1245
27.6k
                    (current_offset > 0) &&
1246
27.6k
                    (file_size > current_offset))
1247
25.8k
                  {
1248
25.8k
                    const magick_off_t remaining = file_size-current_offset;
1249
25.8k
                    const magick_off_t needed = (magick_off_t) image->rows *
1250
25.8k
                      (magick_off_t) bytes_per_row;
1251
25.8k
                    if ((remaining < (magick_off_t) bytes_per_row) ||
1252
24.6k
                        (remaining < needed))
1253
1.37k
                      {
1254
1.37k
                        ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
1255
1.37k
                                       image->filename);
1256
1.37k
                        break;
1257
1.37k
                      }
1258
25.8k
                  }
1259
27.6k
              }
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.2k
            scanline_set=AllocateThreadViewDataArray(image,exception,bytes_per_row,1);
1269
26.2k
            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
708k
            for (y=0; y < (long) image->rows; y++)
1279
682k
              {
1280
682k
                register unsigned long
1281
682k
                  x;
1282
1283
682k
                register PixelPacket
1284
682k
                  *q = (PixelPacket *) NULL;
1285
1286
682k
                void
1287
682k
                  *pixels;
1288
1289
682k
                MagickBool
1290
682k
                  thread_status;
1291
1292
682k
                MagickBool
1293
682k
                  thread_is_grayscale,
1294
682k
                  thread_is_monochrome;
1295
1296
682k
                unsigned long
1297
682k
                  thread_row_count;
1298
1299
682k
                ImportPixelAreaInfo
1300
682k
                  import_info;
1301
1302
#if PNMReadUseOpenMP
1303
#  pragma omp critical (GM_ReadPNMImage)
1304
#endif
1305
682k
                thread_status=status;
1306
682k
                if (thread_status == MagickFail)
1307
135k
                  continue;
1308
1309
547k
                pixels=AccessThreadViewData(scanline_set);
1310
1311
#if PNMReadUseOpenMP
1312
#  pragma omp critical (GM_ReadPNMImage)
1313
#endif
1314
547k
                {
1315
547k
                  thread_is_grayscale=is_grayscale;
1316
547k
                  thread_is_monochrome=is_monochrome;
1317
1318
547k
                  if (ReadBlobZC(image,bytes_per_row,&pixels) != bytes_per_row)
1319
1.31k
                    thread_status=MagickFail;
1320
1321
547k
                  thread_row_count=row_count;
1322
547k
                  row_count++;
1323
1324
547k
                  if (image->previous == (Image *) NULL)
1325
547k
                    if (QuantumTick(thread_row_count,image->rows))
1326
161k
                      if (!MagickMonitorFormatted(thread_row_count,image->rows,
1327
161k
                                                  exception,LoadImageText,
1328
161k
                                                  image->filename,
1329
161k
                                                  image->columns,image->rows))
1330
0
                        thread_status=MagickFail;
1331
547k
                }
1332
1333
547k
                if (thread_status != MagickFail)
1334
545k
                  if ((q=SetImagePixels(image,0,thread_row_count,image->columns,1)) ==
1335
545k
                      (PixelPacket *) NULL)
1336
5.45k
                    thread_status=MagickFail;
1337
1338
547k
                if (thread_status != MagickFail)
1339
540k
                  if (!ImportImagePixelArea(image,quantum_type,bits_per_sample,
1340
540k
                                            (const unsigned char*) pixels,
1341
540k
                                            &import_options,&import_info))
1342
614
                    thread_status=MagickFail;
1343
                /*
1344
                  Scale sub-ranged pixels up to full range if necessary
1345
                */
1346
547k
                if ((thread_status != MagickFail) && (use_scaling))
1347
4.37M
                  for (x=0; x < image->columns; x++)
1348
4.29M
                    {
1349
4.29M
                      SetRedSample(&q[x],
1350
4.29M
                                   RoundDoubleToQuantum(sample_scale*
1351
4.29M
                                                        GetRedSample(&q[x])));
1352
4.29M
                      SetGreenSample(&q[x],
1353
4.29M
                                     RoundDoubleToQuantum(sample_scale*
1354
4.29M
                                                          GetGreenSample(&q[x])));
1355
4.29M
                      SetBlueSample(&q[x],
1356
4.29M
                                    RoundDoubleToQuantum(sample_scale*
1357
4.29M
                                                         GetBlueSample(&q[x])));
1358
4.29M
                      if (image->matte)
1359
379k
                        SetOpacitySample(&q[x],
1360
4.29M
                                         MaxRGB-
1361
4.29M
                                         RoundDoubleToQuantum(sample_scale*
1362
4.29M
                                                              (MaxRGB-
1363
4.29M
                                                               GetOpacitySample(&q[x]))));
1364
4.29M
                    }
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
547k
                if (thread_status != MagickFail)
1374
539k
                  if (check_pixels)
1375
61.8k
                    if (thread_is_grayscale || thread_is_monochrome)
1376
429k
                      for (x=0; x < image->columns; x++)
1377
413k
                        {
1378
413k
                          thread_is_grayscale = thread_is_grayscale && IsGray(q[x]);
1379
413k
                          thread_is_monochrome = thread_is_monochrome && IsMonochrome(q[x]);
1380
413k
                          if (!thread_is_grayscale && !thread_is_monochrome)
1381
10.5k
                            break;
1382
413k
                        }
1383
1384
547k
                if (thread_status != MagickFail)
1385
539k
                  if (!SyncImagePixels(image))
1386
0
                    thread_status=MagickFail;
1387
1388
#if PNMReadUseOpenMP
1389
#  pragma omp critical (GM_ReadPNMImage)
1390
#endif
1391
547k
                {
1392
547k
                  if (thread_status == MagickFail)
1393
7.38k
                    status=MagickFail;
1394
1395
547k
                  if (!thread_is_grayscale)
1396
45.4k
                    is_grayscale=thread_is_grayscale;
1397
1398
547k
                  if (!thread_is_monochrome)
1399
85.4k
                    is_monochrome=thread_is_monochrome;
1400
547k
                }
1401
547k
              }
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
6.14k
              CopyException(exception,&image->exception);
1407
25.6k
            if (EOFBlob(image))
1408
24.2k
              ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1409
24.2k
            break;
1410
25.6k
          }
1411
89
        default:
1412
89
          ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1413
60.3k
        }
1414
49.3k
      StopTimer(&image->timer);
1415
49.3k
      if (status ==MagickFail)
1416
16.7k
        break;
1417
      /*
1418
        Proceed to next image.
1419
      */
1420
32.6k
      if (image_info->subrange != 0)
1421
32.3k
        if (image->scene >= (image_info->subimage+image_info->subrange-1))
1422
32.3k
          break;
1423
264
      if ((format == PBM_ASCII_Format) || (format == PGM_ASCII_Format) || (format == PPM_ASCII_Format))
1424
17
        do
1425
294
          {
1426
            /*
1427
              Skip to end of line.
1428
            */
1429
294
            count=ReadBlob(image,1,&c);
1430
294
            if (count == 0)
1431
15
              break;
1432
294
          } while (c != '\n');
1433
264
      count=ReadBlob(image,1,&c);
1434
264
      if ((count != 0) && (c == 'P'))
1435
1
        {
1436
          /*
1437
            Allocate next image structure.
1438
          */
1439
1
          AllocateNextImage(image_info,image);
1440
1
          if (image->next == (Image *) NULL)
1441
0
            {
1442
0
              DestroyImageList(image);
1443
0
              return((Image *) NULL);
1444
0
            }
1445
1
          image=SyncNextImageInList(image);
1446
1
          if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),
1447
1
                                      exception,LoadImagesText,
1448
1
                                      image->filename))
1449
0
            break;
1450
1
        }
1451
264
    } while ((count != 0) && (c == 'P'));
1452
49.3k
  while (image->previous != (Image *) NULL)
1453
0
    image=image->previous;
1454
49.3k
  CloseBlob(image);
1455
49.3k
  return(image);
1456
207k
}
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.41k
{
1634
7.41k
  char
1635
7.41k
    buffer[MaxTextExtent];
1636
1637
7.41k
  const ImageAttribute
1638
7.41k
    *attribute;
1639
1640
7.41k
  IndexPacket
1641
7.41k
    index;
1642
1643
7.41k
  PNMSubformat
1644
7.41k
    format;
1645
1646
7.41k
  unsigned int
1647
7.41k
    depth;
1648
1649
7.41k
  unsigned long
1650
7.41k
    y;
1651
1652
7.41k
  register const PixelPacket
1653
7.41k
    *p;
1654
1655
7.41k
  register const IndexPacket
1656
7.41k
    *indexes;
1657
1658
7.41k
  register unsigned long
1659
7.41k
    i,
1660
7.41k
    x;
1661
1662
7.41k
  unsigned int
1663
7.41k
    scene;
1664
1665
7.41k
  MagickPassFail
1666
7.41k
    status;
1667
1668
7.41k
  size_t
1669
7.41k
    image_list_length;
1670
1671
  /*
1672
    Open output image file.
1673
  */
1674
7.41k
  assert(image_info != (const ImageInfo *) NULL);
1675
7.41k
  assert(image_info->signature == MagickSignature);
1676
7.41k
  assert(image != (Image *) NULL);
1677
7.41k
  assert(image->signature == MagickSignature);
1678
7.41k
  image_list_length=GetImageListLength(image);
1679
7.41k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1680
7.41k
  if (status == MagickFail)
1681
7.41k
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
1682
7.41k
  scene=0;
1683
7.41k
  do
1684
7.41k
    {
1685
7.41k
      depth=(image->depth <= 8 ? 8 : image->depth <= 16 ? 16 : 32);
1686
1687
      /*
1688
        Write PNM file header.
1689
      */
1690
7.41k
      format=Undefined_PNM_Format;
1691
7.41k
      if (LocaleCompare(image_info->magick,"P7") == 0)
1692
1.07k
        {
1693
1.07k
          format=XV_332_Format;
1694
1.07k
        }
1695
6.33k
      else if (LocaleCompare(image_info->magick,"PPM") == 0)
1696
1.26k
        {
1697
1.26k
          format=PPM_RAW_Format;
1698
1.26k
        }
1699
5.06k
      else if (LocaleCompare(image_info->magick,"PGM") == 0)
1700
1.22k
        {
1701
1.22k
          format=PGM_RAW_Format;
1702
1.22k
        }
1703
3.84k
      else if (LocaleCompare(image_info->magick,"PBM") == 0)
1704
1.23k
        {
1705
1.23k
          format=PBM_RAW_Format;
1706
1.23k
        }
1707
2.61k
      else if (LocaleCompare(image_info->magick,"PAM") == 0)
1708
1.35k
        {
1709
1.35k
          format=PAM_Format;
1710
1.35k
        }
1711
1.25k
      else /* PNM auto format */
1712
1.25k
        {
1713
1.25k
          ImageCharacteristics
1714
1.25k
            characteristics;
1715
1716
          /*
1717
            Make sure that image is in an RGB type space.
1718
          */
1719
1.25k
          if (TransformColorspace(image,RGBColorspace) == MagickFail)
1720
1.25k
            ThrowWriterException(CoderError,UnableToTransformColorspace,image);
1721
1722
          /*
1723
            Analyze image to be written.
1724
          */
1725
1.25k
          if (!GetImageCharacteristics(image,&characteristics,
1726
1.25k
                                       (OptimizeType == image_info->type),
1727
1.25k
                                       &image->exception))
1728
1.25k
            ThrowWriterException(CoderError,UnableToGetImageCharacteristics,image);
1729
1730
1.25k
          if ((characteristics.monochrome) &&
1731
419
              (image_info->type != GrayscaleType) &&
1732
419
              (image_info->type != GrayscaleMatteType) &&
1733
419
              (image_info->type != TrueColorType) &&
1734
419
              (image_info->type != TrueColorMatteType))
1735
419
            {
1736
              /* PBM */
1737
419
              format=PBM_RAW_Format;
1738
419
            }
1739
836
          else if ((characteristics.grayscale) &&
1740
171
                   (image_info->type != TrueColorType) &&
1741
171
                   (image_info->type != TrueColorMatteType))
1742
171
            {
1743
              /* PGM */
1744
171
              format=PGM_RAW_Format;
1745
171
            }
1746
665
          else
1747
665
            {
1748
              /* PPM */
1749
665
              format=PPM_RAW_Format;
1750
665
            }
1751
1.25k
        }
1752
1753
      /*
1754
        Check if ASCII subformat is requested.
1755
      */
1756
7.41k
      if ((PBM_RAW_Format == format) || (PGM_RAW_Format == format) | (PPM_RAW_Format == format))
1757
4.97k
        {
1758
4.97k
          MagickBool
1759
4.97k
            ascii = MagickFalse;
1760
1761
          /*
1762
            If quality is set to zero or "pnm:ascii" is defined, then
1763
            select an ASCII subformat.
1764
          */
1765
4.97k
          if (image_info->quality == 0)
1766
0
            ascii=MagickTrue;
1767
4.97k
          else if ((AccessDefinition(image_info,"pnm","ascii")))
1768
0
            ascii=MagickTrue;
1769
1770
4.97k
          if (ascii)
1771
0
            {
1772
0
              if (PBM_RAW_Format == format)
1773
0
                format=PBM_ASCII_Format;
1774
0
              else if (PGM_RAW_Format == format)
1775
0
                format=PGM_ASCII_Format;
1776
0
              else if (PPM_RAW_Format == format)
1777
0
                format=PPM_ASCII_Format;
1778
0
            }
1779
4.97k
        }
1780
1781
7.41k
      {
1782
7.41k
        const char *header = "";
1783
7.41k
        switch (format)
1784
7.41k
          {
1785
0
          case Undefined_PNM_Format: break;
1786
0
          case PBM_ASCII_Format: header="P1"; break;
1787
0
          case PGM_ASCII_Format: header="P2"; break;
1788
0
          case PPM_ASCII_Format: header="P3"; break;
1789
1.65k
          case PBM_RAW_Format:   header="P4"; break;
1790
1.39k
          case PGM_RAW_Format:   header="P5"; break;
1791
1.93k
          case PPM_RAW_Format:   header="P6"; break;
1792
1.35k
          case PAM_Format:       header="P7"; break;
1793
1.07k
          case XV_332_Format:    header="P7 332"; break;
1794
7.41k
          }
1795
7.41k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Format Id: %s",
1796
7.41k
                              header);
1797
7.41k
        (void) WriteBlobString(image,header);
1798
7.41k
        (void) WriteBlobByte(image,'\n');
1799
7.41k
      }
1800
1801
0
      attribute=GetImageAttribute(image,"comment");
1802
7.41k
      if (attribute != (const ImageAttribute *) NULL)
1803
1.55k
        {
1804
1.55k
          register char
1805
1.55k
            *av;
1806
1807
          /*
1808
            Write comments to file.
1809
          */
1810
1.55k
          (void) WriteBlobByte(image,'#');
1811
89.2M
          for (av=attribute->value; *av != '\0'; av++)
1812
89.2M
            {
1813
89.2M
              (void) WriteBlobByte(image,*av);
1814
89.2M
              if ((*av == '\n') && (*(av+1) != '\0'))
1815
26.9k
                (void) WriteBlobByte(image,'#');
1816
89.2M
            }
1817
1.55k
          (void) WriteBlobByte(image,'\n');
1818
1.55k
        }
1819
7.41k
      if ((PAM_Format != format) && (XV_332_Format != format))
1820
4.97k
        {
1821
4.97k
          MagickFormatString(buffer,sizeof(buffer),"%lu %lu\n",image->columns,image->rows);
1822
4.97k
          (void) WriteBlobString(image,buffer);
1823
4.97k
        }
1824
      /*
1825
        Write PNM raster pixels.
1826
      */
1827
7.41k
      switch (format)
1828
7.41k
        {
1829
0
        case PBM_ASCII_Format:
1830
0
          {
1831
0
            unsigned int
1832
0
              polarity;
1833
1834
0
            size_t
1835
0
              j;
1836
1837
            /*
1838
              Convert image to a PBM ASCII image.
1839
            */
1840
0
            status &= SetImageType(image,BilevelType);
1841
0
            if ((status &= SetImageType(image,BilevelType)) == MagickFail)
1842
0
              ThrowWriterException(CoderError,UnableToSetImageType,image);
1843
0
            polarity=PixelIntensityToQuantum(&image->colormap[0]) < (MaxRGB/2);
1844
0
            if (image->colors == 2)
1845
0
              polarity=PixelIntensityToQuantum(&image->colormap[0]) <
1846
0
                PixelIntensityToQuantum(&image->colormap[1]);
1847
0
            i=0;
1848
0
            j=0;
1849
0
            for (y=0; y < image->rows; y++)
1850
0
              {
1851
0
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1852
0
                if (p == (const PixelPacket *) NULL)
1853
0
                  {
1854
0
                    status=MagickFail;
1855
0
                    break;
1856
0
                  }
1857
0
                indexes=AccessImmutableIndexes(image);
1858
0
                for (x=0; x < image->columns; x++)
1859
0
                  {
1860
0
                    buffer[j++] = (indexes[x] == polarity ? '0' : '1');
1861
0
                    buffer[j++] = ' ';
1862
0
                    i++;
1863
0
                    if (i == 36)
1864
0
                      {
1865
0
                        buffer[j++] = '\n';
1866
0
                        i=0;
1867
0
                      }
1868
0
                    if (j+4 > sizeof(buffer))
1869
0
                      {
1870
0
                        status=(WriteBlob(image,j,buffer) == j);
1871
0
                        j=0;
1872
0
                        if (MagickFail == status)
1873
0
                          break;
1874
0
                      }
1875
0
                  }
1876
0
                if (image->previous == (Image *) NULL)
1877
0
                  if (QuantumTick(y,image->rows))
1878
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1879
0
                                                SaveImageText,image->filename,
1880
0
                                                image->columns,image->rows))
1881
0
                      {
1882
0
                        status=MagickFail;
1883
0
                        break;
1884
0
                      }
1885
0
                if (MagickFail == status)
1886
0
                  break;
1887
0
              }
1888
0
            if (MagickFail != status)
1889
0
              {
1890
0
                if (i != 0)
1891
0
                  buffer[j++] = '\n';
1892
0
                if (j > 0)
1893
0
                  status=(WriteBlob(image,j,buffer) == j);
1894
0
              }
1895
0
            break;
1896
0
          }
1897
0
        case PGM_ASCII_Format:
1898
0
          {
1899
            /*
1900
              Convert image to a PGM ASCII image.
1901
            */
1902
0
            size_t
1903
0
              j;
1904
1905
0
            unsigned int
1906
0
              value;
1907
1908
            /*
1909
              Make sure that image is in an RGB type space.
1910
            */
1911
0
            if (TransformColorspace(image,RGBColorspace) == MagickFail)
1912
0
              ThrowWriterException(CoderError,UnableToTransformColorspace,image);
1913
1914
0
            i=0;
1915
0
            j=0;
1916
1917
0
            value=(depth <=8 ? 255U : depth <= 16 ? 65535U : 4294967295U);
1918
1919
0
            j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u\n",value);
1920
0
            for (y=0; y < image->rows; y++)
1921
0
              {
1922
0
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1923
0
                if (p == (const PixelPacket *) NULL)
1924
0
                  {
1925
0
                    status=MagickFail;
1926
0
                    break;
1927
0
                  }
1928
0
                for (x=0; x < image->columns; x++)
1929
0
                  {
1930
0
                    if (image->is_grayscale)
1931
0
                      index=p->red;
1932
0
                    else
1933
0
                      index=PixelIntensityToQuantum(p);
1934
0
                    if (depth <= 8)
1935
0
                      {
1936
                        /* Use LUT for speed */
1937
0
                        value=ScaleQuantumToChar(index);
1938
0
                        AppendUnsignedCharValueToString(j,buffer,value);
1939
0
                        buffer[j++] = ' ';
1940
0
                      }
1941
0
                    else if (depth <= 16)
1942
0
                      {
1943
0
                        value=ScaleQuantumToShort(index);
1944
0
                        j += snprintf(&buffer[j],(sizeof(buffer)-j)," %u",value);
1945
0
                      }
1946
0
                    else
1947
0
                      {
1948
0
                        value=ScaleQuantumToLong(index);
1949
0
                        j += snprintf(&buffer[j],(sizeof(buffer)-j)," %u",value);
1950
0
                      }
1951
1952
0
                    i++;
1953
0
                    if (i == 12)
1954
0
                      {
1955
0
                        buffer[j++] = '\n';
1956
0
                        i=0;
1957
0
                      }
1958
0
                    if (j+8 > sizeof(buffer))
1959
0
                      {
1960
0
                        status=(WriteBlob(image,j,buffer) == j);
1961
0
                        j=0;
1962
0
                        if (MagickFail == status)
1963
0
                          break;
1964
0
                      }
1965
0
                    p++;
1966
0
                  }
1967
0
                if (image->previous == (Image *) NULL)
1968
0
                  if (QuantumTick(y,image->rows))
1969
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1970
0
                                                SaveImageText,image->filename,
1971
0
                                                image->columns,image->rows))
1972
0
                      {
1973
0
                        status=MagickFail;
1974
0
                        break;
1975
0
                      }
1976
0
                if (MagickFail == status)
1977
0
                  break;
1978
0
              }
1979
0
            if (MagickFail != status)
1980
0
              {
1981
0
                if (i != 0)
1982
0
                  buffer[j++] = '\n';
1983
0
                if (j > 0)
1984
0
                  status=(WriteBlob(image,j,buffer) == j);
1985
0
              }
1986
0
            break;
1987
0
          }
1988
0
        case PPM_ASCII_Format:
1989
0
          {
1990
            /*
1991
              Convert image to a PPM ASCII image.
1992
            */
1993
0
            size_t
1994
0
              j;
1995
1996
0
            unsigned int
1997
0
              value;
1998
1999
            /*
2000
              Make sure that image is in an RGB type space.
2001
            */
2002
0
            if (TransformColorspace(image,RGBColorspace) == MagickFail)
2003
0
              ThrowWriterException(CoderError,UnableToTransformColorspace,image);
2004
2005
0
            i=0;
2006
0
            j=0;
2007
2008
0
            value=(depth <=8 ? 255U : (depth <= 16 ? 65535U : 4294967295U));
2009
2010
0
            j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u\n",value);
2011
0
            for (y=0; y < image->rows; y++)
2012
0
              {
2013
0
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2014
0
                if (p == (const PixelPacket *) NULL)
2015
0
                  {
2016
0
                    status=MagickFail;
2017
0
                    break;
2018
0
                  }
2019
0
                for (x=0; x < image->columns; x++)
2020
0
                  {
2021
0
                    if (depth <= 8)
2022
0
                      {
2023
                        /* Use LUT for speed */
2024
0
                        value=ScaleQuantumToChar(p->red);
2025
0
                        AppendUnsignedCharValueToString(j,buffer,value);
2026
0
                        buffer[j++] = ' ';
2027
0
                        value=ScaleQuantumToChar(p->green);
2028
0
                        AppendUnsignedCharValueToString(j,buffer,value);
2029
0
                        buffer[j++] = ' ';
2030
0
                        value=ScaleQuantumToChar(p->blue);
2031
0
                        AppendUnsignedCharValueToString(j,buffer,value);
2032
0
                        buffer[j++] = ' ';
2033
0
                      }
2034
0
                    else if (depth <= 16)
2035
0
                      {
2036
0
                        j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u %u %u ",
2037
0
                                      ScaleQuantumToShort(p->red),
2038
0
                                      ScaleQuantumToShort(p->green),
2039
0
                                      ScaleQuantumToShort(p->blue));
2040
0
                      }
2041
0
                    else
2042
0
                      {
2043
0
                        j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u %u %u ",
2044
0
                                      (unsigned int) ScaleQuantumToLong(p->red),
2045
0
                                      (unsigned int) ScaleQuantumToLong(p->green),
2046
0
                                      (unsigned int) ScaleQuantumToLong(p->blue));
2047
0
                      }
2048
0
                    i++;
2049
0
                    if (i == 4)
2050
0
                      {
2051
0
                        buffer[j++] = '\n';
2052
0
                        i=0;
2053
0
                      }
2054
0
                    if (j+(8*3) > sizeof(buffer))
2055
0
                      {
2056
0
                        status=(WriteBlob(image,j,buffer) == j);
2057
0
                        j=0;
2058
0
                        if (MagickFail == status)
2059
0
                          break;
2060
0
                      }
2061
0
                    p++;
2062
0
                  }
2063
0
                if (image->previous == (Image *) NULL)
2064
0
                  if (QuantumTick(y,image->rows))
2065
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2066
0
                                                SaveImageText,image->filename,
2067
0
                                                image->columns,image->rows))
2068
0
                      {
2069
0
                        status=MagickFail;
2070
0
                        break;
2071
0
                      }
2072
0
                if (MagickFail == status)
2073
0
                  break;
2074
0
              }
2075
0
            if (MagickFail != status)
2076
0
              {
2077
0
                if (i != 0)
2078
0
                  buffer[j++] = '\n';
2079
0
                if (j > 0)
2080
0
                  status=(WriteBlob(image,j,buffer) == j);
2081
0
              }
2082
0
            break;
2083
0
          }
2084
1.65k
        case PBM_RAW_Format:
2085
3.04k
        case PGM_RAW_Format:
2086
4.97k
        case PPM_RAW_Format:
2087
6.33k
        case PAM_Format:
2088
6.33k
          {
2089
6.33k
            ExportPixelAreaOptions
2090
6.33k
              export_options;
2091
2092
6.33k
            size_t
2093
6.33k
              bytes_per_row;
2094
2095
6.33k
            QuantumType
2096
6.33k
              quantum_type;
2097
2098
6.33k
            unsigned int
2099
6.33k
              bits_per_sample,
2100
6.33k
              samples_per_pixel;
2101
2102
6.33k
            MagickBool
2103
6.33k
              grayscale_miniswhite=MagickFalse;
2104
2105
6.33k
            unsigned char
2106
6.33k
              *pixels;
2107
2108
            /*
2109
              Deduce correct export parameters.
2110
            */
2111
6.33k
            bits_per_sample=(depth <=8 ? 8 : (depth <= 16 ? 16 : 32));
2112
6.33k
            quantum_type=RGBQuantum;
2113
6.33k
            if (PBM_RAW_Format == format)
2114
1.65k
              {
2115
1.65k
                bits_per_sample=1;
2116
1.65k
                grayscale_miniswhite=MagickTrue;
2117
1.65k
                quantum_type=GrayQuantum;
2118
1.65k
              }
2119
4.68k
            else if (PGM_RAW_Format == format)
2120
1.39k
              {
2121
1.39k
                quantum_type=GrayQuantum;
2122
1.39k
              }
2123
3.29k
            else if (PPM_RAW_Format == format)
2124
1.93k
              {
2125
1.93k
                quantum_type=RGBQuantum;
2126
1.93k
              }
2127
1.35k
            else if (PAM_Format == format)
2128
1.35k
              {
2129
1.35k
                ImageCharacteristics
2130
1.35k
                  characteristics;
2131
2132
                /*
2133
                  Make sure image is of desired type.
2134
                */
2135
1.35k
                if (UndefinedType != image_info->type)
2136
0
                  if ((status &= SetImageType(image,image_info->type)) == MagickFail)
2137
1.35k
                    ThrowWriterException(CoderError,UnableToSetImageType,image);
2138
2139
                /*
2140
                  Analyze the image to get its characteristics.
2141
                */
2142
1.35k
                if ((status &= GetImageCharacteristics(image,&characteristics,
2143
1.35k
                                                       (OptimizeType == image_info->type),
2144
1.35k
                                                       &image->exception)) == MagickFail)
2145
0
                  {
2146
0
                    CloseBlob(image);
2147
0
                    return MagickFail;
2148
0
                  }
2149
2150
                /*
2151
                  Choose best encoding based on image characteristics.
2152
                */
2153
1.35k
                if (characteristics.cmyk)
2154
373
                  {
2155
373
                    if (image->matte)
2156
153
                      quantum_type=CMYKAQuantum;
2157
220
                    else
2158
220
                      quantum_type=CMYKQuantum;
2159
373
                  }
2160
985
                else if (characteristics.monochrome)
2161
426
                  {
2162
426
                    bits_per_sample=1;
2163
426
                    grayscale_miniswhite=MagickTrue;
2164
2165
426
                    if (image->matte)
2166
84
                      quantum_type=GrayAlphaQuantum;
2167
342
                    else
2168
342
                      quantum_type=GrayQuantum;
2169
426
                  }
2170
559
                else if (characteristics.grayscale)
2171
217
                  {
2172
217
                    if (image->matte)
2173
74
                      quantum_type=GrayAlphaQuantum;
2174
143
                    else
2175
143
                      quantum_type=GrayQuantum;
2176
217
                  }
2177
342
                else
2178
342
                  {
2179
342
                    if (image->matte)
2180
54
                      quantum_type=RGBAQuantum;
2181
288
                    else
2182
288
                      quantum_type=RGBQuantum;
2183
342
                  }
2184
1.35k
              }
2185
6.33k
            if (image->logging)
2186
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187
0
                                    "Export Quantum Type: %s",
2188
0
                                    QuantumTypeToString(quantum_type));
2189
2190
6.33k
            samples_per_pixel=MagickGetQuantumSamplesPerPixel(quantum_type);
2191
6.33k
            if (image->logging)
2192
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2193
0
                                    "Samples/Pixel: %u", samples_per_pixel);
2194
2195
6.33k
            if (1 == bits_per_sample)
2196
2.07k
              {
2197
                /* bytes_per_row=(((size_t) image->columns*samples_per_pixel+7) >> 3); */
2198
2.07k
                bytes_per_row=MagickArraySize(image->columns,samples_per_pixel);
2199
2.07k
                if (bytes_per_row)
2200
2.07k
                  bytes_per_row += 7;
2201
2.07k
                if (bytes_per_row)
2202
2.07k
                  bytes_per_row >>= 3;
2203
2.07k
              }
2204
4.25k
            else
2205
4.25k
              {
2206
4.25k
                bytes_per_row=MagickArraySize((((size_t) bits_per_sample+7)/8)*
2207
4.25k
                                              samples_per_pixel,image->columns);
2208
4.25k
              }
2209
2210
6.33k
            if (image->logging)
2211
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2212
0
                                    "Bytes/Row: %" MAGICK_SIZE_T_F "u",
2213
0
                                    (MAGICK_SIZE_T) bytes_per_row);
2214
2215
6.33k
            ExportPixelAreaOptionsInit(&export_options);
2216
6.33k
            export_options.grayscale_miniswhite=grayscale_miniswhite;
2217
2218
            /*
2219
              Allocate memory for pixels.
2220
            */
2221
6.33k
            pixels=MagickAllocateResourceLimitedMemory(unsigned char *,bytes_per_row);
2222
6.33k
            if (pixels == (unsigned char *) NULL)
2223
0
              ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
2224
6.33k
                                   image);
2225
2226
            /*
2227
              Output header details
2228
            */
2229
6.33k
            if (PAM_Format == format)
2230
1.35k
              {
2231
                /*
2232
                  PAM header
2233
                */
2234
1.35k
                const char *tuple_type=NULL;
2235
2236
1.35k
                if (GrayQuantum == quantum_type)
2237
485
                  {
2238
485
                    if (1 == bits_per_sample)
2239
342
                      tuple_type="BLACKANDWHITE";
2240
143
                    else
2241
143
                      tuple_type="GRAYSCALE";
2242
485
                  }
2243
873
                else if (GrayAlphaQuantum == quantum_type)
2244
158
                  {
2245
158
                    if (1 == bits_per_sample)
2246
84
                      tuple_type="BLACKANDWHITE_ALPHA";
2247
74
                    else
2248
74
                      tuple_type="GRAYSCALE_ALPHA";
2249
158
                  }
2250
715
                else if (RGBQuantum == quantum_type)
2251
288
                  tuple_type="RGB";
2252
427
                else if (RGBAQuantum == quantum_type)
2253
54
                  tuple_type="RGB_ALPHA";
2254
373
                else if (CMYKQuantum == quantum_type)
2255
220
                  tuple_type="CMYK";
2256
153
                else if (CMYKAQuantum == quantum_type)
2257
153
                  tuple_type="CMYK_ALPHA";
2258
2259
1.35k
                MagickFormatString(buffer,sizeof(buffer),"WIDTH %lu\nHEIGHT %lu\nDEPTH %u"
2260
1.35k
                                   "\nMAXVAL %lu\nTUPLTYPE %s\n",
2261
1.35k
                                   image->columns,image->rows,samples_per_pixel,
2262
1.35k
                                   MaxValueGivenBits(bits_per_sample),tuple_type);
2263
1.35k
                if (image->logging)
2264
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2265
0
                                        "PAM Header: WIDTH %lu, HEIGHT %lu, "
2266
0
                                        "DEPTH %u, MAXVAL %lu, TUPLTYPE %s",
2267
0
                                        image->columns,
2268
0
                                        image->rows,samples_per_pixel,
2269
0
                                        MaxValueGivenBits(bits_per_sample),
2270
0
                                        tuple_type);
2271
1.35k
                WriteBlobString(image,buffer);
2272
2273
1.35k
                (void) WriteBlobString(image,"ENDHDR\n");
2274
1.35k
              }
2275
4.97k
            else if ((PGM_RAW_Format == format) || (PPM_RAW_Format == format))
2276
3.32k
              {
2277
                /*
2278
                  PGM, PPM header
2279
                */
2280
3.32k
                MagickFormatString(buffer,sizeof(buffer),"%lu\n",MaxValueGivenBits(bits_per_sample));
2281
3.32k
                WriteBlobString(image,buffer);
2282
3.32k
              }
2283
2284
            /*
2285
              Output pixels
2286
            */
2287
398k
            for (y=0; y < image->rows; y++)
2288
391k
              {
2289
391k
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2290
391k
                if (p == (const PixelPacket *) NULL)
2291
0
                  break;
2292
391k
                if (ExportImagePixelArea(image,quantum_type,bits_per_sample,pixels,&export_options,0) == MagickFail)
2293
0
                  break;
2294
391k
                if (WriteBlob(image,bytes_per_row,(char *) pixels) != bytes_per_row)
2295
170
                  break;
2296
391k
                if (image->previous == (Image *) NULL)
2297
391k
                  if (QuantumTick(y,image->rows))
2298
112k
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2299
112k
                                                SaveImageText,image->filename,
2300
112k
                                                image->columns,image->rows))
2301
0
                      break;
2302
391k
              }
2303
6.33k
            MagickFreeResourceLimitedMemory(unsigned char *,pixels);
2304
2305
6.33k
            break;
2306
6.33k
          }
2307
1.07k
        case XV_332_Format:
2308
1.07k
          {
2309
1.07k
            static const short int
2310
1.07k
              dither_red[2][16]=
2311
1.07k
              {
2312
1.07k
                {-16,  4, -1, 11,-14,  6, -3,  9,-15,  5, -2, 10,-13,  7, -4,  8},
2313
1.07k
                { 15, -5,  0,-12, 13, -7,  2,-10, 14, -6,  1,-11, 12, -8,  3, -9}
2314
1.07k
              },
2315
1.07k
              dither_green[2][16]=
2316
1.07k
              {
2317
1.07k
                { 11,-15,  7, -3,  8,-14,  4, -2, 10,-16,  6, -4,  9,-13,  5, -1},
2318
1.07k
                {-12, 14, -8,  2, -9, 13, -5,  1,-11, 15, -7,  3,-10, 12, -6,  0}
2319
1.07k
              },
2320
1.07k
              dither_blue[2][16]=
2321
1.07k
              {
2322
1.07k
                { -3,  9,-13,  7, -1, 11,-15,  5, -4,  8,-14,  6, -2, 10,-16,  4},
2323
1.07k
                {  2,-10, 12, -8,  0,-12, 14, -6,  3, -9, 13, -7,  1,-11, 15, -5}
2324
1.07k
              };
2325
2326
1.07k
            long
2327
1.07k
              value;
2328
2329
1.07k
            Quantum
2330
1.07k
              pixel;
2331
2332
1.07k
            unsigned short
2333
1.07k
              *blue_map[2][16],
2334
1.07k
              *green_map[2][16],
2335
1.07k
              *red_map[2][16];
2336
2337
1.07k
            unsigned int
2338
1.07k
              j;
2339
2340
            /*
2341
              Allocate and initialize dither maps.
2342
            */
2343
1.07k
            memset(blue_map,0,sizeof(blue_map));
2344
1.07k
            memset(green_map,0,sizeof(green_map));
2345
1.07k
            memset(red_map,0,sizeof(red_map));
2346
3.23k
            for (i=0; i < 2; i++)
2347
36.6k
              for (j=0; j < 16; j++)
2348
34.5k
                {
2349
34.5k
                  red_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *,
2350
34.5k
                                                                    256*sizeof(unsigned short));
2351
34.5k
                  green_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *,
2352
34.5k
                                                                      256*sizeof(unsigned short));
2353
34.5k
                  blue_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *,
2354
34.5k
                                                                     256*sizeof(unsigned short));
2355
34.5k
                  if ((red_map[i][j] == (unsigned short *) NULL) ||
2356
34.5k
                      (green_map[i][j] == (unsigned short *) NULL) ||
2357
34.5k
                      (blue_map[i][j] == (unsigned short *) NULL))
2358
0
                    {
2359
0
                      for (i=0; i < 2; i++)
2360
0
                        for (j=0; j < 16; j++)
2361
0
                          {
2362
0
                            MagickFreeResourceLimitedMemory(unsigned short *,green_map[i][j]);
2363
0
                            MagickFreeResourceLimitedMemory(unsigned short *,blue_map[i][j]);
2364
0
                            MagickFreeResourceLimitedMemory(unsigned short *,red_map[i][j]);
2365
0
                          }
2366
0
                      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
2367
0
                                           image);
2368
0
                    }
2369
34.5k
                }
2370
            /*
2371
              Initialize dither tables.
2372
            */
2373
3.23k
            for (i=0; i < 2; i++)
2374
36.6k
              for (j=0; j < 16; j++)
2375
8.87M
                for (x=0; x < 256; x++)
2376
8.83M
                  {
2377
8.83M
                    value=x-16;
2378
8.83M
                    if (x < 48)
2379
1.65M
                      value=x/2+8;
2380
8.83M
                    value+=dither_red[i][j];
2381
8.83M
                    red_map[i][j][x]=(unsigned short)
2382
8.83M
                      ((value < 0) ? 0 : (value > 255) ? 255 : value);
2383
8.83M
                    value=x-16;
2384
8.83M
                    if (x < 48)
2385
1.65M
                      value=x/2+8;
2386
8.83M
                    value+=dither_green[i][j];
2387
8.83M
                    green_map[i][j][x]=(unsigned short)
2388
8.83M
                      ((value < 0) ? 0 : (value > 255) ? 255 : value);
2389
8.83M
                    value=x-32;
2390
8.83M
                    if (x < 112)
2391
3.86M
                      value=x/2+24;
2392
8.83M
                    value+=2*dither_blue[i][j];
2393
8.83M
                    blue_map[i][j][x]=(unsigned short)
2394
8.83M
                      ((value < 0) ? 0 : (value > 255) ? 255 : value);
2395
8.83M
                  }
2396
            /*
2397
              Write pixels.
2398
            */
2399
1.07k
            (void) WriteBlobString(image,"#END_OF_COMMENTS\n");
2400
1.07k
            MagickFormatString(buffer,sizeof(buffer),"%lu %lu 255\n",image->columns,image->rows);
2401
1.07k
            (void) WriteBlobString(image,buffer);
2402
1.07k
            i=0;
2403
1.07k
            j=0;
2404
101k
            for (y=0; y < image->rows; y++)
2405
100k
              {
2406
100k
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2407
100k
                if (p == (const PixelPacket *) NULL)
2408
0
                  break;
2409
58.5M
                for (x=0; x < image->columns; x++)
2410
58.4M
                  {
2411
58.4M
                    if (!image_info->dither)
2412
0
                      pixel=(Quantum) ((ScaleQuantumToChar(p->red) & 0xe0) |
2413
0
                                       ((ScaleQuantumToChar(p->green) & 0xe0) >> 3) |
2414
0
                                       ((ScaleQuantumToChar(p->blue) & 0xc0) >> 6));
2415
58.4M
                    else
2416
58.4M
                      pixel=(Quantum)
2417
58.4M
                        ((red_map[i][j][ScaleQuantumToChar(p->red)] & 0xe0) |
2418
58.4M
                         ((green_map[i][j][ScaleQuantumToChar(p->green)] & 0xe0) >> 3) |
2419
58.4M
                         ((blue_map[i][j][ScaleQuantumToChar(p->blue)] & 0xc0) >> 6));
2420
58.4M
                    (void) WriteBlobByte(image,pixel);
2421
58.4M
                    p++;
2422
58.4M
                    j++;
2423
58.4M
                    if (j == 16)
2424
3.65M
                      j=0;
2425
58.4M
                  }
2426
100k
                i++;
2427
100k
                if (i == 2)
2428
49.8k
                  i=0;
2429
100k
                if (QuantumTick(y,image->rows))
2430
22.1k
                  if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2431
22.1k
                                              SaveImageText,image->filename,
2432
22.1k
                                              image->columns,image->rows))
2433
0
                    break;
2434
100k
              }
2435
            /*
2436
              Free allocated memory.
2437
            */
2438
3.23k
            for (i=0; i < 2; i++)
2439
36.6k
              for (j=0; j < 16; j++)
2440
34.5k
                {
2441
34.5k
                  MagickFreeResourceLimitedMemory(unsigned short *,green_map[i][j]);
2442
34.5k
                  MagickFreeResourceLimitedMemory(unsigned short *,blue_map[i][j]);
2443
34.5k
                  MagickFreeResourceLimitedMemory(unsigned short *,red_map[i][j]);
2444
34.5k
                }
2445
1.07k
            break;
2446
1.07k
          }
2447
0
        case Undefined_PNM_Format:
2448
0
          break;
2449
7.41k
        }
2450
7.41k
      if (image->next == (Image *) NULL)
2451
7.41k
        break;
2452
0
      image=SyncNextImageInList(image);
2453
0
      if (status != MagickFail)
2454
0
        status=MagickMonitorFormatted(scene++,image_list_length,
2455
0
                                      &image->exception,SaveImagesText,
2456
0
                                      image->filename);
2457
0
      if (status == MagickFail)
2458
0
        break;
2459
0
    } while (image_info->adjoin);
2460
7.41k
  if (image_info->adjoin)
2461
7.41k
    while (image->previous != (Image *) NULL)
2462
0
      image=image->previous;
2463
7.41k
  status &= CloseBlob(image);
2464
7.41k
  return(status);
2465
7.41k
}