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