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