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