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