]> granicus.if.org Git - imagemagick/blob - coders/pnm.c
(no commit message)
[imagemagick] / coders / pnm.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            PPPP   N   N  M   M                              %
7 %                            P   P  NN  N  MM MM                              %
8 %                            PPPP   N N N  M M M                              %
9 %                            P      N  NN  M   M                              %
10 %                            P      N   N  M   M                              %
11 %                                                                             %
12 %                                                                             %
13 %               Read/Write PBMPlus Portable Anymap Image Format               %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2014 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                             if (image->depth != 1)
1048                               SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1049                                 max_value),q);
1050                             else
1051                               SetPixelAlpha(image,QuantumRange-
1052                                 ScaleAnyToQuantum(pixel,max_value),q);
1053                           }
1054                         q+=GetPixelChannels(image);
1055                       }
1056                       break;
1057                     }
1058                   if (image->depth <= 16)
1059                     {
1060                       unsigned short
1061                         pixel;
1062
1063                       for (x=0; x < (ssize_t) image->columns; x++)
1064                       {
1065                         p=PushShortPixel(MSBEndian,p,&pixel);
1066                         SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),
1067                           q);
1068                         SetPixelAlpha(image,OpaqueAlpha,q);
1069                         if (image->alpha_trait == BlendPixelTrait)
1070                           {
1071                             p=PushShortPixel(MSBEndian,p,&pixel);
1072                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1073                               max_value),q);
1074                           }
1075                         q+=GetPixelChannels(image);
1076                       }
1077                       break;
1078                     }
1079                   for (x=0; x < (ssize_t) image->columns; x++)
1080                   {
1081                     p=PushLongPixel(MSBEndian,p,&pixel);
1082                     SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),q);
1083                     SetPixelAlpha(image,OpaqueAlpha,q);
1084                     if (image->alpha_trait == BlendPixelTrait)
1085                       {
1086                         p=PushLongPixel(MSBEndian,p,&pixel);
1087                         SetPixelAlpha(image,ScaleAnyToQuantum(pixel,max_value),q);
1088                       }
1089                     q+=GetPixelChannels(image);
1090                   }
1091                   break;
1092                 }
1093                 case CMYKQuantum:
1094                 case CMYKAQuantum:
1095                 {
1096                   unsigned int
1097                     pixel;
1098
1099                   if (image->depth <= 8)
1100                     {
1101                       unsigned char
1102                         pixel;
1103
1104                       for (x=0; x < (ssize_t) image->columns; x++)
1105                       {
1106                         p=PushCharPixel(p,&pixel);
1107                         SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1108                         p=PushCharPixel(p,&pixel);
1109                         SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
1110                         p=PushCharPixel(p,&pixel);
1111                         SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
1112                         p=PushCharPixel(p,&pixel);
1113                         SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),q);
1114                         SetPixelAlpha(image,OpaqueAlpha,q);
1115                         if (image->alpha_trait == BlendPixelTrait)
1116                           {
1117                             p=PushCharPixel(p,&pixel);
1118                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1119                               max_value),q);
1120                           }
1121                         q+=GetPixelChannels(image);
1122                       }
1123                       break;
1124                     }
1125                   if (image->depth <= 16)
1126                     {
1127                       unsigned short
1128                         pixel;
1129
1130                       for (x=0; x < (ssize_t) image->columns; x++)
1131                       {
1132                         p=PushShortPixel(MSBEndian,p,&pixel);
1133                         SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1134                         p=PushShortPixel(MSBEndian,p,&pixel);
1135                         SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
1136                         p=PushShortPixel(MSBEndian,p,&pixel);
1137                         SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
1138                         p=PushShortPixel(MSBEndian,p,&pixel);
1139                         SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),q);
1140                         SetPixelAlpha(image,OpaqueAlpha,q);
1141                         if (image->alpha_trait == BlendPixelTrait)
1142                           {
1143                             p=PushShortPixel(MSBEndian,p,&pixel);
1144                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1145                               max_value),q);
1146                           }
1147                         q+=GetPixelChannels(image);
1148                       }
1149                     }
1150                   for (x=0; x < (ssize_t) image->columns; x++)
1151                   {
1152                     p=PushLongPixel(MSBEndian,p,&pixel);
1153                     SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1154                     p=PushLongPixel(MSBEndian,p,&pixel);
1155                     SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
1156                     p=PushLongPixel(MSBEndian,p,&pixel);
1157                     SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
1158                     p=PushLongPixel(MSBEndian,p,&pixel);
1159                     SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),q);
1160                     SetPixelAlpha(image,OpaqueAlpha,q);
1161                     if (image->alpha_trait == BlendPixelTrait)
1162                       {
1163                         p=PushLongPixel(MSBEndian,p,&pixel);
1164                         SetPixelAlpha(image,ScaleAnyToQuantum(pixel,max_value),q);
1165                       }
1166                     q+=GetPixelChannels(image);
1167                   }
1168                   break;
1169                 }
1170                 default:
1171                 {
1172                   unsigned int
1173                     pixel;
1174
1175                   if (image->depth <= 8)
1176                     {
1177                       unsigned char
1178                         pixel;
1179
1180                       for (x=0; x < (ssize_t) image->columns; x++)
1181                       {
1182                         p=PushCharPixel(p,&pixel);
1183                         SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1184                         p=PushCharPixel(p,&pixel);
1185                         SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
1186                         p=PushCharPixel(p,&pixel);
1187                         SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
1188                         SetPixelAlpha(image,OpaqueAlpha,q);
1189                         if (image->alpha_trait == BlendPixelTrait)
1190                           {
1191                             p=PushCharPixel(p,&pixel);
1192                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,max_value),q);
1193                           }
1194                         q+=GetPixelChannels(image);
1195                       }
1196                       break;
1197                     }
1198                   if (image->depth <= 16)
1199                     {
1200                       unsigned short
1201                         pixel;
1202
1203                       for (x=0; x < (ssize_t) image->columns; x++)
1204                       {
1205                         p=PushShortPixel(MSBEndian,p,&pixel);
1206                         SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1207                         p=PushShortPixel(MSBEndian,p,&pixel);
1208                         SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
1209                         p=PushShortPixel(MSBEndian,p,&pixel);
1210                         SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
1211                         SetPixelAlpha(image,OpaqueAlpha,q);
1212                         if (image->alpha_trait == BlendPixelTrait)
1213                           {
1214                             p=PushShortPixel(MSBEndian,p,&pixel);
1215                             SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1216                               max_value),q);
1217                           }
1218                         q+=GetPixelChannels(image);
1219                       }
1220                       break;
1221                     }
1222                   for (x=0; x < (ssize_t) image->columns; x++)
1223                   {
1224                     p=PushLongPixel(MSBEndian,p,&pixel);
1225                     SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1226                     p=PushLongPixel(MSBEndian,p,&pixel);
1227                     SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
1228                     p=PushLongPixel(MSBEndian,p,&pixel);
1229                     SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
1230                     SetPixelAlpha(image,OpaqueAlpha,q);
1231                     if (image->alpha_trait == BlendPixelTrait)
1232                       {
1233                         p=PushLongPixel(MSBEndian,p,&pixel);
1234                         SetPixelAlpha(image,ScaleAnyToQuantum(pixel,max_value),q);
1235                       }
1236                     q+=GetPixelChannels(image);
1237                   }
1238                   break;
1239                 }
1240               }
1241             }
1242           }
1243           sync=SyncAuthenticPixels(image,exception);
1244           if (sync == MagickFalse)
1245             status=MagickFalse;
1246         }
1247         quantum_info=DestroyQuantumInfo(quantum_info);
1248         if (status == MagickFalse)
1249           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1250         SetQuantumImageType(image,quantum_type);
1251         break;
1252       }
1253       case 'F':
1254       case 'f':
1255       {
1256         /*
1257           Convert PFM raster image to pixel packets.
1258         */
1259         if (format == 'f')
1260           (void) SetImageColorspace(image,GRAYColorspace,exception);
1261         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
1262         image->endian=quantum_scale < 0.0 ? LSBEndian : MSBEndian;
1263         image->depth=32;
1264         quantum_info=AcquireQuantumInfo(image_info,image);
1265         if (quantum_info == (QuantumInfo *) NULL)
1266           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1267         status=SetQuantumDepth(image,quantum_info,32);
1268         if (status == MagickFalse)
1269           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1270         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1271         if (status == MagickFalse)
1272           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1273         SetQuantumScale(quantum_info,(double) QuantumRange*fabs(quantum_scale));
1274         extent=GetQuantumExtent(image,quantum_info,quantum_type);
1275         for (y=0; y < (ssize_t) image->rows; y++)
1276         {
1277           MagickBooleanType
1278             sync;
1279
1280           register Quantum
1281             *restrict q;
1282
1283           ssize_t
1284             count,
1285             offset;
1286
1287           size_t
1288             length;
1289
1290           unsigned char
1291             *pixels;
1292
1293           if (status == MagickFalse)
1294             continue;
1295           pixels=GetQuantumPixels(quantum_info);
1296           {
1297             count=ReadBlob(image,extent,pixels);
1298             if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1299                 (image->previous == (Image *) NULL))
1300               {
1301                 MagickBooleanType
1302                   proceed;
1303
1304                 proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1305                   row,image->rows);
1306                 if (proceed == MagickFalse)
1307                   status=MagickFalse;
1308               }
1309             offset=row++;
1310           }
1311           if ((size_t) count != extent)
1312             status=MagickFalse;
1313           q=QueueAuthenticPixels(image,0,(ssize_t) (image->rows-offset-1),
1314             image->columns,1,exception);
1315           if (q == (Quantum *) NULL)
1316             {
1317               status=MagickFalse;
1318               continue;
1319             }
1320           length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1321             quantum_type,pixels,exception);
1322           if (length != extent)
1323             status=MagickFalse;
1324           sync=SyncAuthenticPixels(image,exception);
1325           if (sync == MagickFalse)
1326             status=MagickFalse;
1327         }
1328         quantum_info=DestroyQuantumInfo(quantum_info);
1329         if (status == MagickFalse)
1330           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1331         SetQuantumImageType(image,quantum_type);
1332         break;
1333       }
1334       default:
1335         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1336     }
1337     if (EOFBlob(image) != MagickFalse)
1338       {
1339         (void) ThrowMagickException(exception,GetMagickModule(),
1340           CorruptImageError,"UnexpectedEndOfFile","`%s'",image->filename);
1341         break;
1342       }
1343     /*
1344       Proceed to next image.
1345     */
1346     if (image_info->number_scenes != 0)
1347       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1348         break;
1349     if ((format == '1') || (format == '2') || (format == '3'))
1350       do
1351       {
1352         /*
1353           Skip to end of line.
1354         */
1355         count=ReadBlob(image,1,(unsigned char *) &format);
1356         if (count == 0)
1357           break;
1358         if ((count != 0) && (format == 'P'))
1359           break;
1360       } while (format != '\n');
1361     count=ReadBlob(image,1,(unsigned char *) &format);
1362     if ((count == 1) && (format == 'P'))
1363       {
1364         /*
1365           Allocate next image structure.
1366         */
1367         AcquireNextImage(image_info,image,exception);
1368         if (GetNextImageInList(image) == (Image *) NULL)
1369           {
1370             image=DestroyImageList(image);
1371             return((Image *) NULL);
1372           }
1373         image=SyncNextImageInList(image);
1374         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1375           GetBlobSize(image));
1376         if (status == MagickFalse)
1377           break;
1378       }
1379   } while ((count == 1) && (format == 'P'));
1380   (void) CloseBlob(image);
1381   return(GetFirstImageInList(image));
1382 }
1383 \f
1384 /*
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386 %                                                                             %
1387 %                                                                             %
1388 %                                                                             %
1389 %   R e g i s t e r P N M I m a g e                                           %
1390 %                                                                             %
1391 %                                                                             %
1392 %                                                                             %
1393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1394 %
1395 %  RegisterPNMImage() adds properties for the PNM image format to
1396 %  the list of supported formats.  The properties include the image format
1397 %  tag, a method to read and/or write the format, whether the format
1398 %  supports the saving of more than one frame to the same file or blob,
1399 %  whether the format supports native in-memory I/O, and a brief
1400 %  description of the format.
1401 %
1402 %  The format of the RegisterPNMImage method is:
1403 %
1404 %      size_t RegisterPNMImage(void)
1405 %
1406 */
1407 ModuleExport size_t RegisterPNMImage(void)
1408 {
1409   MagickInfo
1410     *entry;
1411
1412   entry=SetMagickInfo("PAM");
1413   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1414   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1415   entry->description=ConstantString("Common 2-dimensional bitmap format");
1416   entry->mime_type=ConstantString("image/x-portable-pixmap");
1417   entry->module=ConstantString("PNM");
1418   (void) RegisterMagickInfo(entry);
1419   entry=SetMagickInfo("PBM");
1420   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1421   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1422   entry->description=ConstantString("Portable bitmap format (black and white)");
1423   entry->mime_type=ConstantString("image/x-portable-bitmap");
1424   entry->module=ConstantString("PNM");
1425   (void) RegisterMagickInfo(entry);
1426   entry=SetMagickInfo("PFM");
1427   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1428   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1429   entry->endian_support=MagickTrue;
1430   entry->description=ConstantString("Portable float format");
1431   entry->module=ConstantString("PFM");
1432   (void) RegisterMagickInfo(entry);
1433   entry=SetMagickInfo("PGM");
1434   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1435   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1436   entry->description=ConstantString("Portable graymap format (gray scale)");
1437   entry->mime_type=ConstantString("image/x-portable-greymap");
1438   entry->module=ConstantString("PNM");
1439   (void) RegisterMagickInfo(entry);
1440   entry=SetMagickInfo("PNM");
1441   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1442   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1443   entry->magick=(IsImageFormatHandler *) IsPNM;
1444   entry->description=ConstantString("Portable anymap");
1445   entry->mime_type=ConstantString("image/x-portable-pixmap");
1446   entry->module=ConstantString("PNM");
1447   (void) RegisterMagickInfo(entry);
1448   entry=SetMagickInfo("PPM");
1449   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1450   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1451   entry->description=ConstantString("Portable pixmap format (color)");
1452   entry->mime_type=ConstantString("image/x-portable-pixmap");
1453   entry->module=ConstantString("PNM");
1454   (void) RegisterMagickInfo(entry);
1455   return(MagickImageCoderSignature);
1456 }
1457 \f
1458 /*
1459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460 %                                                                             %
1461 %                                                                             %
1462 %                                                                             %
1463 %   U n r e g i s t e r P N M I m a g e                                       %
1464 %                                                                             %
1465 %                                                                             %
1466 %                                                                             %
1467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468 %
1469 %  UnregisterPNMImage() removes format registrations made by the
1470 %  PNM module from the list of supported formats.
1471 %
1472 %  The format of the UnregisterPNMImage method is:
1473 %
1474 %      UnregisterPNMImage(void)
1475 %
1476 */
1477 ModuleExport void UnregisterPNMImage(void)
1478 {
1479   (void) UnregisterMagickInfo("PAM");
1480   (void) UnregisterMagickInfo("PBM");
1481   (void) UnregisterMagickInfo("PGM");
1482   (void) UnregisterMagickInfo("PNM");
1483   (void) UnregisterMagickInfo("PPM");
1484 }
1485 \f
1486 /*
1487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1488 %                                                                             %
1489 %                                                                             %
1490 %                                                                             %
1491 %   W r i t e P N M I m a g e                                                 %
1492 %                                                                             %
1493 %                                                                             %
1494 %                                                                             %
1495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1496 %
1497 %  WritePNMImage() writes an image to a file in the PNM rasterfile format.
1498 %
1499 %  The format of the WritePNMImage method is:
1500 %
1501 %      MagickBooleanType WritePNMImage(const ImageInfo *image_info,
1502 %        Image *image,ExceptionInfo *exception)
1503 %
1504 %  A description of each parameter follows.
1505 %
1506 %    o image_info: the image info.
1507 %
1508 %    o image:  The image.
1509 %
1510 %    o exception: return any errors or warnings in this structure.
1511 %
1512 */
1513 static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image,
1514   ExceptionInfo *exception)
1515 {
1516   char
1517     buffer[MaxTextExtent],
1518     format,
1519     magick[MaxTextExtent];
1520
1521   const char
1522     *value;
1523
1524   MagickBooleanType
1525     status;
1526
1527   MagickOffsetType
1528     scene;
1529
1530   Quantum
1531     index;
1532
1533   QuantumAny
1534     pixel;
1535
1536   QuantumInfo
1537     *quantum_info;
1538
1539   QuantumType
1540     quantum_type;
1541
1542   register unsigned char
1543     *pixels,
1544     *q;
1545
1546   size_t
1547     extent,
1548     packet_size;
1549
1550   ssize_t
1551     count,
1552     y;
1553
1554   /*
1555     Open output image file.
1556   */
1557   assert(image_info != (const ImageInfo *) NULL);
1558   assert(image_info->signature == MagickSignature);
1559   assert(image != (Image *) NULL);
1560   assert(image->signature == MagickSignature);
1561   if (image->debug != MagickFalse)
1562     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1563   assert(exception != (ExceptionInfo *) NULL);
1564   assert(exception->signature == MagickSignature);
1565   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1566   if (status == MagickFalse)
1567     return(status);
1568   scene=0;
1569   do
1570   {
1571     QuantumAny
1572       max_value;
1573
1574     /*
1575       Write PNM file header.
1576     */
1577     packet_size=3;
1578     quantum_type=RGBQuantum;
1579     (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
1580     max_value=GetQuantumRange(image->depth);
1581     switch (magick[1])
1582     {
1583       case 'A':
1584       case 'a':
1585       {
1586         format='7';
1587         break;
1588       }
1589       case 'B':
1590       case 'b':
1591       {
1592         format='4';
1593         if (image_info->compression == NoCompression)
1594           format='1';
1595         break;
1596       }
1597       case 'F':
1598       case 'f':
1599       {
1600         format='F';
1601         if (IsImageGray(image,exception) != MagickFalse)
1602           format='f';
1603         break;
1604       }
1605       case 'G':
1606       case 'g':
1607       {
1608         format='5';
1609         if (image_info->compression == NoCompression)
1610           format='2';
1611         break;
1612       }
1613       case 'N':
1614       case 'n':
1615       {
1616         if ((image_info->type != TrueColorType) &&
1617             (IsImageGray(image,exception) != MagickFalse))
1618           {
1619             format='5';
1620             if (image_info->compression == NoCompression)
1621               format='2';
1622             if (IsImageMonochrome(image,exception) != MagickFalse)
1623               {
1624                 format='4';
1625                 if (image_info->compression == NoCompression)
1626                   format='1';
1627               }
1628             break;
1629           }
1630       }
1631       default:
1632       {
1633         format='6';
1634         if (image_info->compression == NoCompression)
1635           format='3';
1636         break;
1637       }
1638     }
1639     (void) FormatLocaleString(buffer,MaxTextExtent,"P%c\n",format);
1640     (void) WriteBlobString(image,buffer);
1641     value=GetImageProperty(image,"comment",exception);
1642     if (value != (const char *) NULL)
1643       {
1644         register const char
1645           *p;
1646
1647         /*
1648           Write comments to file.
1649         */
1650         (void) WriteBlobByte(image,'#');
1651         for (p=value; *p != '\0'; p++)
1652         {
1653           (void) WriteBlobByte(image,(unsigned char) *p);
1654           if ((*p == '\n') || (*p == '\r'))
1655             (void) WriteBlobByte(image,'#');
1656         }
1657         (void) WriteBlobByte(image,'\n');
1658       }
1659     if (format != '7')
1660       {
1661         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n",
1662           (double) image->columns,(double) image->rows);
1663         (void) WriteBlobString(image,buffer);
1664       }
1665     else
1666       {
1667         char
1668           type[MaxTextExtent];
1669
1670         /*
1671           PAM header.
1672         */
1673         (void) FormatLocaleString(buffer,MaxTextExtent,
1674           "WIDTH %.20g\nHEIGHT %.20g\n",(double) image->columns,(double)
1675           image->rows);
1676         (void) WriteBlobString(image,buffer);
1677         quantum_type=GetQuantumType(image,exception);
1678         switch (quantum_type)
1679         {
1680           case CMYKQuantum:
1681           case CMYKAQuantum:
1682           {
1683             packet_size=4;
1684             (void) CopyMagickString(type,"CMYK",MaxTextExtent);
1685             break;
1686           }
1687           case GrayQuantum:
1688           case GrayAlphaQuantum:
1689           {
1690             packet_size=1;
1691             (void) CopyMagickString(type,"GRAYSCALE",MaxTextExtent);
1692             break;
1693           }
1694           default:
1695           {
1696             quantum_type=RGBQuantum;
1697             if (image->alpha_trait == BlendPixelTrait)
1698               quantum_type=RGBAQuantum;
1699             packet_size=3;
1700             (void) CopyMagickString(type,"RGB",MaxTextExtent);
1701             break;
1702           }
1703         }
1704         if (image->alpha_trait == BlendPixelTrait)
1705           {
1706             packet_size++;
1707             (void) ConcatenateMagickString(type,"_ALPHA",MaxTextExtent);
1708           }
1709         if (image->depth > 32)
1710           image->depth=32;
1711         (void) FormatLocaleString(buffer,MaxTextExtent,
1712           "DEPTH %.20g\nMAXVAL %.20g\n",(double) packet_size,(double)
1713           ((MagickOffsetType) GetQuantumRange(image->depth)));
1714         (void) WriteBlobString(image,buffer);
1715         (void) FormatLocaleString(buffer,MaxTextExtent,"TUPLTYPE %s\nENDHDR\n",
1716           type);
1717         (void) WriteBlobString(image,buffer);
1718       }
1719     /*
1720       Convert runextent encoded to PNM raster pixels.
1721     */
1722     switch (format)
1723     {
1724       case '1':
1725       {
1726         unsigned char
1727           pixels[2048];
1728
1729         /*
1730           Convert image to a PBM image.
1731         */
1732         (void) SetImageType(image,BilevelType,exception);
1733         q=pixels;
1734         for (y=0; y < (ssize_t) image->rows; y++)
1735         {
1736           register const Quantum
1737             *restrict p;
1738
1739           register ssize_t
1740             x;
1741
1742           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1743           if (p == (const Quantum *) NULL)
1744             break;
1745           for (x=0; x < (ssize_t) image->columns; x++)
1746           {
1747             *q++=(unsigned char) (GetPixelLuma(image,p) >= (QuantumRange/2.0) ?
1748               '0' : '1');
1749             *q++=' ';
1750             if ((q-pixels+2) >= 80)
1751               {
1752                 *q++='\n';
1753                 (void) WriteBlob(image,q-pixels,pixels);
1754                 q=pixels;
1755               }
1756             p+=GetPixelChannels(image);
1757           }
1758           if (image->previous == (Image *) NULL)
1759             {
1760               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1761                 image->rows);
1762               if (status == MagickFalse)
1763                 break;
1764             }
1765         }
1766         if (q != pixels)
1767           {
1768             *q++='\n';
1769             (void) WriteBlob(image,q-pixels,pixels);
1770           }
1771         break;
1772       }
1773       case '2':
1774       {
1775         unsigned char
1776           pixels[2048];
1777
1778         /*
1779           Convert image to a PGM image.
1780         */
1781         if (image->depth <= 8)
1782           (void) WriteBlobString(image,"255\n");
1783         else
1784           if (image->depth <= 16)
1785             (void) WriteBlobString(image,"65535\n");
1786           else
1787             (void) WriteBlobString(image,"4294967295\n");
1788         q=pixels;
1789         for (y=0; y < (ssize_t) image->rows; y++)
1790         {
1791           register const Quantum
1792             *restrict p;
1793
1794           register ssize_t
1795             x;
1796
1797           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1798           if (p == (const Quantum *) NULL)
1799             break;
1800           for (x=0; x < (ssize_t) image->columns; x++)
1801           {
1802             index=ClampToQuantum(GetPixelLuma(image,p));
1803             if (image->depth <= 8)
1804               count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,"%u ",
1805                 ScaleQuantumToChar(index));
1806             else
1807               if (image->depth <= 16)
1808                 count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,"%u ",
1809                   ScaleQuantumToShort(index));
1810               else
1811                 count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,"%u ",
1812                   ScaleQuantumToLong(index));
1813             extent=(size_t) count;
1814             (void) strncpy((char *) q,buffer,extent);
1815             q+=extent;
1816             if ((q-pixels+extent) >= 80)
1817               {
1818                 *q++='\n';
1819                 (void) WriteBlob(image,q-pixels,pixels);
1820                 q=pixels;
1821               }
1822             p+=GetPixelChannels(image);
1823           }
1824           if (image->previous == (Image *) NULL)
1825             {
1826               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1827                 image->rows);
1828               if (status == MagickFalse)
1829                 break;
1830             }
1831         }
1832         if (q != pixels)
1833           {
1834             *q++='\n';
1835             (void) WriteBlob(image,q-pixels,pixels);
1836           }
1837         break;
1838       }
1839       case '3':
1840       {
1841         unsigned char
1842           pixels[2048];
1843
1844         /*
1845           Convert image to a PNM image.
1846         */
1847         (void) TransformImageColorspace(image,sRGBColorspace,exception);
1848         if (image->depth <= 8)
1849           (void) WriteBlobString(image,"255\n");
1850         else
1851           if (image->depth <= 16)
1852             (void) WriteBlobString(image,"65535\n");
1853           else
1854             (void) WriteBlobString(image,"4294967295\n");
1855         q=pixels;
1856         for (y=0; y < (ssize_t) image->rows; y++)
1857         {
1858           register const Quantum
1859             *restrict p;
1860
1861           register ssize_t
1862             x;
1863
1864           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1865           if (p == (const Quantum *) NULL)
1866             break;
1867           for (x=0; x < (ssize_t) image->columns; x++)
1868           {
1869             if (image->depth <= 8)
1870               count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,
1871                 "%u %u %u ",ScaleQuantumToChar(GetPixelRed(image,p)),
1872                 ScaleQuantumToChar(GetPixelGreen(image,p)),
1873                 ScaleQuantumToChar(GetPixelBlue(image,p)));
1874             else
1875               if (image->depth <= 16)
1876                 count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,
1877                   "%u %u %u ",ScaleQuantumToShort(GetPixelRed(image,p)),
1878                   ScaleQuantumToShort(GetPixelGreen(image,p)),
1879                   ScaleQuantumToShort(GetPixelBlue(image,p)));
1880               else
1881                 count=(ssize_t) FormatLocaleString(buffer,MaxTextExtent,
1882                   "%u %u %u ",ScaleQuantumToLong(GetPixelRed(image,p)),
1883                   ScaleQuantumToLong(GetPixelGreen(image,p)),
1884                   ScaleQuantumToLong(GetPixelBlue(image,p)));
1885             extent=(size_t) count;
1886             (void) strncpy((char *) q,buffer,extent);
1887             q+=extent;
1888             if ((q-pixels+extent) >= 80)
1889               {
1890                 *q++='\n';
1891                 (void) WriteBlob(image,q-pixels,pixels);
1892                 q=pixels;
1893               }
1894             p+=GetPixelChannels(image);
1895           }
1896           if (image->previous == (Image *) NULL)
1897             {
1898               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1899                 image->rows);
1900               if (status == MagickFalse)
1901                 break;
1902             }
1903         }
1904         if (q != pixels)
1905           {
1906             *q++='\n';
1907             (void) WriteBlob(image,q-pixels,pixels);
1908           }
1909         break;
1910       }
1911       case '4':
1912       {
1913         /*
1914           Convert image to a PBM image.
1915         */
1916         (void) SetImageType(image,BilevelType,exception);
1917         image->depth=1;
1918         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1919         if (quantum_info == (QuantumInfo *) NULL)
1920           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1921         quantum_info->min_is_white=MagickTrue;
1922         pixels=GetQuantumPixels(quantum_info);
1923         for (y=0; y < (ssize_t) image->rows; y++)
1924         {
1925           register const Quantum
1926             *restrict p;
1927
1928           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1929           if (p == (const Quantum *) NULL)
1930             break;
1931           extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1932             GrayQuantum,pixels,exception);
1933           count=WriteBlob(image,extent,pixels);
1934           if (count != (ssize_t) extent)
1935             break;
1936           if (image->previous == (Image *) NULL)
1937             {
1938               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1939                 image->rows);
1940               if (status == MagickFalse)
1941                 break;
1942             }
1943         }
1944         quantum_info=DestroyQuantumInfo(quantum_info);
1945         break;
1946       }
1947       case '5':
1948       {
1949         /*
1950           Convert image to a PGM image.
1951         */
1952         if (image->depth > 32)
1953           image->depth=32;
1954         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
1955           ((MagickOffsetType) GetQuantumRange(image->depth)));
1956         (void) WriteBlobString(image,buffer);
1957         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1958         if (quantum_info == (QuantumInfo *) NULL)
1959           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1960         quantum_info->min_is_white=MagickTrue;
1961         pixels=GetQuantumPixels(quantum_info);
1962         extent=GetQuantumExtent(image,quantum_info,GrayQuantum);
1963         for (y=0; y < (ssize_t) image->rows; y++)
1964         {
1965           register const Quantum
1966             *restrict p;
1967
1968           register ssize_t
1969             x;
1970
1971           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1972           if (p == (const Quantum *) NULL)
1973             break;
1974           q=pixels;
1975           switch (image->depth)
1976           {
1977             case 8:
1978             case 16:
1979             case 32:
1980             {
1981               extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1982                 GrayQuantum,pixels,exception);
1983               break;
1984             }
1985             default:
1986             {
1987               if (image->depth <= 8)
1988                 {
1989                   for (x=0; x < (ssize_t) image->columns; x++)
1990                   {
1991                     if (IsPixelGray(image,p) == MagickFalse)
1992                       pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
1993                         image,p)),max_value);
1994                     else
1995                       {
1996                         if (image->depth == 8)
1997                           pixel=ScaleQuantumToChar(GetPixelRed(image,p));
1998                         else
1999                           pixel=ScaleQuantumToAny(GetPixelRed(image,p),
2000                           max_value);
2001                       }
2002                     q=PopCharPixel((unsigned char) pixel,q);
2003                     p+=GetPixelChannels(image);
2004                   }
2005                   extent=(size_t) (q-pixels);
2006                   break;
2007                 }
2008               if (image->depth <= 16)
2009                 {
2010                   for (x=0; x < (ssize_t) image->columns; x++)
2011                   {
2012                     if (IsPixelGray(image,p) == MagickFalse)
2013                       pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,
2014                         p)),max_value);
2015                     else
2016                       {
2017                         if (image->depth == 16)
2018                           pixel=ScaleQuantumToShort(GetPixelRed(image,p));
2019                         else
2020                           pixel=ScaleQuantumToAny(GetPixelRed(image,p),
2021                             max_value);
2022                       }
2023                     q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2024                     p+=GetPixelChannels(image);
2025                   }
2026                   extent=(size_t) (q-pixels);
2027                   break;
2028                 }
2029               for (x=0; x < (ssize_t) image->columns; x++)
2030               {
2031                 if (IsPixelGray(image,p) == MagickFalse)
2032                   pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,p)),
2033                     max_value);
2034                 else
2035                   {
2036                     if (image->depth == 16)
2037                       pixel=ScaleQuantumToLong(GetPixelRed(image,p));
2038                     else
2039                       pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2040                   }
2041                 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2042                 p+=GetPixelChannels(image);
2043               }
2044               extent=(size_t) (q-pixels);
2045               break;
2046             }
2047           }
2048           count=WriteBlob(image,extent,pixels);
2049           if (count != (ssize_t) extent)
2050             break;
2051           if (image->previous == (Image *) NULL)
2052             {
2053               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2054                 image->rows);
2055               if (status == MagickFalse)
2056                 break;
2057             }
2058         }
2059         quantum_info=DestroyQuantumInfo(quantum_info);
2060         break;
2061       }
2062       case '6':
2063       {
2064         /*
2065           Convert image to a PNM image.
2066         */
2067         (void) TransformImageColorspace(image,sRGBColorspace,exception);
2068         if (image->depth > 32)
2069           image->depth=32;
2070         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
2071           ((MagickOffsetType) GetQuantumRange(image->depth)));
2072         (void) WriteBlobString(image,buffer);
2073         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
2074         if (quantum_info == (QuantumInfo *) NULL)
2075           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2076         (void) SetQuantumEndian(image,quantum_info,MSBEndian);
2077         pixels=GetQuantumPixels(quantum_info);
2078         extent=GetQuantumExtent(image,quantum_info,quantum_type);
2079         for (y=0; y < (ssize_t) image->rows; y++)
2080         {
2081           register const Quantum
2082             *restrict p;
2083
2084           register ssize_t
2085             x;
2086
2087           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2088           if (p == (const Quantum *) NULL)
2089             break;
2090           q=pixels;
2091           switch (image->depth)
2092           {
2093             case 8:
2094             case 16:
2095             case 32:
2096             {
2097               extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2098                 quantum_type,pixels,exception);
2099               break;
2100             }
2101             default:
2102             {
2103               if (image->depth <= 8)
2104                 {
2105                   for (x=0; x < (ssize_t) image->columns; x++)
2106                   {
2107                     pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2108                     q=PopCharPixel((unsigned char) pixel,q);
2109                     pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2110                     q=PopCharPixel((unsigned char) pixel,q);
2111                     pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2112                     q=PopCharPixel((unsigned char) pixel,q);
2113                     p+=GetPixelChannels(image);
2114                   }
2115                   extent=(size_t) (q-pixels);
2116                   break;
2117                 }
2118               if (image->depth <= 16)
2119                 {
2120                   for (x=0; x < (ssize_t) image->columns; x++)
2121                   {
2122                     pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2123                     q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2124                     pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2125                     q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2126                     pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2127                     q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2128                     p+=GetPixelChannels(image);
2129                   }
2130                   extent=(size_t) (q-pixels);
2131                   break;
2132                 }
2133               for (x=0; x < (ssize_t) image->columns; x++)
2134               {
2135                 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2136                 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2137                 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2138                 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2139                 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2140                 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2141                 p+=GetPixelChannels(image);
2142               }
2143               extent=(size_t) (q-pixels);
2144               break;
2145             }
2146           }
2147           count=WriteBlob(image,extent,pixels);
2148           if (count != (ssize_t) extent)
2149             break;
2150           if (image->previous == (Image *) NULL)
2151             {
2152               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2153                 image->rows);
2154               if (status == MagickFalse)
2155                 break;
2156             }
2157         }
2158         quantum_info=DestroyQuantumInfo(quantum_info);
2159         break;
2160       }
2161       case '7':
2162       {
2163         /*
2164           Convert image to a PAM.
2165         */
2166         if (image->depth > 32)
2167           image->depth=32;
2168         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
2169         pixels=GetQuantumPixels(quantum_info);
2170         for (y=0; y < (ssize_t) image->rows; y++)
2171         {
2172           register const Quantum
2173             *restrict p;
2174
2175           register ssize_t
2176             x;
2177
2178           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2179           if (p == (const Quantum *) NULL)
2180             break;
2181           q=pixels;
2182           switch (image->depth)
2183           {
2184             case 8:
2185             case 16:
2186             case 32:
2187             {
2188               extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2189                 quantum_type,pixels,exception);
2190               break;
2191             }
2192             default:
2193             {
2194               switch (quantum_type)
2195               {
2196                 case GrayQuantum:
2197                 case GrayAlphaQuantum:
2198                 {
2199                   if (image->depth <= 8)
2200                     {
2201                       for (x=0; x < (ssize_t) image->columns; x++)
2202                       {
2203                         pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
2204                           image,p)),max_value);
2205                         q=PopCharPixel((unsigned char) pixel,q);
2206                         if (image->alpha_trait == BlendPixelTrait)
2207                           {
2208                             pixel=(unsigned char) ScaleQuantumToAny(
2209                               GetPixelAlpha(image,p),max_value);
2210                             q=PopCharPixel((unsigned char) pixel,q);
2211                           }
2212                         p+=GetPixelChannels(image);
2213                       }
2214                       break;
2215                     }
2216                   if (image->depth <= 16)
2217                     {
2218                       for (x=0; x < (ssize_t) image->columns; x++)
2219                       {
2220                         pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
2221                           image,p)),max_value);
2222                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2223                         if (image->alpha_trait == BlendPixelTrait)
2224                           {
2225                             pixel=(unsigned char) ScaleQuantumToAny(
2226                               GetPixelAlpha(image,p),max_value);
2227                             q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2228                           }
2229                         p+=GetPixelChannels(image);
2230                       }
2231                       break;
2232                     }
2233                   for (x=0; x < (ssize_t) image->columns; x++)
2234                   {
2235                     pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,
2236                       p)),max_value);
2237                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2238                     if (image->alpha_trait == BlendPixelTrait)
2239                       {
2240                         pixel=(unsigned char) ScaleQuantumToAny(
2241                           GetPixelAlpha(image,p),max_value);
2242                         q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2243                       }
2244                     p+=GetPixelChannels(image);
2245                   }
2246                   break;
2247                 }
2248                 case CMYKQuantum:
2249                 case CMYKAQuantum:
2250                 {
2251                   if (image->depth <= 8)
2252                     {
2253                       for (x=0; x < (ssize_t) image->columns; x++)
2254                       {
2255                         pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2256                         q=PopCharPixel((unsigned char) pixel,q);
2257                         pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2258                           max_value);
2259                         q=PopCharPixel((unsigned char) pixel,q);
2260                         pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2261                           max_value);
2262                         q=PopCharPixel((unsigned char) pixel,q);
2263                         pixel=ScaleQuantumToAny(GetPixelBlack(image,p),
2264                           max_value);
2265                         q=PopCharPixel((unsigned char) pixel,q);
2266                         if (image->alpha_trait == BlendPixelTrait)
2267                           {
2268                             pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2269                               max_value);
2270                             q=PopCharPixel((unsigned char) pixel,q);
2271                           }
2272                         p+=GetPixelChannels(image);
2273                       }
2274                       break;
2275                     }
2276                   if (image->depth <= 16)
2277                     {
2278                       for (x=0; x < (ssize_t) image->columns; x++)
2279                       {
2280                         pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2281                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2282                         pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2283                           max_value);
2284                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2285                         pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2286                           max_value);
2287                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2288                         pixel=ScaleQuantumToAny(GetPixelBlack(image,p),
2289                           max_value);
2290                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2291                         if (image->alpha_trait == BlendPixelTrait)
2292                           {
2293                             pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2294                               max_value);
2295                             q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2296                           }
2297                         p+=GetPixelChannels(image);
2298                       }
2299                       break;
2300                     }
2301                   for (x=0; x < (ssize_t) image->columns; x++)
2302                   {
2303                     pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2304                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2305                     pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2306                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2307                     pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2308                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2309                     pixel=ScaleQuantumToAny(GetPixelBlack(image,p),max_value);
2310                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2311                     if (image->alpha_trait == BlendPixelTrait)
2312                       {
2313                         pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2314                           max_value);
2315                         q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2316                       }
2317                     p+=GetPixelChannels(image);
2318                   }
2319                   break;
2320                 }
2321                 default:
2322                 {
2323                   if (image->depth <= 8)
2324                     {
2325                       for (x=0; x < (ssize_t) image->columns; x++)
2326                       {
2327                         pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2328                         q=PopCharPixel((unsigned char) pixel,q);
2329                         pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2330                           max_value);
2331                         q=PopCharPixel((unsigned char) pixel,q);
2332                         pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2333                           max_value);
2334                         q=PopCharPixel((unsigned char) pixel,q);
2335                         if (image->alpha_trait == BlendPixelTrait)
2336                           {
2337                             pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2338                               max_value);
2339                             q=PopCharPixel((unsigned char) pixel,q);
2340                           }
2341                         p+=GetPixelChannels(image);
2342                       }
2343                       break;
2344                     }
2345                   if (image->depth <= 16)
2346                     {
2347                       for (x=0; x < (ssize_t) image->columns; x++)
2348                       {
2349                         pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2350                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2351                         pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2352                           max_value);
2353                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2354                         pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2355                           max_value);
2356                         q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2357                         if (image->alpha_trait == BlendPixelTrait)
2358                           {
2359                             pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2360                               max_value);
2361                             q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2362                           }
2363                         p+=GetPixelChannels(image);
2364                       }
2365                       break;
2366                     }
2367                   for (x=0; x < (ssize_t) image->columns; x++)
2368                   {
2369                     pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2370                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2371                     pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2372                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2373                     pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2374                     q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2375                     if (image->alpha_trait == BlendPixelTrait)
2376                       {
2377                         pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2378                           max_value);
2379                         q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2380                       }
2381                     p+=GetPixelChannels(image);
2382                   }
2383                   break;
2384                 }
2385               }
2386               extent=(size_t) (q-pixels);
2387               break;
2388             }
2389           }
2390           count=WriteBlob(image,extent,pixels);
2391           if (count != (ssize_t) extent)
2392             break;
2393           if (image->previous == (Image *) NULL)
2394             {
2395               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2396                 image->rows);
2397               if (status == MagickFalse)
2398                 break;
2399             }
2400         }
2401         quantum_info=DestroyQuantumInfo(quantum_info);
2402         break;
2403       }
2404       case 'F':
2405       case 'f':
2406       {
2407         (void) WriteBlobString(image,image->endian == LSBEndian ? "-1.0\n" :
2408           "1.0\n");
2409         image->depth=32;
2410         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
2411         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
2412         if (quantum_info == (QuantumInfo *) NULL)
2413           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2414         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2415         if (status == MagickFalse)
2416           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2417         pixels=GetQuantumPixels(quantum_info);
2418         for (y=(ssize_t) image->rows-1; y >= 0; y--)
2419         {
2420           register const Quantum
2421             *restrict p;
2422
2423           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2424           if (p == (const Quantum *) NULL)
2425             break;
2426           extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2427             quantum_type,pixels,exception);
2428           (void) WriteBlob(image,extent,pixels);
2429           if (image->previous == (Image *) NULL)
2430             {
2431               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2432                 image->rows);
2433               if (status == MagickFalse)
2434                 break;
2435             }
2436         }
2437         quantum_info=DestroyQuantumInfo(quantum_info);
2438         break;
2439       }
2440     }
2441     if (GetNextImageInList(image) == (Image *) NULL)
2442       break;
2443     image=SyncNextImageInList(image);
2444     status=SetImageProgress(image,SaveImagesTag,scene++,
2445       GetImageListLength(image));
2446     if (status == MagickFalse)
2447       break;
2448   } while (image_info->adjoin != MagickFalse);
2449   (void) CloseBlob(image);
2450   return(MagickTrue);
2451 }