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