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