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