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