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