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