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