]> 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             *restrict 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             *restrict p;
810
811           register long
812             x;
813
814           register PixelPacket
815             *restrict q;
816
817           ssize_t
818             count;
819
820           unsigned char
821             *pixels;
822
823           if (status == MagickFalse)
824             continue;
825           pixels=GetQuantumPixels(quantum_info);
826 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
827   #pragma omp critical (MagickCore_ReadPNMImage)
828 #endif
829           {
830             count=ReadBlob(image,extent,pixels);
831             if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
832                 (image->previous == (Image *) NULL))
833               {
834                 MagickBooleanType
835                   proceed;
836
837                 proceed=SetImageProgress(image,LoadImageTag,row,image->rows);
838                 if (proceed == MagickFalse)
839                   status=MagickFalse;
840               }
841             offset=row++;
842           }
843           if (count != (ssize_t) extent)
844             status=MagickFalse;
845           q=QueueCacheViewAuthenticPixels(image_view,0,offset,image->columns,1,
846             exception);
847           if (q == (PixelPacket *) NULL)
848             {
849               status=MagickFalse;
850               continue;
851             }
852           p=pixels;
853           if (image->depth == 8)
854             for (x=0; x < (long) image->columns; x++)
855             {
856               q->red=ScaleCharToQuantum(*p++);
857               q->green=ScaleCharToQuantum(*p++);
858               q->blue=ScaleCharToQuantum(*p++);
859               q->opacity=OpaqueOpacity;
860               q++;
861             }
862           else
863             if (image->depth == 16)
864               {
865                 unsigned short
866                   pixel;
867
868                 for (x=0; x < (long) image->columns; x++)
869                 {
870                   p=PushShortPixel(MSBEndian,p,&pixel);
871                   q->red=ScaleShortToQuantum(pixel);
872                   p=PushShortPixel(MSBEndian,p,&pixel);
873                   q->green=ScaleShortToQuantum(pixel);
874                   p=PushShortPixel(MSBEndian,p,&pixel);
875                   q->blue=ScaleShortToQuantum(pixel);
876                   q->opacity=OpaqueOpacity;
877                   q++;
878                 }
879               }
880             else
881               if (image->depth <= 8)
882                 {
883                   unsigned char
884                     pixel;
885
886                   for (x=0; x < (long) image->columns; x++)
887                   {
888                     p=PushCharPixel(p,&pixel);
889                     q->red=ScaleAnyToQuantum(pixel,range);
890                     p=PushCharPixel(p,&pixel);
891                     q->green=ScaleAnyToQuantum(pixel,range);
892                     p=PushCharPixel(p,&pixel);
893                     q->blue=ScaleAnyToQuantum(pixel,range);
894                     q->opacity=OpaqueOpacity;
895                     q++;
896                   }
897                 }
898               else
899                 {
900                   unsigned short
901                     pixel;
902
903                   for (x=0; x < (long) image->columns; x++)
904                   {
905                     p=PushShortPixel(MSBEndian,p,&pixel);
906                     q->red=ScaleAnyToQuantum(pixel,range);
907                     p=PushShortPixel(MSBEndian,p,&pixel);
908                     q->green=ScaleAnyToQuantum(pixel,range);
909                     p=PushShortPixel(MSBEndian,p,&pixel);
910                     q->blue=ScaleAnyToQuantum(pixel,range);
911                     q->opacity=OpaqueOpacity;
912                     q++;
913                   }
914                 }
915           if ((type == BilevelType) || (type == GrayscaleType))
916             {
917               q=QueueCacheViewAuthenticPixels(image_view,0,offset,
918                 image->columns,1,exception);
919               for (x=0; x < (long) image->columns; x++)
920               {
921                 if ((type == BilevelType) &&
922                     (IsMonochromePixel(q) == MagickFalse))
923                   type=IsGrayPixel(q) == MagickFalse ? UndefinedType :
924                     GrayscaleType;
925                 if ((type == GrayscaleType) && (IsGrayPixel(q) == MagickFalse))
926                   type=UndefinedType;
927                 if ((type != BilevelType) && (type != GrayscaleType))
928                   break;
929                 q++;
930               }
931             }
932           sync=SyncCacheViewAuthenticPixels(image_view,exception);
933           if (sync == MagickFalse)
934             status=MagickFalse;
935         }
936         image_view=DestroyCacheView(image_view);
937         quantum_info=DestroyQuantumInfo(quantum_info);
938         if (status == MagickFalse)
939           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
940         if (type != UndefinedType)
941           image->type=type;
942         break;
943       }
944       case '7':
945       {
946         register IndexPacket
947           *indexes;
948
949         QuantumAny
950           range;
951
952         unsigned long
953           channels;
954
955         /*
956           Convert PAM raster image to pixel packets.
957         */
958         range=GetQuantumRange(image->depth);
959         switch (quantum_type)
960         {
961           case GrayQuantum:
962           case GrayAlphaQuantum:
963           {
964             channels=1;
965             break;
966           }
967           case CMYKQuantum:
968           case CMYKAQuantum:
969           {
970             channels=4;
971             break;
972           }
973           default:
974           {
975             channels=3;
976             break;
977           }
978         }
979         if (image->matte != MagickFalse)
980           channels++;
981         extent=channels*(image->depth <= 8 ? 1 : 2)*image->columns;
982         quantum_info=AcquireQuantumInfo(image_info,image);
983         if (quantum_info == (QuantumInfo *) NULL)
984           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
985         image_view=AcquireCacheView(image);
986 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
987   #pragma omp parallel for schedule(static,1) shared(row,status,quantum_type)
988 #endif
989         for (y=0; y < (long) image->rows; y++)
990         {
991           long
992             offset;
993
994           MagickBooleanType
995             sync;
996
997           register const unsigned char
998             *restrict p;
999
1000           register long
1001             x;
1002
1003           register PixelPacket
1004             *restrict q;
1005
1006           ssize_t
1007             count;
1008
1009           unsigned char
1010             *pixels;
1011
1012           if (status == MagickFalse)
1013             continue;
1014           pixels=GetQuantumPixels(quantum_info);
1015 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
1016   #pragma omp critical (MagickCore_ReadPNMImage)
1017 #endif
1018           {
1019             count=ReadBlob(image,extent,pixels);
1020             if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1021                 (image->previous == (Image *) NULL))
1022               {
1023                 MagickBooleanType
1024                   proceed;
1025
1026                 proceed=SetImageProgress(image,LoadImageTag,row,image->rows);
1027                 if (proceed == MagickFalse)
1028                   status=MagickFalse;
1029               }
1030             offset=row++;
1031           }
1032           if (count != (ssize_t) extent)
1033             status=MagickFalse;
1034           q=QueueCacheViewAuthenticPixels(image_view,0,offset,image->columns,1,
1035             exception);
1036           if (q == (PixelPacket *) NULL)
1037             {
1038               status=MagickFalse;
1039               continue;
1040             }
1041           indexes=GetCacheViewAuthenticIndexQueue(image_view);
1042           p=pixels;
1043           if ((image->depth == 8) || (image->depth == 16))
1044             (void) ImportQuantumPixels(image,image_view,quantum_info,
1045               quantum_type,pixels,exception);
1046           else
1047             switch (quantum_type)
1048             {
1049               case GrayQuantum:
1050               case GrayAlphaQuantum:
1051               {
1052                 if (image->depth <= 8)
1053                   {
1054                     unsigned char
1055                       pixel;
1056
1057                     for (x=0; x < (long) image->columns; x++)
1058                     {
1059                       p=PushCharPixel(p,&pixel);
1060                       SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1061                       q->green=q->red;
1062                       q->blue=q->red;
1063                       SetOpacityPixelComponent(q,OpaqueOpacity);
1064                       if (image->matte != MagickFalse)
1065                         {
1066                           p=PushCharPixel(p,&pixel);
1067                           SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1068                         }
1069                       q++;
1070                     }
1071                   }
1072                 else
1073                   {
1074                     unsigned short
1075                       pixel;
1076
1077                     for (x=0; x < (long) image->columns; x++)
1078                     {
1079                       p=PushShortPixel(MSBEndian,p,&pixel);
1080                       SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1081                       q->green=q->red;
1082                       q->blue=q->red;
1083                       SetOpacityPixelComponent(q,OpaqueOpacity);
1084                       if (image->matte != MagickFalse)
1085                         {
1086                           p=PushShortPixel(MSBEndian,p,&pixel);
1087                           SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1088                         }
1089                       q++;
1090                     }
1091                   }
1092                 break;
1093               }
1094               case CMYKQuantum:
1095               case CMYKAQuantum:
1096               {
1097                 if (image->depth <= 8)
1098                   {
1099                     unsigned char
1100                       pixel;
1101
1102                     for (x=0; x < (long) image->columns; x++)
1103                     {
1104                       p=PushCharPixel(p,&pixel);
1105                       SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1106                       p=PushCharPixel(p,&pixel);
1107                       SetGreenPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1108                       p=PushCharPixel(p,&pixel);
1109                       SetBluePixelComponent(q,ScaleAnyToQuantum(pixel,range));
1110                       p=PushCharPixel(p,&pixel);
1111                       indexes[x]=ScaleAnyToQuantum(pixel,range);
1112                       SetOpacityPixelComponent(q,OpaqueOpacity);
1113                       if (image->matte != MagickFalse)
1114                         {
1115                           p=PushCharPixel(p,&pixel);
1116                           SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1117                         }
1118                       q++;
1119                     }
1120                   }
1121                 else
1122                   {
1123                     unsigned short
1124                       pixel;
1125
1126                     for (x=0; x < (long) image->columns; x++)
1127                     {
1128                       p=PushShortPixel(MSBEndian,p,&pixel);
1129                       SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1130                       p=PushShortPixel(MSBEndian,p,&pixel);
1131                       SetGreenPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1132                       p=PushShortPixel(MSBEndian,p,&pixel);
1133                       SetBluePixelComponent(q,ScaleAnyToQuantum(pixel,range));
1134                       p=PushShortPixel(MSBEndian,p,&pixel);
1135                       indexes[x]=ScaleAnyToQuantum(pixel,range);
1136                       SetOpacityPixelComponent(q,OpaqueOpacity);
1137                       if (image->matte != MagickFalse)
1138                         {
1139                           p=PushShortPixel(MSBEndian,p,&pixel);
1140                           SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1141                         }
1142                       q++;
1143                     }
1144                   }
1145                 break;
1146               }
1147               default:
1148               {
1149                 if (image->depth <= 8)
1150                   {
1151                     unsigned char
1152                       pixel;
1153
1154                     for (x=0; x < (long) image->columns; x++)
1155                     {
1156                       p=PushCharPixel(p,&pixel);
1157                       SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1158                       p=PushCharPixel(p,&pixel);
1159                       SetGreenPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1160                       p=PushCharPixel(p,&pixel);
1161                       SetBluePixelComponent(q,ScaleAnyToQuantum(pixel,range));
1162                       SetOpacityPixelComponent(q,OpaqueOpacity);
1163                       if (image->matte != MagickFalse)
1164                         {
1165                           p=PushCharPixel(p,&pixel);
1166                           SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1167                         }
1168                       q++;
1169                     }
1170                   }
1171                 else
1172                   {
1173                     unsigned short
1174                       pixel;
1175
1176                     for (x=0; x < (long) image->columns; x++)
1177                     {
1178                       p=PushShortPixel(MSBEndian,p,&pixel);
1179                       SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1180                       p=PushShortPixel(MSBEndian,p,&pixel);
1181                       SetGreenPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1182                       p=PushShortPixel(MSBEndian,p,&pixel);
1183                       SetBluePixelComponent(q,ScaleAnyToQuantum(pixel,range));
1184                       SetOpacityPixelComponent(q,OpaqueOpacity);
1185                       if (image->matte != MagickFalse)
1186                         {
1187                           p=PushShortPixel(MSBEndian,p,&pixel);
1188                           SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
1189                         }
1190                       q++;
1191                     }
1192                   }
1193                 break;
1194               }
1195             }
1196           sync=SyncCacheViewAuthenticPixels(image_view,exception);
1197           if (sync == MagickFalse)
1198             status=MagickFalse;
1199         }
1200         image_view=DestroyCacheView(image_view);
1201         quantum_info=DestroyQuantumInfo(quantum_info);
1202         if (status == MagickFalse)
1203           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1204         SetQuantumImageType(image,quantum_type);
1205         break;
1206       }
1207       case 'F':
1208       case 'f':
1209       {
1210         /*
1211           Convert PFM raster image to pixel packets.
1212         */
1213         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
1214         image->endian=quantum_scale < 0.0 ? LSBEndian : MSBEndian;
1215         image->depth=32;
1216         quantum_info=AcquireQuantumInfo(image_info,image);
1217         if (quantum_info == (QuantumInfo *) NULL)
1218           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1219         status=SetQuantumDepth(image,quantum_info,32);
1220         if (status == MagickFalse)
1221           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1222         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1223         if (status == MagickFalse)
1224           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1225         SetQuantumScale(quantum_info,(MagickRealType) QuantumRange*
1226           fabs(quantum_scale));
1227         extent=GetQuantumExtent(image,quantum_info,quantum_type);
1228         image_view=AcquireCacheView(image);
1229 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
1230   #pragma omp parallel for schedule(static,1) shared(row,status,quantum_type)
1231 #endif
1232         for (y=0; y < (long) image->rows; y++)
1233         {
1234           long
1235             offset;
1236
1237           MagickBooleanType
1238             sync;
1239
1240           register PixelPacket
1241             *restrict q;
1242
1243           ssize_t
1244             count;
1245
1246           size_t
1247             length;
1248
1249           unsigned char
1250             *pixels;
1251
1252           if (status == MagickFalse)
1253             continue;
1254           pixels=GetQuantumPixels(quantum_info);
1255 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
1256   #pragma omp critical (MagickCore_ReadPNMImage)
1257 #endif
1258           {
1259             count=ReadBlob(image,extent,pixels);
1260             if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1261                 (image->previous == (Image *) NULL))
1262               {
1263                 MagickBooleanType
1264                   proceed;
1265
1266                 proceed=SetImageProgress(image,LoadImageTag,row,image->rows);
1267                 if (proceed == MagickFalse)
1268                   status=MagickFalse;
1269               }
1270             offset=row++;
1271           }
1272           if ((size_t) count != extent)
1273             status=MagickFalse;
1274           q=QueueCacheViewAuthenticPixels(image_view,0,(long) (image->rows-
1275             offset-1),image->columns,1,exception);
1276           if (q == (PixelPacket *) NULL)
1277             {
1278               status=MagickFalse;
1279               continue;
1280             }
1281           length=ImportQuantumPixels(image,image_view,quantum_info,quantum_type,
1282             pixels,exception);
1283           if (length != extent)
1284             status=MagickFalse;
1285           sync=SyncCacheViewAuthenticPixels(image_view,exception);
1286           if (sync == MagickFalse)
1287             status=MagickFalse;
1288         }
1289         image_view=DestroyCacheView(image_view);
1290         quantum_info=DestroyQuantumInfo(quantum_info);
1291         if (status == MagickFalse)
1292           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1293         SetQuantumImageType(image,quantum_type);
1294         break;
1295       }
1296       default:
1297         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1298     }
1299     if (EOFBlob(image) != MagickFalse)
1300       (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
1301         "UnexpectedEndOfFile","`%s'",image->filename);
1302     /*
1303       Proceed to next image.
1304     */
1305     if (image_info->number_scenes != 0)
1306       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1307         break;
1308     if ((format == '1') || (format == '2') || (format == '3'))
1309       do
1310       {
1311         /*
1312           Skip to end of line.
1313         */
1314         count=ReadBlob(image,1,(unsigned char *) &format);
1315         if (count == 0)
1316           break;
1317         if ((count != 0) && (format == 'P'))
1318           break;
1319       } while (format != '\n');
1320     count=ReadBlob(image,1,(unsigned char *) &format);
1321     if ((count == 1) && (format == 'P'))
1322       {
1323         /*
1324           Allocate next image structure.
1325         */
1326         AcquireNextImage(image_info,image);
1327         if (GetNextImageInList(image) == (Image *) NULL)
1328           {
1329             image=DestroyImageList(image);
1330             return((Image *) NULL);
1331           }
1332         image=SyncNextImageInList(image);
1333         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1334           GetBlobSize(image));
1335         if (status == MagickFalse)
1336           break;
1337       }
1338   } while ((count == 1) && (format == 'P'));
1339   (void) CloseBlob(image);
1340   return(GetFirstImageInList(image));
1341 }
1342 \f
1343 /*
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345 %                                                                             %
1346 %                                                                             %
1347 %                                                                             %
1348 %   R e g i s t e r P N M I m a g e                                           %
1349 %                                                                             %
1350 %                                                                             %
1351 %                                                                             %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 %
1354 %  RegisterPNMImage() adds properties for the PNM image format to
1355 %  the list of supported formats.  The properties include the image format
1356 %  tag, a method to read and/or write the format, whether the format
1357 %  supports the saving of more than one frame to the same file or blob,
1358 %  whether the format supports native in-memory I/O, and a brief
1359 %  description of the format.
1360 %
1361 %  The format of the RegisterPNMImage method is:
1362 %
1363 %      unsigned long RegisterPNMImage(void)
1364 %
1365 */
1366 ModuleExport unsigned long RegisterPNMImage(void)
1367 {
1368   MagickInfo
1369     *entry;
1370
1371   entry=SetMagickInfo("PAM");
1372   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1373   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1374   entry->description=ConstantString("Common 2-dimensional bitmap format");
1375   entry->module=ConstantString("PNM");
1376   (void) RegisterMagickInfo(entry);
1377   entry=SetMagickInfo("PBM");
1378   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1379   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1380   entry->description=ConstantString("Portable bitmap format (black and white)");
1381   entry->module=ConstantString("PNM");
1382   (void) RegisterMagickInfo(entry);
1383   entry=SetMagickInfo("PFM");
1384   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1385   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1386   entry->description=ConstantString("Portable float format");
1387   entry->module=ConstantString("PFM");
1388   (void) RegisterMagickInfo(entry);
1389   entry=SetMagickInfo("PGM");
1390   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1391   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1392   entry->description=ConstantString("Portable graymap format (gray scale)");
1393   entry->module=ConstantString("PNM");
1394   (void) RegisterMagickInfo(entry);
1395   entry=SetMagickInfo("PNM");
1396   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1397   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1398   entry->magick=(IsImageFormatHandler *) IsPNM;
1399   entry->description=ConstantString("Portable anymap");
1400   entry->module=ConstantString("PNM");
1401   (void) RegisterMagickInfo(entry);
1402   entry=SetMagickInfo("PPM");
1403   entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1404   entry->encoder=(EncodeImageHandler *) WritePNMImage;
1405   entry->description=ConstantString("Portable pixmap format (color)");
1406   entry->module=ConstantString("PNM");
1407   (void) RegisterMagickInfo(entry);
1408   return(MagickImageCoderSignature);
1409 }
1410 \f
1411 /*
1412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413 %                                                                             %
1414 %                                                                             %
1415 %                                                                             %
1416 %   U n r e g i s t e r P N M I m a g e                                       %
1417 %                                                                             %
1418 %                                                                             %
1419 %                                                                             %
1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 %
1422 %  UnregisterPNMImage() removes format registrations made by the
1423 %  PNM module from the list of supported formats.
1424 %
1425 %  The format of the UnregisterPNMImage method is:
1426 %
1427 %      UnregisterPNMImage(void)
1428 %
1429 */
1430 ModuleExport void UnregisterPNMImage(void)
1431 {
1432   (void) UnregisterMagickInfo("PAM");
1433   (void) UnregisterMagickInfo("PBM");
1434   (void) UnregisterMagickInfo("PGM");
1435   (void) UnregisterMagickInfo("PNM");
1436   (void) UnregisterMagickInfo("PPM");
1437 }
1438 \f
1439 /*
1440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1441 %                                                                             %
1442 %                                                                             %
1443 %                                                                             %
1444 %   W r i t e P N M I m a g e                                                 %
1445 %                                                                             %
1446 %                                                                             %
1447 %                                                                             %
1448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449 %
1450 %  WritePNMImage() writes an image to a file in the PNM rasterfile format.
1451 %
1452 %  The format of the WritePNMImage method is:
1453 %
1454 %      MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
1455 %
1456 %  A description of each parameter follows.
1457 %
1458 %    o image_info: the image info.
1459 %
1460 %    o image:  The image.
1461 %
1462 */
1463 static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
1464 {
1465   char
1466     buffer[MaxTextExtent],
1467     format,
1468     magick[MaxTextExtent];
1469
1470   const char
1471     *value;
1472
1473   IndexPacket
1474     index;
1475
1476   long
1477     y;
1478
1479   MagickBooleanType
1480     status;
1481
1482   MagickOffsetType
1483     scene;
1484
1485   QuantumAny
1486     pixel;
1487
1488   QuantumInfo
1489     *quantum_info;
1490
1491   QuantumType
1492     quantum_type;
1493
1494   register long
1495     i;
1496
1497   register unsigned char
1498     *pixels,
1499     *q;
1500
1501   ssize_t
1502     count;
1503
1504   size_t
1505     extent,
1506     packet_size;
1507
1508   /*
1509     Open output image file.
1510   */
1511   assert(image_info != (const ImageInfo *) NULL);
1512   assert(image_info->signature == MagickSignature);
1513   assert(image != (Image *) NULL);
1514   assert(image->signature == MagickSignature);
1515   if (image->debug != MagickFalse)
1516     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1517   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1518   if (status == MagickFalse)
1519     return(status);
1520   scene=0;
1521   do
1522   {
1523     /*
1524       Write PNM file header.
1525     */
1526     packet_size=3;
1527     quantum_type=RGBQuantum;
1528     (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
1529     switch (magick[1])
1530     {
1531       case 'A':
1532       case 'a':
1533       {
1534         format='7';
1535         break;
1536       }
1537       case 'B':
1538       case 'b':
1539       {
1540         format='4';
1541         if (image_info->compression == NoCompression)
1542           format='1';
1543         break;
1544       }
1545       case 'F':
1546       case 'f':
1547       {
1548         format='F';
1549         if (IsGrayImage(image,&image->exception) != MagickFalse)
1550           format='f';
1551         break;
1552       }
1553       case 'G':
1554       case 'g':
1555       {
1556         format='5';
1557         if (image_info->compression == NoCompression)
1558           format='2';
1559         break;
1560       }
1561       case 'N':
1562       case 'n':
1563       {
1564         if ((image_info->type != TrueColorType) &&
1565             (IsGrayImage(image,&image->exception) != MagickFalse))
1566           {
1567             format='5';
1568             if (image_info->compression == NoCompression)
1569               format='2';
1570             if (IsMonochromeImage(image,&image->exception) != MagickFalse)
1571               {
1572                 format='4';
1573                 if (image_info->compression == NoCompression)
1574                   format='1';
1575               }
1576             break;
1577           }
1578       }
1579       default:
1580       {
1581         format='6';
1582         if (image_info->compression == NoCompression)
1583           format='3';
1584         break;
1585       }
1586     }
1587     (void) FormatMagickString(buffer,MaxTextExtent,"P%c\n",format);
1588     (void) WriteBlobString(image,buffer);
1589     value=GetImageProperty(image,"comment");
1590     if (value != (const char *) NULL)
1591       {
1592         register const char
1593           *p;
1594
1595         /*
1596           Write comments to file.
1597         */
1598         (void) WriteBlobByte(image,'#');
1599         for (p=value; *p != '\0'; p++)
1600         {
1601           (void) WriteBlobByte(image,(unsigned char) *p);
1602           if ((*p == '\r') && (*(p+1) != '\0'))
1603             (void) WriteBlobByte(image,'#');
1604           if ((*p == '\n') && (*(p+1) != '\0'))
1605             (void) WriteBlobByte(image,'#');
1606         }
1607         (void) WriteBlobByte(image,'\n');
1608       }
1609     if (format != '7')
1610       {
1611         if (image->colorspace != RGBColorspace)
1612           (void) TransformImageColorspace(image,RGBColorspace);
1613         (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n",
1614           image->columns,image->rows);
1615         (void) WriteBlobString(image,buffer);
1616       }
1617     else
1618       {
1619         char
1620           type[MaxTextExtent];
1621
1622         /*
1623           PAM header.
1624         */
1625         (void) FormatMagickString(buffer,MaxTextExtent,
1626           "WIDTH %lu\nHEIGHT %lu\n",image->columns,image->rows);
1627         (void) WriteBlobString(image,buffer);
1628         quantum_type=GetQuantumType(image,&image->exception);
1629         switch (quantum_type)
1630         {
1631           case CMYKQuantum:
1632           case CMYKAQuantum:
1633           {
1634             packet_size=4;
1635             (void) CopyMagickString(type,"CMYK",MaxTextExtent);
1636             break;
1637           }
1638           case GrayQuantum:
1639           case GrayAlphaQuantum:
1640           {
1641             packet_size=1;
1642             (void) CopyMagickString(type,"GRAYSCALE",MaxTextExtent);
1643             break;
1644           }
1645           default:
1646           {
1647             quantum_type=RGBQuantum;
1648             if (image->matte != MagickFalse)
1649               quantum_type=RGBAQuantum;
1650             packet_size=3;
1651             (void) CopyMagickString(type,"RGB",MaxTextExtent);
1652             break;
1653           }
1654         }
1655         if (image->matte != MagickFalse)
1656           {
1657             packet_size++;
1658             (void) ConcatenateMagickString(type,"_ALPHA",MaxTextExtent);
1659           }
1660         if (image->depth > 16)
1661           image->depth=16;
1662         (void) FormatMagickString(buffer,MaxTextExtent,
1663           "DEPTH %lu\nMAXVAL %lu\n",(unsigned long) packet_size,(unsigned long)
1664           GetQuantumRange(image->depth));
1665         (void) WriteBlobString(image,buffer);
1666         (void) FormatMagickString(buffer,MaxTextExtent,"TUPLTYPE %s\nENDHDR\n",
1667           type);
1668         (void) WriteBlobString(image,buffer);
1669       }
1670     /*
1671       Convert runextent encoded to PNM raster pixels.
1672     */
1673     switch (format)
1674     {
1675       case '1':
1676       {
1677         unsigned char
1678           pixels[2048];
1679
1680         /*
1681           Convert image to a PBM image.
1682         */
1683         q=pixels;
1684         for (y=0; y < (long) image->rows; y++)
1685         {
1686           register const IndexPacket
1687             *restrict indexes;
1688
1689           register const PixelPacket
1690             *restrict p;
1691
1692           register long
1693             x;
1694
1695           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1696           if (p == (const PixelPacket *) NULL)
1697             break;
1698           indexes=GetVirtualIndexQueue(image);
1699           for (x=0; x < (long) image->columns; x++)
1700           {
1701             pixel=PixelIntensityToQuantum(p);
1702             *q++=(unsigned char) (pixel >= (Quantum) (QuantumRange/2) ?
1703               '0' : '1');
1704             *q++=' ';
1705             if ((q-pixels+2) >= 80)
1706               {
1707                 *q++='\n';
1708                 (void) WriteBlob(image,q-pixels,pixels);
1709                 q=pixels;
1710                 i=0;
1711               }
1712             p++;
1713           }
1714           if (image->previous == (Image *) NULL)
1715             {
1716               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1717               if (status == MagickFalse)
1718                 break;
1719             }
1720         }
1721         if (q != pixels)
1722           {
1723             *q++='\n';
1724             (void) WriteBlob(image,q-pixels,pixels);
1725           }
1726         break;
1727       }
1728       case '2':
1729       {
1730         unsigned char
1731           pixels[2048];
1732
1733         /*
1734           Convert image to a PGM image.
1735         */
1736         if (image->depth <= 8)
1737           (void) WriteBlobString(image,"255\n");
1738         else
1739           (void) WriteBlobString(image,"65535\n");
1740         q=pixels;
1741         for (y=0; y < (long) image->rows; y++)
1742         {
1743           register const PixelPacket
1744             *restrict p;
1745
1746           register long
1747             x;
1748
1749           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1750           if (p == (const PixelPacket *) NULL)
1751             break;
1752           for (x=0; x < (long) image->columns; x++)
1753           {
1754             index=PixelIntensityToQuantum(p);
1755             if (image->depth <= 8)
1756               count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,"%u ",
1757                 ScaleQuantumToChar(index));
1758             else
1759               count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,"%u ",
1760                 ScaleQuantumToShort(index));
1761             extent=(size_t) count;
1762             (void) strncpy((char *) q,buffer,extent);
1763             q+=extent;
1764             if ((q-pixels+extent) >= 80)
1765               {
1766                 *q++='\n';
1767                 (void) WriteBlob(image,q-pixels,pixels);
1768                 q=pixels;
1769               }
1770             p++;
1771           }
1772           if (image->previous == (Image *) NULL)
1773             {
1774               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1775               if (status == MagickFalse)
1776                 break;
1777             }
1778         }
1779         if (q != pixels)
1780           {
1781             *q++='\n';
1782             (void) WriteBlob(image,q-pixels,pixels);
1783           }
1784         break;
1785       }
1786       case '3':
1787       {
1788         unsigned char
1789           pixels[2048];
1790
1791         /*
1792           Convert image to a PNM image.
1793         */
1794         if (image->depth <= 8)
1795           (void) WriteBlobString(image,"255\n");
1796         else
1797           (void) WriteBlobString(image,"65535\n");
1798         q=pixels;
1799         for (y=0; y < (long) image->rows; y++)
1800         {
1801           register const PixelPacket
1802             *restrict p;
1803
1804           register long
1805             x;
1806
1807           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1808           if (p == (const PixelPacket *) NULL)
1809             break;
1810           for (x=0; x < (long) image->columns; x++)
1811           {
1812             if (image->depth <= 8)
1813               count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,
1814                 "%u %u %u ",ScaleQuantumToChar(GetRedPixelComponent(p)),
1815                 ScaleQuantumToChar(GetGreenPixelComponent(p)),
1816                 ScaleQuantumToChar(GetBluePixelComponent(p)));
1817             else
1818               count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,
1819                 "%u %u %u ",ScaleQuantumToShort(GetRedPixelComponent(p)),
1820                 ScaleQuantumToShort(GetGreenPixelComponent(p)),
1821                 ScaleQuantumToShort(GetBluePixelComponent(p)));
1822             extent=(size_t) count;
1823             (void) strncpy((char *) q,buffer,extent);
1824             q+=extent;
1825             if ((q-pixels+extent) >= 80)
1826               {
1827                 *q++='\n';
1828                 (void) WriteBlob(image,q-pixels,pixels);
1829                 q=pixels;
1830               }
1831             p++;
1832           }
1833           if (image->previous == (Image *) NULL)
1834             {
1835               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1836               if (status == MagickFalse)
1837                 break;
1838             }
1839         }
1840         if (q != pixels)
1841           {
1842             *q++='\n';
1843             (void) WriteBlob(image,q-pixels,pixels);
1844           }
1845         break;
1846       }
1847       case '4':
1848       {
1849         /*
1850           Convert image to a PBM image.
1851         */
1852         image->depth=1;
1853         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1854         if (quantum_info == (QuantumInfo *) NULL)
1855           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1856         quantum_info->min_is_white=MagickTrue;
1857         pixels=GetQuantumPixels(quantum_info);
1858         for (y=0; y < (long) image->rows; y++)
1859         {
1860           register const PixelPacket
1861             *restrict p;
1862
1863           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1864           if (p == (const PixelPacket *) NULL)
1865             break;
1866           extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1867             quantum_info,GrayQuantum,pixels,&image->exception);
1868           count=WriteBlob(image,extent,pixels);
1869           if (count != (ssize_t) extent)
1870             break;
1871           if (image->previous == (Image *) NULL)
1872             {
1873               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1874               if (status == MagickFalse)
1875                 break;
1876             }
1877         }
1878         quantum_info=DestroyQuantumInfo(quantum_info);
1879         break;
1880       }
1881       case '5':
1882       {
1883         QuantumAny
1884           range;
1885
1886         /*
1887           Convert image to a PGM image.
1888         */
1889         if (image->depth > 8)
1890           image->depth=16;
1891         (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(unsigned long)
1892           GetQuantumRange(image->depth));
1893         (void) WriteBlobString(image,buffer);
1894         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1895         if (quantum_info == (QuantumInfo *) NULL)
1896           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1897         quantum_info->min_is_white=MagickTrue;
1898         pixels=GetQuantumPixels(quantum_info);
1899         extent=GetQuantumExtent(image,quantum_info,GrayQuantum);
1900         range=GetQuantumRange(image->depth);
1901         for (y=0; y < (long) image->rows; y++)
1902         {
1903           register const PixelPacket
1904             *restrict p;
1905
1906           register long
1907             x;
1908
1909           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1910           if (p == (const PixelPacket *) NULL)
1911             break;
1912           q=pixels;
1913           if ((image->depth == 8) || (image->depth == 16))
1914             extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1915               quantum_info,GrayQuantum,pixels,&image->exception);
1916           else
1917             {
1918               if (image->depth <= 8)
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 == 8)
1926                         pixel=ScaleQuantumToChar(GetRedPixelComponent(p));
1927                       else
1928                         pixel=ScaleQuantumToAny(p->red,range);
1929                     }
1930                   q=PopCharPixel((unsigned char) pixel,q);
1931                   p++;
1932                 }
1933               else
1934                 for (x=0; x < (long) image->columns; x++)
1935                 {
1936                   if (IsGrayPixel(p) == MagickFalse)
1937                     pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
1938                   else
1939                     {
1940                       if (image->depth == 16)
1941                         pixel=ScaleQuantumToShort(GetRedPixelComponent(p));
1942                       else
1943                         pixel=ScaleQuantumToAny(p->red,range);
1944                     }
1945                   q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1946                   p++;
1947                 }
1948               extent=(size_t) (q-pixels);
1949             }
1950           count=WriteBlob(image,extent,pixels);
1951           if (count != (ssize_t) extent)
1952             break;
1953           if (image->previous == (Image *) NULL)
1954             {
1955               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1956               if (status == MagickFalse)
1957                 break;
1958             }
1959         }
1960         quantum_info=DestroyQuantumInfo(quantum_info);
1961         break;
1962       }
1963       case '6':
1964       {
1965         QuantumAny
1966           range;
1967
1968         /*
1969           Convert image to a PNM image.
1970         */
1971         if (image->depth > 8)
1972           image->depth=16;
1973         (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(unsigned long)
1974           GetQuantumRange(image->depth));
1975         (void) WriteBlobString(image,buffer);
1976         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1977         if (quantum_info == (QuantumInfo *) NULL)
1978           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1979         pixels=GetQuantumPixels(quantum_info);
1980         extent=GetQuantumExtent(image,quantum_info,quantum_type);
1981         range=GetQuantumRange(image->depth);
1982         for (y=0; y < (long) image->rows; y++)
1983         {
1984           register const PixelPacket
1985             *restrict p;
1986
1987           register long
1988             x;
1989
1990           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1991           if (p == (const PixelPacket *) NULL)
1992             break;
1993           q=pixels;
1994           if ((image->depth == 8) || (image->depth == 16))
1995             extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1996               quantum_info,quantum_type,pixels,&image->exception);
1997           else
1998             {
1999               if (image->depth <= 8)
2000                 for (x=0; x < (long) image->columns; x++)
2001                 {
2002                   pixel=ScaleQuantumToAny(p->red,range);
2003                   q=PopCharPixel((unsigned char) pixel,q);
2004                   pixel=ScaleQuantumToAny(p->green,range);
2005                   q=PopCharPixel((unsigned char) pixel,q);
2006                   pixel=ScaleQuantumToAny(p->blue,range);
2007                   q=PopCharPixel((unsigned char) pixel,q);
2008                   p++;
2009                 }
2010               else
2011                 for (x=0; x < (long) image->columns; x++)
2012                 {
2013                   pixel=ScaleQuantumToAny(p->red,range);
2014                   q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2015                   pixel=ScaleQuantumToAny(p->green,range);
2016                   q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2017                   pixel=ScaleQuantumToAny(p->blue,range);
2018                   q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2019                   p++;
2020                 }
2021               extent=(size_t) (q-pixels);
2022             }
2023           count=WriteBlob(image,extent,pixels);
2024           if (count != (ssize_t) extent)
2025             break;
2026           if (image->previous == (Image *) NULL)
2027             {
2028               status=SetImageProgress(image,SaveImageTag,y,image->rows);
2029               if (status == MagickFalse)
2030                 break;
2031             }
2032         }
2033         quantum_info=DestroyQuantumInfo(quantum_info);
2034         break;
2035       }
2036       case '7':
2037       {
2038         QuantumAny
2039           range;
2040
2041         /*
2042           Convert image to a PAM.
2043         */
2044         if (image->depth > 16)
2045           image->depth=16;
2046         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
2047         pixels=GetQuantumPixels(quantum_info);
2048         range=GetQuantumRange(image->depth);
2049         for (y=0; y < (long) image->rows; y++)
2050         {
2051           register const IndexPacket
2052             *restrict indexes;
2053
2054           register const PixelPacket
2055             *restrict p;
2056
2057           register long
2058             x;
2059
2060           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2061           if (p == (const PixelPacket *) NULL)
2062             break;
2063           indexes=GetVirtualIndexQueue(image);
2064           q=pixels;
2065           if ((image->depth == 8) || (image->depth == 16))
2066             extent=ExportQuantumPixels(image,(const CacheView *) NULL,
2067               quantum_info,quantum_type,pixels,&image->exception);
2068           else
2069             {
2070               switch (quantum_type)
2071               {
2072                 case GrayQuantum:
2073                 case GrayAlphaQuantum:
2074                 {
2075                   if (image->depth <= 8)
2076                     for (x=0; x < (long) image->columns; x++)
2077                     {
2078                       pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
2079                       q=PopCharPixel((unsigned char) pixel,q);
2080                       if (image->matte != MagickFalse)
2081                         {
2082                           pixel=(unsigned char) ScaleQuantumToAny(p->opacity,
2083                             range);
2084                           q=PopCharPixel((unsigned char) pixel,q);
2085                         }
2086                       p++;
2087                     }
2088                   else
2089                     for (x=0; x < (long) image->columns; x++)
2090                     {
2091                       pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
2092                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2093                       if (image->matte != MagickFalse)
2094                         {
2095                           pixel=(unsigned char) ScaleQuantumToAny(p->opacity,
2096                             range);
2097                           q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2098                         }
2099                       p++;
2100                     }
2101                   break;
2102                 }
2103                 case CMYKQuantum:
2104                 case CMYKAQuantum:
2105                 {
2106                   if (image->depth <= 8)
2107                     for (x=0; x < (long) image->columns; x++)
2108                     {
2109                       pixel=ScaleQuantumToAny(p->red,range);
2110                       q=PopCharPixel((unsigned char) pixel,q);
2111                       pixel=ScaleQuantumToAny(p->green,range);
2112                       q=PopCharPixel((unsigned char) pixel,q);
2113                       pixel=ScaleQuantumToAny(p->blue,range);
2114                       q=PopCharPixel((unsigned char) pixel,q);
2115                       pixel=ScaleQuantumToAny(indexes[x],range);
2116                       q=PopCharPixel((unsigned char) pixel,q);
2117                       if (image->matte != MagickFalse)
2118                         {
2119                           pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
2120                             GetOpacityPixelComponent(p)),range);
2121                           q=PopCharPixel((unsigned char) pixel,q);
2122                         }
2123                       p++;
2124                     }
2125                   else
2126                     for (x=0; x < (long) image->columns; x++)
2127                     {
2128                       pixel=ScaleQuantumToAny(p->red,range);
2129                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2130                       pixel=ScaleQuantumToAny(p->green,range);
2131                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2132                       pixel=ScaleQuantumToAny(p->blue,range);
2133                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2134                       pixel=ScaleQuantumToAny(indexes[x],range);
2135                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2136                       if (image->matte != MagickFalse)
2137                         {
2138                           pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
2139                             GetOpacityPixelComponent(p)),range);
2140                           q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2141                         }
2142                       p++;
2143                     }
2144                   break;
2145                 }
2146                 default:
2147                 {
2148                   if (image->depth <= 8)
2149                     for (x=0; x < (long) image->columns; x++)
2150                     {
2151                       pixel=ScaleQuantumToAny(p->red,range);
2152                       q=PopCharPixel((unsigned char) pixel,q);
2153                       pixel=ScaleQuantumToAny(p->green,range);
2154                       q=PopCharPixel((unsigned char) pixel,q);
2155                       pixel=ScaleQuantumToAny(p->blue,range);
2156                       q=PopCharPixel((unsigned char) pixel,q);
2157                       if (image->matte != MagickFalse)
2158                         {
2159                           pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
2160                             GetOpacityPixelComponent(p)),range);
2161                           q=PopCharPixel((unsigned char) pixel,q);
2162                         }
2163                       p++;
2164                     }
2165                   else
2166                     for (x=0; x < (long) image->columns; x++)
2167                     {
2168                       pixel=ScaleQuantumToAny(p->red,range);
2169                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2170                       pixel=ScaleQuantumToAny(p->green,range);
2171                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2172                       pixel=ScaleQuantumToAny(p->blue,range);
2173                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2174                       if (image->matte != MagickFalse)
2175                         {
2176                           pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
2177                             GetOpacityPixelComponent(p)),range);
2178                           q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2179                         }
2180                       p++;
2181                     }
2182                   break;
2183                 }
2184               }
2185               extent=(size_t) (q-pixels);
2186             }
2187           count=WriteBlob(image,extent,pixels);
2188           if (count != (ssize_t) extent)
2189             break;
2190           if (image->previous == (Image *) NULL)
2191             {
2192               status=SetImageProgress(image,SaveImageTag,y,image->rows);
2193               if (status == MagickFalse)
2194                 break;
2195             }
2196         }
2197         quantum_info=DestroyQuantumInfo(quantum_info);
2198         break;
2199       }
2200       case 'F':
2201       case 'f':
2202       {
2203         (void) WriteBlobString(image,image->endian != LSBEndian ? "1.0\n" :
2204           "-1.0\n");
2205         image->depth=32;
2206         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
2207         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
2208         if (quantum_info == (QuantumInfo *) NULL)
2209           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2210         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2211         if (status == MagickFalse)
2212           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2213         pixels=GetQuantumPixels(quantum_info);
2214         for (y=(long) image->rows-1; y >= 0; y--)
2215         {
2216           register const PixelPacket
2217             *restrict p;
2218
2219           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2220           if (p == (const PixelPacket *) NULL)
2221             break;
2222           extent=ExportQuantumPixels(image,(const CacheView *) NULL,
2223             quantum_info,quantum_type,pixels,&image->exception);
2224           (void) WriteBlob(image,extent,pixels);
2225           if (image->previous == (Image *) NULL)
2226             {
2227               status=SetImageProgress(image,SaveImageTag,y,image->rows);
2228               if (status == MagickFalse)
2229                 break;
2230             }
2231         }
2232         quantum_info=DestroyQuantumInfo(quantum_info);
2233         break;
2234       }
2235     }
2236     if (GetNextImageInList(image) == (Image *) NULL)
2237       break;
2238     image=SyncNextImageInList(image);
2239     status=SetImageProgress(image,SaveImagesTag,scene++,
2240       GetImageListLength(image));
2241     if (status == MagickFalse)
2242       break;
2243   } while (image_info->adjoin != MagickFalse);
2244   (void) CloseBlob(image);
2245   return(MagickTrue);
2246 }