]> granicus.if.org Git - imagemagick/blob - coders/pnm.c
d31bd475e23997166e90ec0d3dca3189dba376be
[imagemagick] / coders / pnm.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            PPPP   N   N  M   M                              %
7 %                            P   P  NN  N  MM MM                              %
8 %                            PPPP   N N N  M M M                              %
9 %                            P      N  NN  M   M                              %
10 %                            P      N   N  M   M                              %
11 %                                                                             %
12 %                                                                             %
13 %               Read/Write PBMPlus Portable Anymap Image Format               %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/image.h"
54 #include "MagickCore/image-private.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/module.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/property.h"
63 #include "MagickCore/quantum-private.h"
64 #include "MagickCore/static.h"
65 #include "MagickCore/statistic.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/string-private.h"
68 \f
69 /*
70   Forward declarations.
71 */
72 static MagickBooleanType
73   WritePNMImage(const ImageInfo *,Image *,ExceptionInfo *);
74 \f
75 /*
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %                                                                             %
78 %                                                                             %
79 %                                                                             %
80 %   I s P N M                                                                 %
81 %                                                                             %
82 %                                                                             %
83 %                                                                             %
84 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 %
86 %  IsPNM() returns MagickTrue if the image format type, identified by the
87 %  magick string, is PNM.
88 %
89 %  The format of the IsPNM method is:
90 %
91 %      MagickBooleanType IsPNM(const unsigned char *magick,const size_t extent)
92 %
93 %  A description of each parameter follows:
94 %
95 %    o magick: compare image format pattern against these bytes.
96 %
97 %    o extent: Specifies the extent of the magick string.
98 %
99 */
100 static MagickBooleanType IsPNM(const unsigned char *magick,const size_t extent)
101 {
102   if (extent < 2)
103     return(MagickFalse);
104   if ((*magick == (unsigned char) 'P') &&
105       ((magick[1] == '1') || (magick[1] == '2') || (magick[1] == '3') ||
106        (magick[1] == '4') || (magick[1] == '5') || (magick[1] == '6') ||
107        (magick[1] == '7') || (magick[1] == 'F') || (magick[1] == 'f')))
108     return(MagickTrue);
109   return(MagickFalse);
110 }
111 \f
112 /*
113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114 %                                                                             %
115 %                                                                             %
116 %                                                                             %
117 %   R e a d P N M I m a g e                                                   %
118 %                                                                             %
119 %                                                                             %
120 %                                                                             %
121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122 %
123 %  ReadPNMImage() reads a Portable Anymap image file and returns it.
124 %  It allocates the memory necessary for the new Image structure and returns
125 %  a pointer to the new image.
126 %
127 %  The format of the ReadPNMImage method is:
128 %
129 %      Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
130 %
131 %  A description of each parameter follows:
132 %
133 %    o image_info: the image info.
134 %
135 %    o exception: return any errors or warnings in this structure.
136 %
137 */
138
139 static int PNMComment(Image *image,ExceptionInfo *exception)
140 {
141   int
142     c;
143
144   char
145     *comment;
146
147   register char
148     *p;
149
150   size_t
151     extent;
152
153   /*
154     Read comment.
155   */
156   comment=AcquireString(GetImageProperty(image,"comment",exception));
157   p=comment+strlen(comment);
158   extent=strlen(comment)+MaxTextExtent;
159   for (c='#'; (c != EOF) && (c != (int) '\n'); p++)
160   {
161     if ((size_t) (p-comment+1) >= extent)
162       {
163         extent<<=1;
164         comment=(char *) ResizeQuantumMemory(comment,extent+MaxTextExtent,
165           sizeof(*comment));
166         if (comment == (char *) NULL)
167           break;
168         p=comment+strlen(comment);
169       }
170     c=ReadBlobByte(image);
171     if (c != EOF)
172       {
173         *p=(char) c;
174         *(p+1)='\0';
175       }
176   }
177   if (comment == (char *) NULL)
178     return(c);
179   (void) SetImageProperty(image,"comment",comment,exception);
180   comment=DestroyString(comment);
181   return(c);
182 }
183
184 static unsigned int PNMInteger(Image *image,const unsigned int base,
185   ExceptionInfo *exception)
186 {
187   int
188     c;
189
190   unsigned int
191     value;
192
193   /*
194     Skip any leading whitespace.
195   */
196   do
197   {
198     c=ReadBlobByte(image);
199     if (c == EOF)
200       return(0);
201     if (c == (int) '#')
202       c=PNMComment(image,exception);
203   } while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
204   if (base == 2)
205     return((unsigned int) (c-(int) '0'));
206   /*
207     Evaluate number.
208   */
209   value=0;
210   while (isdigit(c) != 0) {
211     if (value > (unsigned int) (INT_MAX/10))
212       break;
213     value*=10;
214     if (value > (unsigned int) (INT_MAX-(c-(int) '0')))
215       break;
216     value+=c-(int) '0';
217     c=ReadBlobByte(image);
218     if (c == EOF)
219       return(0);
220   }
221   return(value);
222 }
223
224 static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
225 {
226   char
227     format;
228
229   double
230     quantum_scale;
231
232   Image
233     *image;
234
235   MagickBooleanType
236     status;
237
238   QuantumAny
239     max_value;
240
241   QuantumInfo
242     *quantum_info;
243
244   QuantumType
245     quantum_type;
246
247   size_t
248     depth,
249     extent,
250     packet_size;
251
252   ssize_t
253     count,
254     row,
255     y;
256
257   /*
258     Open image file.
259   */
260   assert(image_info != (const ImageInfo *) NULL);
261   assert(image_info->signature == MagickSignature);
262   if (image_info->debug != MagickFalse)
263     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
264       image_info->filename);
265   assert(exception != (ExceptionInfo *) NULL);
266   assert(exception->signature == MagickSignature);
267   image=AcquireImage(image_info,exception);
268   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
269   if (status == MagickFalse)
270     {
271       image=DestroyImageList(image);
272       return((Image *) NULL);
273     }
274   /*
275     Read PNM image.
276   */
277   count=ReadBlob(image,1,(unsigned char *) &format);
278   do
279   {
280     /*
281       Initialize image structure.
282     */
283     if ((count != 1) || (format != 'P'))
284       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
285     max_value=1;
286     quantum_type=RGBQuantum;
287     quantum_scale=1.0;
288     format=(char) ReadBlobByte(image);
289     if (format != '7')
290       {
291         /*
292           PBM, PGM, PPM, and PNM.
293         */
294         image->columns=(size_t) PNMInteger(image,10,exception);
295         image->rows=(size_t) PNMInteger(image,10,exception);
296         if ((format == 'f') || (format == 'F'))
297           {
298             char
299               scale[MaxTextExtent];
300
301             (void) ReadBlobString(image,scale);
302             quantum_scale=StringToDouble(scale,(char **) NULL);
303           }
304         else
305           {
306             if ((format == '1') || (format == '4'))
307               max_value=1;  /* bitmap */
308             else
309               max_value=(QuantumAny) PNMInteger(image,10,exception);
310           }
311       }
312     else
313       {
314         char
315           keyword[MaxTextExtent],
316           value[MaxTextExtent];
317
318         int
319           c;
320
321         register char
322           *p;
323
324         /*
325           PAM.
326         */
327         for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
328         {
329           while (isspace((int) ((unsigned char) c)) != 0)
330             c=ReadBlobByte(image);
331           if (c == '#')
332             {
333               /*
334                 Comment.
335               */
336               c=PNMComment(image,exception);
337               c=ReadBlobByte(image);
338               while (isspace((int) ((unsigned char) c)) != 0)
339                 c=ReadBlobByte(image);
340             }
341           p=keyword;
342           do
343           {
344             if ((size_t) (p-keyword) < (MaxTextExtent-1))
345               *p++=c;
346             c=ReadBlobByte(image);
347           } while (isalnum(c));
348           *p='\0';
349           if (LocaleCompare(keyword,"endhdr") == 0)
350             break;
351           while (isspace((int) ((unsigned char) c)) != 0)
352             c=ReadBlobByte(image);
353           p=value;
354           while (isalnum(c) || (c == '_'))
355           {
356             if ((size_t) (p-value) < (MaxTextExtent-1))
357               *p++=c;
358             c=ReadBlobByte(image);
359           }
360           *p='\0';
361           /*
362             Assign a value to the specified keyword.
363           */
364           if (LocaleCompare(keyword,"depth") == 0)
365             packet_size=StringToUnsignedLong(value);
366           (void) packet_size;
367           if (LocaleCompare(keyword,"height") == 0)
368             image->rows=StringToUnsignedLong(value);
369           if (LocaleCompare(keyword,"maxval") == 0)
370             max_value=StringToUnsignedLong(value);
371           if (LocaleCompare(keyword,"TUPLTYPE") == 0)
372             {
373               if (LocaleCompare(value,"BLACKANDWHITE") == 0)
374                 {
375                   (void) SetImageColorspace(image,GRAYColorspace,exception);
376                   quantum_type=GrayQuantum;
377                 }
378               if (LocaleCompare(value,"BLACKANDWHITE_ALPHA") == 0)
379                 {
380                   (void) SetImageColorspace(image,GRAYColorspace,exception);
381                   image->alpha_trait=BlendPixelTrait;
382                   quantum_type=GrayAlphaQuantum;
383                 }
384               if (LocaleCompare(value,"GRAYSCALE") == 0)
385                 {
386                   quantum_type=GrayQuantum;
387                   (void) SetImageColorspace(image,GRAYColorspace,exception);
388                 }
389               if (LocaleCompare(value,"GRAYSCALE_ALPHA") == 0)
390                 {
391                   (void) SetImageColorspace(image,GRAYColorspace,exception);
392                   image->alpha_trait=BlendPixelTrait;
393                   quantum_type=GrayAlphaQuantum;
394                 }
395               if (LocaleCompare(value,"RGB_ALPHA") == 0)
396                 {
397                   image->alpha_trait=BlendPixelTrait;
398                   quantum_type=RGBAQuantum;
399                 }
400               if (LocaleCompare(value,"CMYK") == 0)
401                 {
402                   (void) SetImageColorspace(image,CMYKColorspace,exception);
403                   quantum_type=CMYKQuantum;
404                 }
405               if (LocaleCompare(value,"CMYK_ALPHA") == 0)
406                 {
407                   (void) SetImageColorspace(image,CMYKColorspace,exception);
408                   image->alpha_trait=BlendPixelTrait;
409                   quantum_type=CMYKAQuantum;
410                 }
411             }
412           if (LocaleCompare(keyword,"width") == 0)
413             image->columns=StringToUnsignedLong(value);
414         }
415       }
416     if ((image->columns == 0) || (image->rows == 0))
417       ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
418     if ((max_value == 0) || (max_value > 4294967295))
419       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
420     for (depth=1; GetQuantumRange(depth) < max_value; depth++) ;
421     image->depth=depth;
422     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
423       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
424         break;
425     status=SetImageExtent(image,image->columns,image->rows,exception);
426     if (status == MagickFalse)
427       return(DestroyImageList(image));
428     /*
429       Convert PNM pixels to runextent-encoded MIFF packets.
430     */
431     row=0;
432     switch (format)
433     {
434       case '1':
435       {
436         /*
437           Convert PBM image to pixel packets.
438         */
439         (void) SetImageColorspace(image,GRAYColorspace,exception);
440         for (y=0; y < (ssize_t) image->rows; y++)
441         {
442           register ssize_t
443             x;
444
445           register Quantum
446             *restrict q;
447
448           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
449           if (q == (Quantum *) NULL)
450             break;
451           for (x=0; x < (ssize_t) image->columns; x++)
452           {
453             SetPixelGray(image,PNMInteger(image,2,exception) == 0 ?
454               QuantumRange : 0,q);
455             q+=GetPixelChannels(image);
456           }
457           if (SyncAuthenticPixels(image,exception) == MagickFalse)
458             break;
459           if (image->previous == (Image *) NULL)
460             {
461               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
462                 image->rows);
463               if (status == MagickFalse)
464                 break;
465             }
466         }
467         image->type=BilevelType;
468         break;
469       }
470       case '2':
471       {
472         Quantum
473           intensity;
474
475         /*
476           Convert PGM image to pixel packets.
477         */
478         (void) SetImageColorspace(image,GRAYColorspace,exception);
479         for (y=0; y < (ssize_t) image->rows; y++)
480         {
481           register ssize_t
482             x;
483
484           register Quantum
485             *restrict q;
486
487           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
488           if (q == (Quantum *) NULL)
489             break;
490           for (x=0; x < (ssize_t) image->columns; x++)
491           {
492             intensity=ScaleAnyToQuantum(PNMInteger(image,10,exception),
493               max_value);
494             SetPixelGray(image,intensity,q);
495             q+=GetPixelChannels(image);
496           }
497           if (SyncAuthenticPixels(image,exception) == MagickFalse)
498             break;
499           if (image->previous == (Image *) NULL)
500             {
501               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
502                 image->rows);
503               if (status == MagickFalse)
504                 break;
505             }
506         }
507         image->type=GrayscaleType;
508         break;
509       }
510       case '3':
511       {
512         /*
513           Convert PNM image to pixel packets.
514         */
515         for (y=0; y < (ssize_t) image->rows; y++)
516         {
517           register ssize_t
518             x;
519
520           register Quantum
521             *restrict q;
522
523           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
524           if (q == (Quantum *) NULL)
525             break;
526           for (x=0; x < (ssize_t) image->columns; x++)
527           {
528             Quantum
529               pixel;
530
531             pixel=ScaleAnyToQuantum(PNMInteger(image,10,exception),max_value);
532             SetPixelRed(image,pixel,q);
533             pixel=ScaleAnyToQuantum(PNMInteger(image,10,exception),max_value);
534             SetPixelGreen(image,pixel,q);
535             pixel=ScaleAnyToQuantum(PNMInteger(image,10,exception),max_value);
536             SetPixelBlue(image,pixel,q);
537             q+=GetPixelChannels(image);
538           }
539           if (SyncAuthenticPixels(image,exception) == MagickFalse)
540             break;
541           if (image->previous == (Image *) NULL)
542             {
543               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
544                 image->rows);
545               if (status == MagickFalse)
546                 break;
547             }
548         }
549         break;
550       }
551       case '4':
552       {
553         /*
554           Convert PBM raw image to pixel packets.
555         */
556         (void) SetImageColorspace(image,GRAYColorspace,exception);
557         quantum_type=GrayQuantum;
558         if (image->storage_class == PseudoClass)
559           quantum_type=IndexQuantum;
560         quantum_info=AcquireQuantumInfo(image_info,image);
561         if (quantum_info == (QuantumInfo *) NULL)
562           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
563         SetQuantumMinIsWhite(quantum_info,MagickTrue);
564         extent=GetQuantumExtent(image,quantum_info,quantum_type);
565         for (y=0; y < (ssize_t) image->rows; y++)
566         {
567           const void
568             *pixels;
569
570           MagickBooleanType
571             sync;
572
573           register Quantum
574             *restrict q;
575
576           ssize_t
577             count,
578             offset;
579
580           size_t
581             length;
582
583           if (status == MagickFalse)
584             continue;
585           pixels=ReadBlobStream(image,extent,GetQuantumPixels(quantum_info),
586             &count);
587           if (count != (ssize_t) extent)
588             status=MagickFalse;
589           if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
590               (image->previous == (Image *) NULL))
591             {
592               MagickBooleanType
593                 proceed;
594
595               proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
596                 row,image->rows);
597               if (proceed == MagickFalse)
598                 status=MagickFalse;
599             }
600           offset=row++;
601           q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
602           if (q == (Quantum *) NULL)
603             {
604               status=MagickFalse;
605               continue;
606             }
607           length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
608             quantum_type,pixels,exception);
609           if (length != extent)
610             status=MagickFalse;
611           sync=SyncAuthenticPixels(image,exception);
612           if (sync == MagickFalse)
613             status=MagickFalse;
614         }
615         quantum_info=DestroyQuantumInfo(quantum_info);
616         if (status == MagickFalse)
617           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
618         SetQuantumImageType(image,quantum_type);
619         break;
620       }
621       case '5':
622       {
623         /*
624           Convert PGM raw image to pixel packets.
625         */
626         (void) SetImageColorspace(image,GRAYColorspace,exception);
627         quantum_type=GrayQuantum;
628         if (image->depth <= 8)
629           extent=image->columns;
630         else
631           if (image->depth <= 16)
632             extent=2*image->columns;
633           else
634             extent=4*image->columns;
635         quantum_info=AcquireQuantumInfo(image_info,image);
636         if (quantum_info == (QuantumInfo *) NULL)
637           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
638         for (y=0; y < (ssize_t) image->rows; y++)
639         {
640           const void
641             *pixels;
642
643           MagickBooleanType
644             sync;
645
646           register const unsigned char
647             *restrict p;
648
649           register ssize_t
650             x;
651
652           register Quantum
653             *restrict q;
654
655           ssize_t
656             count,
657             offset;
658
659           if (status == MagickFalse)
660             continue;
661           pixels=ReadBlobStream(image,extent,GetQuantumPixels(quantum_info),
662             &count);
663           if (count != (ssize_t) extent)
664             status=MagickFalse;
665           if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
666               (image->previous == (Image *) NULL))
667             {
668               MagickBooleanType
669                 proceed;
670
671               proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
672                 row,image->rows);
673               if (proceed == MagickFalse)
674                 status=MagickFalse;
675             }
676           offset=row++;
677           q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
678           if (q == (Quantum *) NULL)
679             {
680               status=MagickFalse;
681               continue;
682             }
683           p=pixels;
684           switch (image->depth)
685           {
686             case 8:
687             case 16:
688             case 32:
689             {
690               (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
691                 quantum_type,pixels,exception);
692               break;
693             }
694             default:
695             {
696               unsigned int
697                 pixel;
698
699               if (image->depth <= 8)
700                 {
701                   unsigned char
702                     pixel;
703
704                   for (x=0; x < (ssize_t) image->columns; x++)
705                   {
706                     p=PushCharPixel(p,&pixel);
707                     SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),q);
708                     q+=GetPixelChannels(image);
709                   }
710                   break;
711                 }
712               if (image->depth <= 16)
713                 {
714                   unsigned short
715                     pixel;
716
717                   for (x=0; x < (ssize_t) image->columns; x++)
718                   {
719                     p=PushShortPixel(MSBEndian,p,&pixel);
720                     SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),q);
721                     q+=GetPixelChannels(image);
722                   }
723                   break;
724                 }
725               for (x=0; x < (ssize_t) image->columns; x++)
726               {
727                 p=PushLongPixel(MSBEndian,p,&pixel);
728                 SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),q);
729                 q+=GetPixelChannels(image);
730               }
731               break;
732             }
733           }
734           sync=SyncAuthenticPixels(image,exception);
735           if (sync == MagickFalse)
736             status=MagickFalse;
737         }
738         quantum_info=DestroyQuantumInfo(quantum_info);
739         if (status == MagickFalse)
740           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
741         SetQuantumImageType(image,quantum_type);
742         break;
743       }
744       case '6':
745       {
746         /*
747           Convert PNM raster image to pixel packets.
748         */
749         quantum_type=RGBQuantum;
750         extent=3*(image->depth <= 8 ? 1 : 2)*image->columns;
751         quantum_info=AcquireQuantumInfo(image_info,image);
752         if (quantum_info == (QuantumInfo *) NULL)
753           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
754         (void) SetQuantumEndian(image,quantum_info,MSBEndian);
755         for (y=0; y < (ssize_t) image->rows; y++)
756         {
757           const void
758             *pixels;
759
760           MagickBooleanType
761             sync;
762
763           register const unsigned char
764             *restrict p;
765
766           register ssize_t
767             x;
768
769           register Quantum
770             *restrict q;
771
772           ssize_t
773             count,
774             offset;
775
776           if (status == MagickFalse)
777             continue;
778           pixels=ReadBlobStream(image,extent,GetQuantumPixels(quantum_info),
779             &count);
780           if (count != (ssize_t) extent)
781             status=MagickFalse;
782           if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
783               (image->previous == (Image *) NULL))
784             {
785               MagickBooleanType
786                 proceed;
787
788               proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
789                 row,image->rows);
790               if (proceed == MagickFalse)
791                 status=MagickFalse;
792             }
793           offset=row++;
794           q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
795           if (q == (Quantum *) NULL)
796             {
797               status=MagickFalse;
798               continue;
799             }
800           p=pixels;
801           switch (image->depth)
802           {
803             case 8:
804             {
805               for (x=0; x < (ssize_t) image->columns; x++)
806               {
807                 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
808                 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
809                 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
810                 SetPixelAlpha(image,OpaqueAlpha,q);
811                 q+=GetPixelChannels(image);
812               }
813               break;
814             }
815             case 16:
816             {
817               unsigned short
818                 pixel;
819
820               for (x=0; x < (ssize_t) image->columns; x++)
821               {
822                 p=PushShortPixel(MSBEndian,p,&pixel);
823                 SetPixelRed(image,ScaleShortToQuantum(pixel),q);
824                 p=PushShortPixel(MSBEndian,p,&pixel);
825                 SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
826                 p=PushShortPixel(MSBEndian,p,&pixel);
827                 SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
828                 SetPixelAlpha(image,OpaqueAlpha,q);
829                 q+=GetPixelChannels(image);
830               }
831               break;
832             }
833             case 32:
834             {
835               unsigned int
836                 pixel;
837
838               for (x=0; x < (ssize_t) image->columns; x++)
839               {
840                 p=PushLongPixel(MSBEndian,p,&pixel);
841                 SetPixelRed(image,ScaleLongToQuantum(pixel),q);
842                 p=PushLongPixel(MSBEndian,p,&pixel);
843                 SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
844                 p=PushLongPixel(MSBEndian,p,&pixel);
845                 SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
846                 SetPixelAlpha(image,OpaqueAlpha,q);
847                 q+=GetPixelChannels(image);
848               }
849               break;
850             }
851             default:
852             {
853               unsigned int
854                 pixel;
855
856               if (image->depth <= 8)
857                 {
858                   unsigned char
859                     pixel;
860
861                   for (x=0; x < (ssize_t) image->columns; x++)
862                   {
863                     p=PushCharPixel(p,&pixel);
864                     SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
865                     p=PushCharPixel(p,&pixel);
866                     SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
867                     p=PushCharPixel(p,&pixel);
868                     SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
869                     SetPixelAlpha(image,OpaqueAlpha,q);
870                     q+=GetPixelChannels(image);
871                   }
872                   break;
873                 }
874               if (image->depth <= 16)
875                 {
876                   unsigned short
877                     pixel;
878
879                   for (x=0; x < (ssize_t) image->columns; x++)
880                   {
881                     p=PushShortPixel(MSBEndian,p,&pixel);
882                     SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
883                     p=PushShortPixel(MSBEndian,p,&pixel);
884                     SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
885                     p=PushShortPixel(MSBEndian,p,&pixel);
886                     SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
887                     SetPixelAlpha(image,OpaqueAlpha,q);
888                     q+=GetPixelChannels(image);
889                   }
890                   break;
891                 }
892               for (x=0; x < (ssize_t) image->columns; x++)
893               {
894                 p=PushLongPixel(MSBEndian,p,&pixel);
895                 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
896                 p=PushLongPixel(MSBEndian,p,&pixel);
897                 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
898                 p=PushLongPixel(MSBEndian,p,&pixel);
899                 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
900                 SetPixelAlpha(image,OpaqueAlpha,q);
901                 q+=GetPixelChannels(image);
902               }
903               break;
904             }
905           }
906           sync=SyncAuthenticPixels(image,exception);
907           if (sync == MagickFalse)
908             status=MagickFalse;
909         }
910         quantum_info=DestroyQuantumInfo(quantum_info);
911         if (status == MagickFalse)
912           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
913         break;
914       }
915       case '7':
916       {
917         size_t
918           channels;
919
920         /*
921           Convert PAM raster image to pixel packets.
922         */
923         switch (quantum_type)
924         {
925           case GrayQuantum:
926           case GrayAlphaQuantum:
927           {
928             channels=1;
929             break;
930           }
931           case CMYKQuantum:
932           case CMYKAQuantum:
933           {
934             channels=4;
935             break;
936           }
937           default:
938           {
939             channels=3;
940             break;
941           }
942         }
943         if (image->alpha_trait != UndefinedPixelTrait)
944           channels++;
945         if (image->depth <= 8)
946           extent=channels*image->columns;
947         else
948           if (image->depth <= 16)
949             extent=2*channels*image->columns;
950           else
951             extent=4*channels*image->columns;
952         quantum_info=AcquireQuantumInfo(image_info,image);
953         if (quantum_info == (QuantumInfo *) NULL)
954           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
955         for (y=0; y < (ssize_t) image->rows; y++)
956         {
957           const void
958             *pixels;
959
960           MagickBooleanType
961             sync;
962
963           register const unsigned char
964             *restrict p;
965
966           register ssize_t
967             x;
968
969           register Quantum
970             *restrict q;
971
972           ssize_t
973             count,
974             offset;
975
976           if (status == MagickFalse)
977             continue;
978           pixels=ReadBlobStream(image,extent,GetQuantumPixels(quantum_info),
979             &count);
980           if (count != (ssize_t) extent)
981             status=MagickFalse;
982           if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
983               (image->previous == (Image *) NULL))
984             {
985               MagickBooleanType
986                 proceed;
987
988               proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
989                 row,image->rows);
990               if (proceed == MagickFalse)
991                 status=MagickFalse;
992             }
993           offset=row++;
994           q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
995           if (q == (Quantum *) NULL)
996             {
997               status=MagickFalse;
998               continue;
999             }
1000           p=pixels;
1001           switch (image->depth)
1002           {
1003             case 8:
1004             case 16:
1005             case 32:
1006             {
1007               (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1008                 quantum_type,pixels,exception);
1009               break;
1010             }
1011             default:
1012             {
1013               switch (quantum_type)
1014               {
1015                 case GrayQuantum:
1016                 case GrayAlphaQuantum:
1017                 {
1018                   unsigned int
1019                     pixel;
1020
1021                   if (image->depth <= 8)
1022                     {
1023                       unsigned char
1024                         pixel;
1025
1026                       for (x=0; x < (ssize_t) image->columns; x++)
1027                       {
1028                         p=PushCharPixel(p,&pixel);
1029                         SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),
1030                           q);
1031                         SetPixelAlpha(image,OpaqueAlpha,q);
1032                         if (image->alpha_trait != UndefinedPixelTrait)
1033                           {
1034                             p=PushCharPixel(p,&pixel);
1035                             if (image->depth != 1)
1036                               SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1037                                 max_value),q);
1038                             else
1039                               SetPixelAlpha(image,QuantumRange-
1040                                 ScaleAnyToQuantum(pixel,max_value),q);
1041                           }
1042                         q+=GetPixelChannels(image);
1043                       }
1044                       break;
1045                     }
1046                   if (image->depth <= 16)
1047                     {
1048                       unsigned short
1049                         pixel;
1050
1051                       for (x=0; x < (ssize_t) image->columns; x++)
1052                       {
1053                         p=PushShortPixel(MSBEndian,p,&pixel);
1054                         SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),
1055                           q);
1056                         SetPixelAlpha(image,OpaqueAlpha,q);
1057                         if (image->alpha_trait != UndefinedPixelTrait)
1058                           {
1059                             p=PushShortPixel(MSBEndian,p,&pixel);
1060                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1061                               max_value),q);
1062                           }
1063                         q+=GetPixelChannels(image);
1064                       }
1065                       break;
1066                     }
1067                   for (x=0; x < (ssize_t) image->columns; x++)
1068                   {
1069                     p=PushLongPixel(MSBEndian,p,&pixel);
1070                     SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),q);
1071                     SetPixelAlpha(image,OpaqueAlpha,q);
1072                     if (image->alpha_trait != UndefinedPixelTrait)
1073                       {
1074                         p=PushLongPixel(MSBEndian,p,&pixel);
1075                         SetPixelAlpha(image,ScaleAnyToQuantum(pixel,max_value),
1076                           q);
1077                       }
1078                     q+=GetPixelChannels(image);
1079                   }
1080                   break;
1081                 }
1082                 case CMYKQuantum:
1083                 case CMYKAQuantum:
1084                 {
1085                   unsigned int
1086                     pixel;
1087
1088                   if (image->depth <= 8)
1089                     {
1090                       unsigned char
1091                         pixel;
1092
1093                       for (x=0; x < (ssize_t) image->columns; x++)
1094                       {
1095                         p=PushCharPixel(p,&pixel);
1096                         SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1097                         p=PushCharPixel(p,&pixel);
1098                         SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1099                           q);
1100                         p=PushCharPixel(p,&pixel);
1101                         SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1102                           q);
1103                         p=PushCharPixel(p,&pixel);
1104                         SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),
1105                           q);
1106                         SetPixelAlpha(image,OpaqueAlpha,q);
1107                         if (image->alpha_trait != UndefinedPixelTrait)
1108                           {
1109                             p=PushCharPixel(p,&pixel);
1110                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1111                               max_value),q);
1112                           }
1113                         q+=GetPixelChannels(image);
1114                       }
1115                       break;
1116                     }
1117                   if (image->depth <= 16)
1118                     {
1119                       unsigned short
1120                         pixel;
1121
1122                       for (x=0; x < (ssize_t) image->columns; x++)
1123                       {
1124                         p=PushShortPixel(MSBEndian,p,&pixel);
1125                         SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1126                         p=PushShortPixel(MSBEndian,p,&pixel);
1127                         SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1128                           q);
1129                         p=PushShortPixel(MSBEndian,p,&pixel);
1130                         SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1131                           q);
1132                         p=PushShortPixel(MSBEndian,p,&pixel);
1133                         SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),
1134                           q);
1135                         SetPixelAlpha(image,OpaqueAlpha,q);
1136                         if (image->alpha_trait != UndefinedPixelTrait)
1137                           {
1138                             p=PushShortPixel(MSBEndian,p,&pixel);
1139                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1140                               max_value),q);
1141                           }
1142                         q+=GetPixelChannels(image);
1143                       }
1144                     }
1145                   for (x=0; x < (ssize_t) image->columns; x++)
1146                   {
1147                     p=PushLongPixel(MSBEndian,p,&pixel);
1148                     SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1149                     p=PushLongPixel(MSBEndian,p,&pixel);
1150                     SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
1151                     p=PushLongPixel(MSBEndian,p,&pixel);
1152                     SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
1153                     p=PushLongPixel(MSBEndian,p,&pixel);
1154                     SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),q);
1155                     SetPixelAlpha(image,OpaqueAlpha,q);
1156                     if (image->alpha_trait != UndefinedPixelTrait)
1157                       {
1158                         p=PushLongPixel(MSBEndian,p,&pixel);
1159                         SetPixelAlpha(image,ScaleAnyToQuantum(pixel,max_value),
1160                           q);
1161                       }
1162                     q+=GetPixelChannels(image);
1163                   }
1164                   break;
1165                 }
1166                 default:
1167                 {
1168                   unsigned int
1169                     pixel;
1170
1171                   if (image->depth <= 8)
1172                     {
1173                       unsigned char
1174                         pixel;
1175
1176                       for (x=0; x < (ssize_t) image->columns; x++)
1177                       {
1178                         p=PushCharPixel(p,&pixel);
1179                         SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1180                         p=PushCharPixel(p,&pixel);
1181                         SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1182                           q);
1183                         p=PushCharPixel(p,&pixel);
1184                         SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1185                           q);
1186                         SetPixelAlpha(image,OpaqueAlpha,q);
1187                         if (image->alpha_trait != UndefinedPixelTrait)
1188                           {
1189                             p=PushCharPixel(p,&pixel);
1190                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1191                               max_value),q);
1192                           }
1193                         q+=GetPixelChannels(image);
1194                       }
1195                       break;
1196                     }
1197                   if (image->depth <= 16)
1198                     {
1199                       unsigned short
1200                         pixel;
1201
1202                       for (x=0; x < (ssize_t) image->columns; x++)
1203                       {
1204                         p=PushShortPixel(MSBEndian,p,&pixel);
1205                         SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1206                         p=PushShortPixel(MSBEndian,p,&pixel);
1207                         SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1208                           q);
1209                         p=PushShortPixel(MSBEndian,p,&pixel);
1210                         SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1211                           q);
1212                         SetPixelAlpha(image,OpaqueAlpha,q);
1213                         if (image->alpha_trait != UndefinedPixelTrait)
1214                           {
1215                             p=PushShortPixel(MSBEndian,p,&pixel);
1216                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1217                               max_value),q);
1218                           }
1219                         q+=GetPixelChannels(image);
1220                       }
1221                       break;
1222                     }
1223                   for (x=0; x < (ssize_t) image->columns; x++)
1224                   {
1225                     p=PushLongPixel(MSBEndian,p,&pixel);
1226                     SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1227                     p=PushLongPixel(MSBEndian,p,&pixel);
1228                     SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
1229                     p=PushLongPixel(MSBEndian,p,&pixel);
1230                     SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
1231                     SetPixelAlpha(image,OpaqueAlpha,q);
1232                     if (image->alpha_trait != UndefinedPixelTrait)
1233                       {
1234                         p=PushLongPixel(MSBEndian,p,&pixel);
1235                         SetPixelAlpha(image,ScaleAnyToQuantum(pixel,max_value),
1236                           q);
1237                       }
1238                     q+=GetPixelChannels(image);
1239                   }
1240                   break;
1241                 }
1242               }
1243             }
1244           }
1245           sync=SyncAuthenticPixels(image,exception);
1246           if (sync == MagickFalse)
1247             status=MagickFalse;
1248         }
1249         quantum_info=DestroyQuantumInfo(quantum_info);
1250         if (status == MagickFalse)
1251           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1252         SetQuantumImageType(image,quantum_type);
1253         break;
1254       }
1255       case 'F':
1256       case 'f':
1257       {
1258         /*
1259           Convert PFM raster image to pixel packets.
1260         */
1261         if (format == 'f')
1262           (void) SetImageColorspace(image,GRAYColorspace,exception);
1263         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
1264         image->endian=quantum_scale < 0.0 ? LSBEndian : MSBEndian;
1265         image->depth=32;
1266         quantum_info=AcquireQuantumInfo(image_info,image);
1267         if (quantum_info == (QuantumInfo *) NULL)
1268           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1269         status=SetQuantumDepth(image,quantum_info,32);
1270         if (status == MagickFalse)
1271           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1272         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1273         if (status == MagickFalse)
1274           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1275         SetQuantumScale(quantum_info,(double) QuantumRange*fabs(quantum_scale));
1276         extent=GetQuantumExtent(image,quantum_info,quantum_type);
1277         for (y=0; y < (ssize_t) image->rows; y++)
1278         {
1279           const void
1280             *pixels;
1281
1282           MagickBooleanType
1283             sync;
1284
1285           register Quantum
1286             *restrict q;
1287
1288           ssize_t
1289             count,
1290             offset;
1291
1292           size_t
1293             length;
1294
1295           if (status == MagickFalse)
1296             continue;
1297           pixels=ReadBlobStream(image,extent,GetQuantumPixels(quantum_info),
1298             &count);
1299           if ((size_t) count != extent)
1300             status=MagickFalse;
1301           if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1302               (image->previous == (Image *) NULL))
1303             {
1304               MagickBooleanType
1305                 proceed;
1306
1307               proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1308                 row,image->rows);
1309               if (proceed == MagickFalse)
1310                 status=MagickFalse;
1311             }
1312           offset=row++;
1313           q=QueueAuthenticPixels(image,0,(ssize_t) (image->rows-offset-1),
1314             image->columns,1,exception);
1315           if (q == (Quantum *) NULL)
1316             {
1317               status=MagickFalse;
1318               continue;
1319             }
1320           length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1321             quantum_type,pixels,exception);
1322           if (length != extent)
1323             status=MagickFalse;
1324           sync=SyncAuthenticPixels(image,exception);
1325           if (sync == MagickFalse)
1326             status=MagickFalse;
1327         }
1328         quantum_info=DestroyQuantumInfo(quantum_info);
1329         if (status == MagickFalse)
1330           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1331         SetQuantumImageType(image,quantum_type);
1332         break;
1333       }
1334       default:
1335         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1336     }
1337     if (EOFBlob(image) != MagickFalse)
1338       {
1339         (void) ThrowMagickException(exception,GetMagickModule(),
1340           CorruptImageError,"UnexpectedEndOfFile","`%s'",image->filename);
1341         break;
1342       }
1343     /*
1344       Proceed to next image.
1345     */
1346     if (image_info->number_scenes != 0)
1347       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1348         break;
1349     if ((format == '1') || (format == '2') || (format == '3'))
1350       do
1351       {
1352         /*
1353           Skip to end of line.
1354         */
1355         count=ReadBlob(image,1,(unsigned char *) &format);
1356         if (count != 1)
1357           break;
1358         if (format == 'P')
1359           break;
1360       } while (format != '\n');
1361     count=ReadBlob(image,1,(unsigned char *) &format);
1362     if ((count == 1) && (format == 'P'))
1363       {
1364         /*
1365           Allocate next image structure.
1366         */
1367         AcquireNextImage(image_info,image,exception);
1368         if (GetNextImageInList(image) == (Image *) NULL)
1369           {
1370             image=DestroyImageList(image);
1371             return((Image *) NULL);
1372           }
1373         image=SyncNextImageInList(image);
1374         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1375           GetBlobSize(image));
1376         if (status == MagickFalse)
1377           break;
1378       }
1379   } while ((count == 1) && (format == 'P'));
1380   (void) CloseBlob(image);
1381   return(GetFirstImageInList(image));
1382 }
1383 \f
1384 /*
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386 %                                                                             %
1387 %                                                                             %
1388 %                                                                             %
1389 %   R e g i s t e r P N M I m a g e                                           %
1390 %                                                                             %
1391 %                                                                             %
1392 %                                                                             %
1393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1394 %
1395 %  RegisterPNMImage() adds properties for the PNM image format to
1396 %  the list of supported formats.  The properties include the image format
1397 %  tag, a method to read and/or write the format, whether the format
1398 %  supports the saving of more than one frame to the same file or blob,
1399 %  whether the format supports native in-memory I/O, and a brief
1400 %  description of the format.
1401 %
1402 %  The format of the RegisterPNMImage method is:
1403 %
1404 %      size_t RegisterPNMImage(void)
1405 %
1406 */
1407 ModuleExport size_t RegisterPNMImage(void)
1408 {
1409   MagickInfo
1410     *entry;
1411
1412   entry=AcquireMagickInfo("PNM","PAM","Common 2-dimensional bitmap format");
1413   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1414   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1415   entry->mime_type=ConstantString("image/x-portable-pixmap");
1416   (void) RegisterMagickInfo(entry);
1417   entry=AcquireMagickInfo("PNM","PBM",
1418     "Portable bitmap format (black and white)");
1419   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1420   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1421   entry->mime_type=ConstantString("image/x-portable-bitmap");
1422   (void) RegisterMagickInfo(entry);
1423   entry=AcquireMagickInfo("PNM","PFM","Portable float format");
1424   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1425   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1426   entry->flags|=CoderEndianSupportFlag;
1427   (void) RegisterMagickInfo(entry);
1428   entry=AcquireMagickInfo("PNM","PGM","Portable graymap format (gray scale)");
1429   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1430   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1431   entry->mime_type=ConstantString("image/x-portable-greymap");
1432   (void) RegisterMagickInfo(entry);
1433   entry=AcquireMagickInfo("PNM","PNM","Portable anymap");
1434   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1435   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1436   entry->magick=(IsImageFormatHandler *) IsPNM;
1437   entry->mime_type=ConstantString("image/x-portable-pixmap");
1438   (void) RegisterMagickInfo(entry);
1439   entry=AcquireMagickInfo("PNM","PPM","Portable pixmap format (color)");
1440   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1441   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1442   entry->mime_type=ConstantString("image/x-portable-pixmap");
1443   (void) RegisterMagickInfo(entry);
1444   return(MagickImageCoderSignature);
1445 }
1446 \f
1447 /*
1448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449 %                                                                             %
1450 %                                                                             %
1451 %                                                                             %
1452 %   U n r e g i s t e r P N M I m a g e                                       %
1453 %                                                                             %
1454 %                                                                             %
1455 %                                                                             %
1456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457 %
1458 %  UnregisterPNMImage() removes format registrations made by the
1459 %  PNM module from the list of supported formats.
1460 %
1461 %  The format of the UnregisterPNMImage method is:
1462 %
1463 %      UnregisterPNMImage(void)
1464 %
1465 */
1466 ModuleExport void UnregisterPNMImage(void)
1467 {
1468   (void) UnregisterMagickInfo("PAM");
1469   (void) UnregisterMagickInfo("PBM");
1470   (void) UnregisterMagickInfo("PGM");
1471   (void) UnregisterMagickInfo("PNM");
1472   (void) UnregisterMagickInfo("PPM");
1473 }
1474 \f
1475 /*
1476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477 %                                                                             %
1478 %                                                                             %
1479 %                                                                             %
1480 %   W r i t e P N M I m a g e                                                 %
1481 %                                                                             %
1482 %                                                                             %
1483 %                                                                             %
1484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1485 %
1486 %  WritePNMImage() writes an image to a file in the PNM rasterfile format.
1487 %
1488 %  The format of the WritePNMImage method is:
1489 %
1490 %      MagickBooleanType WritePNMImage(const ImageInfo *image_info,
1491 %        Image *image,ExceptionInfo *exception)
1492 %
1493 %  A description of each parameter follows.
1494 %
1495 %    o image_info: the image info.
1496 %
1497 %    o image:  The image.
1498 %
1499 %    o exception: return any errors or warnings in this structure.
1500 %
1501 */
1502 static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image,
1503   ExceptionInfo *exception)
1504 {
1505   char
1506     buffer[MaxTextExtent],
1507     format,
1508     magick[MaxTextExtent];
1509
1510   const char
1511     *value;
1512
1513   MagickBooleanType
1514     status;
1515
1516   MagickOffsetType
1517     scene;
1518
1519   Quantum
1520     index;
1521
1522   QuantumAny
1523     pixel;
1524
1525   QuantumInfo
1526     *quantum_info;
1527
1528   QuantumType
1529     quantum_type;
1530
1531   register unsigned char
1532     *pixels,
1533     *q;
1534
1535   size_t
1536     extent,
1537     packet_size;
1538
1539   ssize_t
1540     count,
1541     y;
1542
1543   /*
1544     Open output image file.
1545   */
1546   assert(image_info != (const ImageInfo *) NULL);
1547   assert(image_info->signature == MagickSignature);
1548   assert(image != (Image *) NULL);
1549   assert(image->signature == MagickSignature);
1550   if (image->debug != MagickFalse)
1551     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1552   assert(exception != (ExceptionInfo *) NULL);
1553   assert(exception->signature == MagickSignature);
1554   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1555   if (status == MagickFalse)
1556     return(status);
1557   scene=0;
1558   do
1559   {
1560     QuantumAny
1561       max_value;
1562
1563     /*
1564       Write PNM file header.
1565     */
1566     packet_size=3;
1567     quantum_type=RGBQuantum;
1568     (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
1569     max_value=GetQuantumRange(image->depth);
1570     switch (magick[1])
1571     {
1572       case 'A':
1573       case 'a':
1574       {
1575         format='7';
1576         break;
1577       }
1578       case 'B':
1579       case 'b':
1580       {
1581         format='4';
1582         if (image_info->compression == NoCompression)
1583           format='1';
1584         break;
1585       }
1586       case 'F':
1587       case 'f':
1588       {
1589         format='F';
1590         if (SetImageGray(image,exception) != MagickFalse)
1591           format='f';
1592         break;
1593       }
1594       case 'G':
1595       case 'g':
1596       {
1597         format='5';
1598         if (image_info->compression == NoCompression)
1599           format='2';
1600         break;
1601       }
1602       case 'N':
1603       case 'n':
1604       {
1605         if ((image_info->type != TrueColorType) &&
1606             (SetImageGray(image,exception) != MagickFalse))
1607           {
1608             format='5';
1609             if (image_info->compression == NoCompression)
1610               format='2';
1611             if (SetImageMonochrome(image,exception) != MagickFalse)
1612               {
1613                 format='4';
1614                 if (image_info->compression == NoCompression)
1615                   format='1';
1616               }
1617             break;
1618           }
1619       }
1620       default:
1621       {
1622         format='6';
1623         if (image_info->compression == NoCompression)
1624           format='3';
1625         break;
1626       }
1627     }
1628     (void) FormatLocaleString(buffer,MaxTextExtent,"P%c\n",format);
1629     (void) WriteBlobString(image,buffer);
1630     value=GetImageProperty(image,"comment",exception);
1631     if (value != (const char *) NULL)
1632       {
1633         register const char
1634           *p;
1635
1636         /*
1637           Write comments to file.
1638         */
1639         (void) WriteBlobByte(image,'#');
1640         for (p=value; *p != '\0'; p++)
1641         {
1642           (void) WriteBlobByte(image,(unsigned char) *p);
1643           if ((*p == '\n') || (*p == '\r'))
1644             (void) WriteBlobByte(image,'#');
1645         }
1646         (void) WriteBlobByte(image,'\n');
1647       }
1648     if (format != '7')
1649       {
1650         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n",
1651           (double) image->columns,(double) image->rows);
1652         (void) WriteBlobString(image,buffer);
1653       }
1654     else
1655       {
1656         char
1657           type[MaxTextExtent];
1658
1659         /*
1660           PAM header.
1661         */
1662         (void) FormatLocaleString(buffer,MaxTextExtent,
1663           "WIDTH %.20g\nHEIGHT %.20g\n",(double) image->columns,(double)
1664           image->rows);
1665         (void) WriteBlobString(image,buffer);
1666         quantum_type=GetQuantumType(image,exception);
1667         switch (quantum_type)
1668         {
1669           case CMYKQuantum:
1670           case CMYKAQuantum:
1671           {
1672             packet_size=4;
1673             (void) CopyMagickString(type,"CMYK",MaxTextExtent);
1674             break;
1675           }
1676           case GrayQuantum:
1677           case GrayAlphaQuantum:
1678           {
1679             packet_size=1;
1680             (void) CopyMagickString(type,"GRAYSCALE",MaxTextExtent);
1681             break;
1682           }
1683           default:
1684           {
1685             quantum_type=RGBQuantum;
1686             if (image->alpha_trait != UndefinedPixelTrait)
1687               quantum_type=RGBAQuantum;
1688             packet_size=3;
1689             (void) CopyMagickString(type,"RGB",MaxTextExtent);
1690             break;
1691           }
1692         }
1693         if (image->alpha_trait != UndefinedPixelTrait)
1694           {
1695             packet_size++;
1696             (void) ConcatenateMagickString(type,"_ALPHA",MaxTextExtent);
1697           }
1698         if (image->depth > 32)
1699           image->depth=32;
1700         (void) FormatLocaleString(buffer,MaxTextExtent,
1701           "DEPTH %.20g\nMAXVAL %.20g\n",(double) packet_size,(double)
1702           ((MagickOffsetType) GetQuantumRange(image->depth)));
1703         (void) WriteBlobString(image,buffer);
1704         (void) FormatLocaleString(buffer,MaxTextExtent,"TUPLTYPE %s\nENDHDR\n",
1705           type);
1706         (void) WriteBlobString(image,buffer);
1707       }
1708     /*
1709       Convert runextent encoded to PNM raster pixels.
1710     */
1711     switch (format)
1712     {
1713       case '1':
1714       {
1715         unsigned char
1716           pixels[2048];
1717
1718         /*
1719           Convert image to a PBM image.
1720         */
1721         (void) SetImageType(image,BilevelType,exception);
1722         q=pixels;
1723         for (y=0; y < (ssize_t) image->rows; y++)
1724         {
1725           register const Quantum
1726             *restrict p;
1727
1728           register ssize_t
1729             x;
1730
1731           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1732           if (p == (const Quantum *) NULL)
1733             break;
1734           for (x=0; x < (ssize_t) image->columns; x++)
1735           {
1736             *q++=(unsigned char) (GetPixelLuma(image,p) >= (QuantumRange/2.0) ?
1737               '0' : '1');
1738             *q++=' ';
1739             if ((q-pixels+2) >= 80)
1740               {
1741                 *q++='\n';
1742                 (void) WriteBlob(image,q-pixels,pixels);
1743                 q=pixels;
1744               }
1745             p+=GetPixelChannels(image);
1746           }
1747           if (image->previous == (Image *) NULL)
1748             {
1749               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1750                 image->rows);
1751               if (status == MagickFalse)
1752                 break;
1753             }
1754         }
1755         if (q != pixels)
1756           {
1757             *q++='\n';
1758             (void) WriteBlob(image,q-pixels,pixels);
1759           }
1760         break;
1761       }
1762       case '2':
1763       {
1764         unsigned char
1765           pixels[2048];
1766
1767         /*
1768           Convert image to a PGM image.
1769         */
1770         if (image->depth <= 8)
1771           (void) WriteBlobString(image,"255\n");
1772         else
1773           if (image->depth <= 16)
1774             (void) WriteBlobString(image,"65535\n");
1775           else
1776             (void) WriteBlobString(image,"4294967295\n");
1777         q=pixels;
1778         for (y=0; y < (ssize_t) image->rows; y++)
1779         {
1780           register const Quantum
1781             *restrict p;
1782
1783           register ssize_t
1784             x;
1785
1786           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1787           if (p == (const Quantum *) NULL)
1788             break;
1789           for (x=0; x < (ssize_t) image->columns; x++)
1790           {
1791             index=ClampToQuantum(GetPixelLuma(image,p));
1792             if (image->depth <= 8)
1793               count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,"%u ",
1794                 ScaleQuantumToChar(index));
1795             else
1796               if (image->depth <= 16)
1797                 count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,"%u ",
1798                   ScaleQuantumToShort(index));
1799               else
1800                 count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,"%u ",
1801                   ScaleQuantumToLong(index));
1802             extent=(size_t) count;
1803             (void) strncpy((char *) q,buffer,extent);
1804             q+=extent;
1805             if ((q-pixels+extent) >= 80)
1806               {
1807                 *q++='\n';
1808                 (void) WriteBlob(image,q-pixels,pixels);
1809                 q=pixels;
1810               }
1811             p+=GetPixelChannels(image);
1812           }
1813           if (image->previous == (Image *) NULL)
1814             {
1815               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1816                 image->rows);
1817               if (status == MagickFalse)
1818                 break;
1819             }
1820         }
1821         if (q != pixels)
1822           {
1823             *q++='\n';
1824             (void) WriteBlob(image,q-pixels,pixels);
1825           }
1826         break;
1827       }
1828       case '3':
1829       {
1830         unsigned char
1831           pixels[2048];
1832
1833         /*
1834           Convert image to a PNM image.
1835         */
1836         (void) TransformImageColorspace(image,sRGBColorspace,exception);
1837         if (image->depth <= 8)
1838           (void) WriteBlobString(image,"255\n");
1839         else
1840           if (image->depth <= 16)
1841             (void) WriteBlobString(image,"65535\n");
1842           else
1843             (void) WriteBlobString(image,"4294967295\n");
1844         q=pixels;
1845         for (y=0; y < (ssize_t) image->rows; y++)
1846         {
1847           register const Quantum
1848             *restrict p;
1849
1850           register ssize_t
1851             x;
1852
1853           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1854           if (p == (const Quantum *) NULL)
1855             break;
1856           for (x=0; x < (ssize_t) image->columns; x++)
1857           {
1858             if (image->depth <= 8)
1859               count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,
1860                 "%u %u %u ",ScaleQuantumToChar(GetPixelRed(image,p)),
1861                 ScaleQuantumToChar(GetPixelGreen(image,p)),
1862                 ScaleQuantumToChar(GetPixelBlue(image,p)));
1863             else
1864               if (image->depth <= 16)
1865                 count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,
1866                   "%u %u %u ",ScaleQuantumToShort(GetPixelRed(image,p)),
1867                   ScaleQuantumToShort(GetPixelGreen(image,p)),
1868                   ScaleQuantumToShort(GetPixelBlue(image,p)));
1869               else
1870                 count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,
1871                   "%u %u %u ",ScaleQuantumToLong(GetPixelRed(image,p)),
1872                   ScaleQuantumToLong(GetPixelGreen(image,p)),
1873                   ScaleQuantumToLong(GetPixelBlue(image,p)));
1874             extent=(size_t) count;
1875             (void) strncpy((char *) q,buffer,extent);
1876             q+=extent;
1877             if ((q-pixels+extent) >= 80)
1878               {
1879                 *q++='\n';
1880                 (void) WriteBlob(image,q-pixels,pixels);
1881                 q=pixels;
1882               }
1883             p+=GetPixelChannels(image);
1884           }
1885           if (image->previous == (Image *) NULL)
1886             {
1887               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1888                 image->rows);
1889               if (status == MagickFalse)
1890                 break;
1891             }
1892         }
1893         if (q != pixels)
1894           {
1895             *q++='\n';
1896             (void) WriteBlob(image,q-pixels,pixels);
1897           }
1898         break;
1899       }
1900       case '4':
1901       {
1902         /*
1903           Convert image to a PBM image.
1904         */
1905         (void) SetImageType(image,BilevelType,exception);
1906         image->depth=1;
1907         quantum_info=AcquireQuantumInfo(image_info,image);
1908         if (quantum_info == (QuantumInfo *) NULL)
1909           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1910         (void) SetQuantumEndian(image,quantum_info,MSBEndian);
1911         quantum_info->min_is_white=MagickTrue;
1912         pixels=GetQuantumPixels(quantum_info);
1913         for (y=0; y < (ssize_t) image->rows; y++)
1914         {
1915           register const Quantum
1916             *restrict p;
1917
1918           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1919           if (p == (const Quantum *) NULL)
1920             break;
1921           extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1922             GrayQuantum,pixels,exception);
1923           count=WriteBlob(image,extent,pixels);
1924           if (count != (ssize_t) extent)
1925             break;
1926           if (image->previous == (Image *) NULL)
1927             {
1928               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1929                 image->rows);
1930               if (status == MagickFalse)
1931                 break;
1932             }
1933         }
1934         quantum_info=DestroyQuantumInfo(quantum_info);
1935         break;
1936       }
1937       case '5':
1938       {
1939         /*
1940           Convert image to a PGM image.
1941         */
1942         if (image->depth > 32)
1943           image->depth=32;
1944         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
1945           ((MagickOffsetType) GetQuantumRange(image->depth)));
1946         (void) WriteBlobString(image,buffer);
1947         quantum_info=AcquireQuantumInfo(image_info,image);
1948         if (quantum_info == (QuantumInfo *) NULL)
1949           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1950         (void) SetQuantumEndian(image,quantum_info,MSBEndian);
1951         quantum_info->min_is_white=MagickTrue;
1952         pixels=GetQuantumPixels(quantum_info);
1953         extent=GetQuantumExtent(image,quantum_info,GrayQuantum);
1954         for (y=0; y < (ssize_t) image->rows; y++)
1955         {
1956           register const Quantum
1957             *restrict p;
1958
1959           register ssize_t
1960             x;
1961
1962           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1963           if (p == (const Quantum *) NULL)
1964             break;
1965           q=pixels;
1966           switch (image->depth)
1967           {
1968             case 8:
1969             case 16:
1970             case 32:
1971             {
1972               extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1973                 GrayQuantum,pixels,exception);
1974               break;
1975             }
1976             default:
1977             {
1978               if (image->depth <= 8)
1979                 {
1980                   for (x=0; x < (ssize_t) image->columns; x++)
1981                   {
1982                     if (IsPixelGray(image,p) == MagickFalse)
1983                       pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
1984                         image,p)),max_value);
1985                     else
1986                       {
1987                         if (image->depth == 8)
1988                           pixel=ScaleQuantumToChar(GetPixelRed(image,p));
1989                         else
1990                           pixel=ScaleQuantumToAny(GetPixelRed(image,p),
1991                           max_value);
1992                       }
1993                     q=PopCharPixel((unsigned char) pixel,q);
1994                     p+=GetPixelChannels(image);
1995                   }
1996                   extent=(size_t) (q-pixels);
1997                   break;
1998                 }
1999               if (image->depth <= 16)
2000                 {
2001                   for (x=0; x < (ssize_t) image->columns; x++)
2002                   {
2003                     if (IsPixelGray(image,p) == MagickFalse)
2004                       pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,
2005                         p)),max_value);
2006                     else
2007                       {
2008                         if (image->depth == 16)
2009                           pixel=ScaleQuantumToShort(GetPixelRed(image,p));
2010                         else
2011                           pixel=ScaleQuantumToAny(GetPixelRed(image,p),
2012                             max_value);
2013                       }
2014                     q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2015                     p+=GetPixelChannels(image);
2016                   }
2017                   extent=(size_t) (q-pixels);
2018                   break;
2019                 }
2020               for (x=0; x < (ssize_t) image->columns; x++)
2021               {
2022                 if (IsPixelGray(image,p) == MagickFalse)
2023                   pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,p)),
2024                     max_value);
2025                 else
2026                   {
2027                     if (image->depth == 16)
2028                       pixel=ScaleQuantumToLong(GetPixelRed(image,p));
2029                     else
2030                       pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2031                   }
2032                 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2033                 p+=GetPixelChannels(image);
2034               }
2035               extent=(size_t) (q-pixels);
2036               break;
2037             }
2038           }
2039           count=WriteBlob(image,extent,pixels);
2040           if (count != (ssize_t) extent)
2041             break;
2042           if (image->previous == (Image *) NULL)
2043             {
2044               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2045                 image->rows);
2046               if (status == MagickFalse)
2047                 break;
2048             }
2049         }
2050         quantum_info=DestroyQuantumInfo(quantum_info);
2051         break;
2052       }
2053       case '6':
2054       {
2055         /*
2056           Convert image to a PNM image.
2057         */
2058         (void) TransformImageColorspace(image,sRGBColorspace,exception);
2059         if (image->depth > 32)
2060           image->depth=32;
2061         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
2062           ((MagickOffsetType) GetQuantumRange(image->depth)));
2063         (void) WriteBlobString(image,buffer);
2064         quantum_info=AcquireQuantumInfo(image_info,image);
2065         if (quantum_info == (QuantumInfo *) NULL)
2066           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2067         (void) SetQuantumEndian(image,quantum_info,MSBEndian);
2068         pixels=GetQuantumPixels(quantum_info);
2069         extent=GetQuantumExtent(image,quantum_info,quantum_type);
2070         for (y=0; y < (ssize_t) image->rows; y++)
2071         {
2072           register const Quantum
2073             *restrict p;
2074
2075           register ssize_t
2076             x;
2077
2078           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2079           if (p == (const Quantum *) NULL)
2080             break;
2081           q=pixels;
2082           switch (image->depth)
2083           {
2084             case 8:
2085             case 16:
2086             case 32:
2087             {
2088               extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2089                 quantum_type,pixels,exception);
2090               break;
2091             }
2092             default:
2093             {
2094               if (image->depth <= 8)
2095                 {
2096                   for (x=0; x < (ssize_t) image->columns; x++)
2097                   {
2098                     pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2099                     q=PopCharPixel((unsigned char) pixel,q);
2100                     pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2101                     q=PopCharPixel((unsigned char) pixel,q);
2102                     pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2103                     q=PopCharPixel((unsigned char) pixel,q);
2104                     p+=GetPixelChannels(image);
2105                   }
2106                   extent=(size_t) (q-pixels);
2107                   break;
2108                 }
2109               if (image->depth <= 16)
2110                 {
2111                   for (x=0; x < (ssize_t) image->columns; x++)
2112                   {
2113                     pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2114                     q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2115                     pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2116                     q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2117                     pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2118                     q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2119                     p+=GetPixelChannels(image);
2120                   }
2121                   extent=(size_t) (q-pixels);
2122                   break;
2123                 }
2124               for (x=0; x < (ssize_t) image->columns; x++)
2125               {
2126                 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2127                 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2128                 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2129                 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2130                 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2131                 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2132                 p+=GetPixelChannels(image);
2133               }
2134               extent=(size_t) (q-pixels);
2135               break;
2136             }
2137           }
2138           count=WriteBlob(image,extent,pixels);
2139           if (count != (ssize_t) extent)
2140             break;
2141           if (image->previous == (Image *) NULL)
2142             {
2143               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2144                 image->rows);
2145               if (status == MagickFalse)
2146                 break;
2147             }
2148         }
2149         quantum_info=DestroyQuantumInfo(quantum_info);
2150         break;
2151       }
2152       case '7':
2153       {
2154         /*
2155           Convert image to a PAM.
2156         */
2157         if (image->depth > 32)
2158           image->depth=32;
2159         quantum_info=AcquireQuantumInfo(image_info,image);
2160         if (quantum_info == (QuantumInfo *) NULL)
2161           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2162         (void) SetQuantumEndian(image,quantum_info,MSBEndian);
2163         pixels=GetQuantumPixels(quantum_info);
2164         for (y=0; y < (ssize_t) image->rows; y++)
2165         {
2166           register const Quantum
2167             *restrict p;
2168
2169           register ssize_t
2170             x;
2171
2172           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2173           if (p == (const Quantum *) NULL)
2174             break;
2175           q=pixels;
2176           switch (image->depth)
2177           {
2178             case 8:
2179             case 16:
2180             case 32:
2181             {
2182               extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2183                 quantum_type,pixels,exception);
2184               break;
2185             }
2186             default:
2187             {
2188               switch (quantum_type)
2189               {
2190                 case GrayQuantum:
2191                 case GrayAlphaQuantum:
2192                 {
2193                   if (image->depth <= 8)
2194                     {
2195                       for (x=0; x < (ssize_t) image->columns; x++)
2196                       {
2197                         pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
2198                           image,p)),max_value);
2199                         q=PopCharPixel((unsigned char) pixel,q);
2200                         if (image->alpha_trait != UndefinedPixelTrait)
2201                           {
2202                             pixel=(unsigned char) ScaleQuantumToAny(
2203                               GetPixelAlpha(image,p),max_value);
2204                             q=PopCharPixel((unsigned char) pixel,q);
2205                           }
2206                         p+=GetPixelChannels(image);
2207                       }
2208                       break;
2209                     }
2210                   if (image->depth <= 16)
2211                     {
2212                       for (x=0; x < (ssize_t) image->columns; x++)
2213                       {
2214                         pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
2215                           image,p)),max_value);
2216                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2217                         if (image->alpha_trait != UndefinedPixelTrait)
2218                           {
2219                             pixel=(unsigned char) ScaleQuantumToAny(
2220                               GetPixelAlpha(image,p),max_value);
2221                             q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2222                           }
2223                         p+=GetPixelChannels(image);
2224                       }
2225                       break;
2226                     }
2227                   for (x=0; x < (ssize_t) image->columns; x++)
2228                   {
2229                     pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,
2230                       p)),max_value);
2231                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2232                     if (image->alpha_trait != UndefinedPixelTrait)
2233                       {
2234                         pixel=(unsigned char) ScaleQuantumToAny(
2235                           GetPixelAlpha(image,p),max_value);
2236                         q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2237                       }
2238                     p+=GetPixelChannels(image);
2239                   }
2240                   break;
2241                 }
2242                 case CMYKQuantum:
2243                 case CMYKAQuantum:
2244                 {
2245                   if (image->depth <= 8)
2246                     {
2247                       for (x=0; x < (ssize_t) image->columns; x++)
2248                       {
2249                         pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2250                         q=PopCharPixel((unsigned char) pixel,q);
2251                         pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2252                           max_value);
2253                         q=PopCharPixel((unsigned char) pixel,q);
2254                         pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2255                           max_value);
2256                         q=PopCharPixel((unsigned char) pixel,q);
2257                         pixel=ScaleQuantumToAny(GetPixelBlack(image,p),
2258                           max_value);
2259                         q=PopCharPixel((unsigned char) pixel,q);
2260                         if (image->alpha_trait != UndefinedPixelTrait)
2261                           {
2262                             pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2263                               max_value);
2264                             q=PopCharPixel((unsigned char) pixel,q);
2265                           }
2266                         p+=GetPixelChannels(image);
2267                       }
2268                       break;
2269                     }
2270                   if (image->depth <= 16)
2271                     {
2272                       for (x=0; x < (ssize_t) image->columns; x++)
2273                       {
2274                         pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2275                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2276                         pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2277                           max_value);
2278                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2279                         pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2280                           max_value);
2281                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2282                         pixel=ScaleQuantumToAny(GetPixelBlack(image,p),
2283                           max_value);
2284                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2285                         if (image->alpha_trait != UndefinedPixelTrait)
2286                           {
2287                             pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2288                               max_value);
2289                             q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2290                           }
2291                         p+=GetPixelChannels(image);
2292                       }
2293                       break;
2294                     }
2295                   for (x=0; x < (ssize_t) image->columns; x++)
2296                   {
2297                     pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2298                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2299                     pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2300                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2301                     pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2302                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2303                     pixel=ScaleQuantumToAny(GetPixelBlack(image,p),max_value);
2304                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2305                     if (image->alpha_trait != UndefinedPixelTrait)
2306                       {
2307                         pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2308                           max_value);
2309                         q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2310                       }
2311                     p+=GetPixelChannels(image);
2312                   }
2313                   break;
2314                 }
2315                 default:
2316                 {
2317                   if (image->depth <= 8)
2318                     {
2319                       for (x=0; x < (ssize_t) image->columns; x++)
2320                       {
2321                         pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2322                         q=PopCharPixel((unsigned char) pixel,q);
2323                         pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2324                           max_value);
2325                         q=PopCharPixel((unsigned char) pixel,q);
2326                         pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2327                           max_value);
2328                         q=PopCharPixel((unsigned char) pixel,q);
2329                         if (image->alpha_trait != UndefinedPixelTrait)
2330                           {
2331                             pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2332                               max_value);
2333                             q=PopCharPixel((unsigned char) pixel,q);
2334                           }
2335                         p+=GetPixelChannels(image);
2336                       }
2337                       break;
2338                     }
2339                   if (image->depth <= 16)
2340                     {
2341                       for (x=0; x < (ssize_t) image->columns; x++)
2342                       {
2343                         pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2344                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2345                         pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2346                           max_value);
2347                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2348                         pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2349                           max_value);
2350                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2351                         if (image->alpha_trait != UndefinedPixelTrait)
2352                           {
2353                             pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2354                               max_value);
2355                             q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2356                           }
2357                         p+=GetPixelChannels(image);
2358                       }
2359                       break;
2360                     }
2361                   for (x=0; x < (ssize_t) image->columns; x++)
2362                   {
2363                     pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2364                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2365                     pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2366                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2367                     pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2368                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2369                     if (image->alpha_trait != UndefinedPixelTrait)
2370                       {
2371                         pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2372                           max_value);
2373                         q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2374                       }
2375                     p+=GetPixelChannels(image);
2376                   }
2377                   break;
2378                 }
2379               }
2380               extent=(size_t) (q-pixels);
2381               break;
2382             }
2383           }
2384           count=WriteBlob(image,extent,pixels);
2385           if (count != (ssize_t) extent)
2386             break;
2387           if (image->previous == (Image *) NULL)
2388             {
2389               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2390                 image->rows);
2391               if (status == MagickFalse)
2392                 break;
2393             }
2394         }
2395         quantum_info=DestroyQuantumInfo(quantum_info);
2396         break;
2397       }
2398       case 'F':
2399       case 'f':
2400       {
2401         (void) WriteBlobString(image,image->endian == LSBEndian ? "-1.0\n" :
2402           "1.0\n");
2403         image->depth=32;
2404         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
2405         quantum_info=AcquireQuantumInfo(image_info,image);
2406         if (quantum_info == (QuantumInfo *) NULL)
2407           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2408         (void) SetQuantumEndian(image,quantum_info,MSBEndian);
2409         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2410         if (status == MagickFalse)
2411           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2412         pixels=GetQuantumPixels(quantum_info);
2413         for (y=(ssize_t) image->rows-1; y >= 0; y--)
2414         {
2415           register const Quantum
2416             *restrict p;
2417
2418           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2419           if (p == (const Quantum *) NULL)
2420             break;
2421           extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2422             quantum_type,pixels,exception);
2423           (void) WriteBlob(image,extent,pixels);
2424           if (image->previous == (Image *) NULL)
2425             {
2426               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2427                 image->rows);
2428               if (status == MagickFalse)
2429                 break;
2430             }
2431         }
2432         quantum_info=DestroyQuantumInfo(quantum_info);
2433         break;
2434       }
2435     }
2436     if (GetNextImageInList(image) == (Image *) NULL)
2437       break;
2438     image=SyncNextImageInList(image);
2439     status=SetImageProgress(image,SaveImagesTag,scene++,
2440       GetImageListLength(image));
2441     if (status == MagickFalse)
2442       break;
2443   } while (image_info->adjoin != MagickFalse);
2444   (void) CloseBlob(image);
2445   return(MagickTrue);
2446 }