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