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