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