]> granicus.if.org Git - imagemagick/blob - coders/pnm.c
4ce534ff3d20464901685c93c7dd35c42e6779a9
[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 > 200505)
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 > 200505)
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 > 200505)
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 > 200505)
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 > 200505)
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 > 200505)
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 > 200505)
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 > 200505)
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 > 200505)
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 > 200505)
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 %  Procedure WritePNMImage() writes an image to a file in the PNM rasterfile
1436 %  format.
1437 %
1438 %  The format of the WritePNMImage method is:
1439 %
1440 %      MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
1441 %
1442 %  A description of each parameter follows.
1443 %
1444 %    o image_info: the image info.
1445 %
1446 %    o image:  The image.
1447 %
1448 */
1449 static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
1450 {
1451   char
1452     buffer[MaxTextExtent],
1453     format,
1454     magick[MaxTextExtent];
1455
1456   const char
1457     *value;
1458
1459   IndexPacket
1460     index;
1461
1462   long
1463     y;
1464
1465   MagickBooleanType
1466     status;
1467
1468   MagickOffsetType
1469     scene;
1470
1471   QuantumAny
1472     pixel;
1473
1474   QuantumInfo
1475     *quantum_info;
1476
1477   QuantumType
1478     quantum_type;
1479
1480   register unsigned char
1481     *pixels,
1482     *q;
1483
1484   ssize_t
1485     count;
1486
1487   size_t
1488     extent,
1489     packet_size;
1490
1491   /*
1492     Open output image file.
1493   */
1494   assert(image_info != (const ImageInfo *) NULL);
1495   assert(image_info->signature == MagickSignature);
1496   assert(image != (Image *) NULL);
1497   assert(image->signature == MagickSignature);
1498   if (image->debug != MagickFalse)
1499     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1500   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1501   if (status == MagickFalse)
1502     return(status);
1503   scene=0;
1504   do
1505   {
1506     /*
1507       Write PNM file header.
1508     */
1509     packet_size=3;
1510     quantum_type=RGBQuantum;
1511     (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
1512     switch (magick[1])
1513     {
1514       case 'A':
1515       case 'a':
1516       {
1517         format='7';
1518         break;
1519       }
1520       case 'B':
1521       case 'b':
1522       {
1523         format='4';
1524         if (image_info->compression == NoCompression)
1525           format='1';
1526         break;
1527       }
1528       case 'F':
1529       case 'f':
1530       {
1531         format='F';
1532         if (IsGrayImage(image,&image->exception) != MagickFalse)
1533           format='f';
1534         break;
1535       }
1536       case 'G':
1537       case 'g':
1538       {
1539         format='5';
1540         if (image_info->compression == NoCompression)
1541           format='2';
1542         break;
1543       }
1544       case 'N':
1545       case 'n':
1546       {
1547         if ((image_info->type != TrueColorType) &&
1548             (IsGrayImage(image,&image->exception) != MagickFalse))
1549           {
1550             format='5';
1551             if (image_info->compression == NoCompression)
1552               format='2';
1553             if (IsMonochromeImage(image,&image->exception) != MagickFalse)
1554               {
1555                 format='4';
1556                 if (image_info->compression == NoCompression)
1557                   format='1';
1558               }
1559             break;
1560           }
1561       }
1562       default:
1563       {
1564         format='6';
1565         if (image_info->compression == NoCompression)
1566           format='3';
1567         break;
1568       }
1569     }
1570     (void) FormatMagickString(buffer,MaxTextExtent,"P%c\n",format);
1571     (void) WriteBlobString(image,buffer);
1572     value=GetImageProperty(image,"comment");
1573     if (value != (const char *) NULL)
1574       {
1575         register const char
1576           *p;
1577
1578         /*
1579           Write comments to file.
1580         */
1581         (void) WriteBlobByte(image,'#');
1582         for (p=value; *p != '\0'; p++)
1583         {
1584           (void) WriteBlobByte(image,(unsigned char) *p);
1585           if ((*p == '\r') && (*(p+1) != '\0'))
1586             (void) WriteBlobByte(image,'#');
1587           if ((*p == '\n') && (*(p+1) != '\0'))
1588             (void) WriteBlobByte(image,'#');
1589         }
1590         (void) WriteBlobByte(image,'\n');
1591       }
1592     if (format != '7')
1593       {
1594         if (image->colorspace != RGBColorspace)
1595           (void) TransformImageColorspace(image,RGBColorspace);
1596         (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n",
1597           image->columns,image->rows);
1598         (void) WriteBlobString(image,buffer);
1599       }
1600     else
1601       {
1602         char
1603           type[MaxTextExtent];
1604
1605         /*
1606           PAM header.
1607         */
1608         (void) FormatMagickString(buffer,MaxTextExtent,
1609           "WIDTH %lu\nHEIGHT %lu\n",image->columns,image->rows);
1610         (void) WriteBlobString(image,buffer);
1611         quantum_type=GetQuantumType(image,&image->exception);
1612         switch (quantum_type)
1613         {
1614           case CMYKQuantum:
1615           case CMYKAQuantum:
1616           {
1617             packet_size=4;
1618             (void) CopyMagickString(type,"CMYK",MaxTextExtent);
1619             break;
1620           }
1621           case GrayQuantum:
1622           case GrayAlphaQuantum:
1623           {
1624             packet_size=1;
1625             (void) CopyMagickString(type,"GRAYSCALE",MaxTextExtent);
1626             break;
1627           }
1628           default:
1629           {
1630             quantum_type=RGBQuantum;
1631             if (image->matte != MagickFalse)
1632               quantum_type=RGBAQuantum;
1633             packet_size=3;
1634             (void) CopyMagickString(type,"RGB",MaxTextExtent);
1635             break;
1636           }
1637         }
1638         if (image->matte != MagickFalse)
1639           {
1640             packet_size++;
1641             (void) ConcatenateMagickString(type,"_ALPHA",MaxTextExtent);
1642           }
1643         if (image->depth > 16)
1644           image->depth=16;
1645         (void) FormatMagickString(buffer,MaxTextExtent,
1646           "DEPTH %lu\nMAXVAL %lu\n",(unsigned long) packet_size,(unsigned long)
1647           GetQuantumRange(image->depth));
1648         (void) WriteBlobString(image,buffer);
1649         (void) FormatMagickString(buffer,MaxTextExtent,"TUPLTYPE %s\nENDHDR\n",
1650           type);
1651         (void) WriteBlobString(image,buffer);
1652       }
1653     /*
1654       Convert runextent encoded to PNM raster pixels.
1655     */
1656     switch (format)
1657     {
1658       case '1':
1659       {
1660         char
1661           *pixels;
1662
1663         /*
1664           Convert image to a PBM image.
1665         */
1666         pixels=AcquireString((const char *) NULL);
1667         for (y=0; y < (long) image->rows; y++)
1668         {
1669           register const IndexPacket
1670             *restrict indexes;
1671
1672           register const PixelPacket
1673             *restrict p;
1674
1675           register long
1676             x;
1677
1678           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1679           if (p == (const PixelPacket *) NULL)
1680             break;
1681           indexes=GetVirtualIndexQueue(image);
1682           *pixels='\0';
1683           for (x=0; x < (long) image->columns; x++)
1684           {
1685             pixel=PixelIntensityToQuantum(p);
1686             (void) ConcatenateString(&pixels,
1687               pixel >= (Quantum) (QuantumRange/2) ? "0 " : "1 ");
1688             p++;
1689           }
1690           (void) ConcatenateString(&pixels,"\n");
1691           (void) WriteBlob(image,strlen(pixels),(unsigned char *) pixels);
1692           if (image->previous == (Image *) NULL)
1693             {
1694               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1695               if (status == MagickFalse)
1696                 break;
1697             }
1698         }
1699         pixels=DestroyString(pixels);
1700         break;
1701       }
1702       case '2':
1703       {
1704         char
1705           *pixels;
1706
1707         /*
1708           Convert image to a PGM image.
1709         */
1710         if (image->depth <= 8)
1711           (void) WriteBlobString(image,"255\n");
1712         else
1713           (void) WriteBlobString(image,"65535\n");
1714         pixels=AcquireString((const char *) NULL);
1715         for (y=0; y < (long) image->rows; y++)
1716         {
1717           register const PixelPacket
1718             *restrict p;
1719
1720           register long
1721             x;
1722
1723           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1724           if (p == (const PixelPacket *) NULL)
1725             break;
1726           *pixels='\0';
1727           for (x=0; x < (long) image->columns; x++)
1728           {
1729             index=PixelIntensityToQuantum(p);
1730             if (image->depth <= 8)
1731               count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,"%u ",
1732                 ScaleQuantumToChar(index));
1733             else
1734               count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,"%u ",
1735                 ScaleQuantumToShort(index));
1736             (void) ConcatenateString(&pixels,buffer);
1737             p++;
1738           }
1739           (void) ConcatenateString(&pixels,"\n");
1740           (void) WriteBlob(image,strlen(pixels),(unsigned char *) pixels);
1741           if (image->previous == (Image *) NULL)
1742             {
1743               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1744               if (status == MagickFalse)
1745                 break;
1746             }
1747         }
1748         pixels=DestroyString(pixels);
1749         break;
1750       }
1751       case '3':
1752       {
1753         char
1754           *pixels;
1755
1756         /*
1757           Convert image to a PNM image.
1758         */
1759         if (image->depth <= 8)
1760           (void) WriteBlobString(image,"255\n");
1761         else
1762           (void) WriteBlobString(image,"65535\n");
1763         pixels=AcquireString((const char *) NULL);
1764         for (y=0; y < (long) image->rows; y++)
1765         {
1766           register const PixelPacket
1767             *restrict p;
1768
1769           register long
1770             x;
1771
1772           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1773           if (p == (const PixelPacket *) NULL)
1774             break;
1775           *pixels='\0';
1776           for (x=0; x < (long) image->columns; x++)
1777           {
1778             if (image->depth <= 8)
1779               count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,
1780                 "%u %u %u ",ScaleQuantumToChar(GetRedPixelComponent(p)),
1781                 ScaleQuantumToChar(GetGreenPixelComponent(p)),
1782                 ScaleQuantumToChar(GetBluePixelComponent(p)));
1783             else
1784               count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,
1785                 "%u %u %u ",ScaleQuantumToShort(GetRedPixelComponent(p)),
1786                 ScaleQuantumToShort(GetGreenPixelComponent(p)),
1787                 ScaleQuantumToShort(GetBluePixelComponent(p)));
1788             (void) ConcatenateString(&pixels,buffer);
1789             p++;
1790           }
1791           (void) ConcatenateString(&pixels,"\n");
1792           (void) WriteBlob(image,strlen(pixels),(unsigned char *) pixels);
1793           if (image->previous == (Image *) NULL)
1794             {
1795               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1796               if (status == MagickFalse)
1797                 break;
1798             }
1799         }
1800         pixels=DestroyString(pixels);
1801         break;
1802       }
1803       case '4':
1804       {
1805         /*
1806           Convert image to a PBM image.
1807         */
1808         image->depth=1;
1809         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1810         if (quantum_info == (QuantumInfo *) NULL)
1811           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1812         quantum_info->min_is_white=MagickTrue;
1813         pixels=GetQuantumPixels(quantum_info);
1814         for (y=0; y < (long) image->rows; y++)
1815         {
1816           register const PixelPacket
1817             *restrict p;
1818
1819           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1820           if (p == (const PixelPacket *) NULL)
1821             break;
1822           extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1823             quantum_info,GrayQuantum,pixels,&image->exception);
1824           count=WriteBlob(image,extent,pixels);
1825           if (count != (ssize_t) extent)
1826             break;
1827           if (image->previous == (Image *) NULL)
1828             {
1829               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1830               if (status == MagickFalse)
1831                 break;
1832             }
1833         }
1834         quantum_info=DestroyQuantumInfo(quantum_info);
1835         break;
1836       }
1837       case '5':
1838       {
1839         QuantumAny
1840           range;
1841
1842         /*
1843           Convert image to a PGM image.
1844         */
1845         if (image->depth > 8)
1846           image->depth=16;
1847         (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(unsigned long)
1848           GetQuantumRange(image->depth));
1849         (void) WriteBlobString(image,buffer);
1850         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1851         if (quantum_info == (QuantumInfo *) NULL)
1852           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1853         quantum_info->min_is_white=MagickTrue;
1854         pixels=GetQuantumPixels(quantum_info);
1855         extent=GetQuantumExtent(image,quantum_info,GrayQuantum);
1856         range=GetQuantumRange(image->depth);
1857         for (y=0; y < (long) image->rows; y++)
1858         {
1859           register const PixelPacket
1860             *restrict p;
1861
1862           register long
1863             x;
1864
1865           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1866           if (p == (const PixelPacket *) NULL)
1867             break;
1868           q=pixels;
1869           if ((image->depth == 8) || (image->depth == 16))
1870             extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1871               quantum_info,GrayQuantum,pixels,&image->exception);
1872           else
1873             {
1874               if (image->depth <= 8)
1875                 for (x=0; x < (long) image->columns; x++)
1876                 {
1877                   if (IsGrayPixel(p) == MagickFalse)
1878                     pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
1879                   else
1880                     {
1881                       if (image->depth == 8)
1882                         pixel=ScaleQuantumToChar(GetRedPixelComponent(p));
1883                       else
1884                         pixel=ScaleQuantumToAny(p->red,range);
1885                     }
1886                   q=PopCharPixel((unsigned char) pixel,q);
1887                   p++;
1888                 }
1889               else
1890                 for (x=0; x < (long) image->columns; x++)
1891                 {
1892                   if (IsGrayPixel(p) == MagickFalse)
1893                     pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
1894                   else
1895                     {
1896                       if (image->depth == 16)
1897                         pixel=ScaleQuantumToShort(GetRedPixelComponent(p));
1898                       else
1899                         pixel=ScaleQuantumToAny(p->red,range);
1900                     }
1901                   q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1902                   p++;
1903                 }
1904               extent=(size_t) (q-pixels);
1905             }
1906           count=WriteBlob(image,extent,pixels);
1907           if (count != (ssize_t) extent)
1908             break;
1909           if (image->previous == (Image *) NULL)
1910             {
1911               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1912               if (status == MagickFalse)
1913                 break;
1914             }
1915         }
1916         quantum_info=DestroyQuantumInfo(quantum_info);
1917         break;
1918       }
1919       case '6':
1920       {
1921         QuantumAny
1922           range;
1923
1924         /*
1925           Convert image to a PNM image.
1926         */
1927         if (image->depth > 8)
1928           image->depth=16;
1929         (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(unsigned long)
1930           GetQuantumRange(image->depth));
1931         (void) WriteBlobString(image,buffer);
1932         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1933         if (quantum_info == (QuantumInfo *) NULL)
1934           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1935         pixels=GetQuantumPixels(quantum_info);
1936         extent=GetQuantumExtent(image,quantum_info,quantum_type);
1937         range=GetQuantumRange(image->depth);
1938         for (y=0; y < (long) image->rows; y++)
1939         {
1940           register const PixelPacket
1941             *restrict p;
1942
1943           register long
1944             x;
1945
1946           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1947           if (p == (const PixelPacket *) NULL)
1948             break;
1949           q=pixels;
1950           if ((image->depth == 8) || (image->depth == 16))
1951             extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1952               quantum_info,quantum_type,pixels,&image->exception);
1953           else
1954             {
1955               if (image->depth <= 8)
1956                 for (x=0; x < (long) image->columns; x++)
1957                 {
1958                   pixel=ScaleQuantumToAny(p->red,range);
1959                   q=PopCharPixel((unsigned char) pixel,q);
1960                   pixel=ScaleQuantumToAny(p->green,range);
1961                   q=PopCharPixel((unsigned char) pixel,q);
1962                   pixel=ScaleQuantumToAny(p->blue,range);
1963                   q=PopCharPixel((unsigned char) pixel,q);
1964                   if (image->matte != MagickFalse)
1965                     {
1966                       pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
1967                         GetOpacityPixelComponent(p)),range);
1968                       q=PopCharPixel((unsigned char) pixel,q);
1969                     }
1970                   p++;
1971                 }
1972               else
1973                 for (x=0; x < (long) image->columns; x++)
1974                 {
1975                   pixel=ScaleQuantumToAny(p->red,range);
1976                   q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1977                   pixel=ScaleQuantumToAny(p->green,range);
1978                   q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1979                   pixel=ScaleQuantumToAny(p->blue,range);
1980                   q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1981                   if (image->matte != MagickFalse)
1982                     {
1983                       pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
1984                         GetOpacityPixelComponent(p)),range);
1985                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1986                     }
1987                   p++;
1988                 }
1989               extent=(size_t) (q-pixels);
1990             }
1991           count=WriteBlob(image,extent,pixels);
1992           if (count != (ssize_t) extent)
1993             break;
1994           if (image->previous == (Image *) NULL)
1995             {
1996               status=SetImageProgress(image,SaveImageTag,y,image->rows);
1997               if (status == MagickFalse)
1998                 break;
1999             }
2000         }
2001         quantum_info=DestroyQuantumInfo(quantum_info);
2002         break;
2003       }
2004       case '7':
2005       {
2006         QuantumAny
2007           range;
2008
2009         /*
2010           Convert image to a PAM.
2011         */
2012         if (image->depth > 16)
2013           image->depth=16;
2014         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
2015         pixels=GetQuantumPixels(quantum_info);
2016         range=GetQuantumRange(image->depth);
2017         for (y=0; y < (long) image->rows; y++)
2018         {
2019           register const IndexPacket
2020             *restrict indexes;
2021
2022           register const PixelPacket
2023             *restrict p;
2024
2025           register long
2026             x;
2027
2028           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2029           if (p == (const PixelPacket *) NULL)
2030             break;
2031           indexes=GetVirtualIndexQueue(image);
2032           q=pixels;
2033           if ((image->depth == 8) || (image->depth == 16))
2034             extent=ExportQuantumPixels(image,(const CacheView *) NULL,
2035               quantum_info,quantum_type,pixels,&image->exception);
2036           else
2037             {
2038               switch (quantum_type)
2039               {
2040                 case GrayQuantum:
2041                 case GrayAlphaQuantum:
2042                 {
2043                   if (image->depth <= 8)
2044                     for (x=0; x < (long) image->columns; x++)
2045                     {
2046                       pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
2047                       q=PopCharPixel((unsigned char) pixel,q);
2048                       if (image->matte != MagickFalse)
2049                         {
2050                           pixel=(unsigned char) ScaleQuantumToAny(p->opacity,
2051                             range);
2052                           q=PopCharPixel((unsigned char) pixel,q);
2053                         }
2054                       p++;
2055                     }
2056                   else
2057                     for (x=0; x < (long) image->columns; x++)
2058                     {
2059                       pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
2060                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2061                       if (image->matte != MagickFalse)
2062                         {
2063                           pixel=(unsigned char) ScaleQuantumToAny(p->opacity,
2064                             range);
2065                           q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2066                         }
2067                       p++;
2068                     }
2069                   break;
2070                 }
2071                 case CMYKQuantum:
2072                 case CMYKAQuantum:
2073                 {
2074                   if (image->depth <= 8)
2075                     for (x=0; x < (long) image->columns; x++)
2076                     {
2077                       pixel=ScaleQuantumToAny(p->red,range);
2078                       q=PopCharPixel((unsigned char) pixel,q);
2079                       pixel=ScaleQuantumToAny(p->green,range);
2080                       q=PopCharPixel((unsigned char) pixel,q);
2081                       pixel=ScaleQuantumToAny(p->blue,range);
2082                       q=PopCharPixel((unsigned char) pixel,q);
2083                       pixel=ScaleQuantumToAny(indexes[x],range);
2084                       q=PopCharPixel((unsigned char) pixel,q);
2085                       if (image->matte != MagickFalse)
2086                         {
2087                           pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
2088                             GetOpacityPixelComponent(p)),range);
2089                           q=PopCharPixel((unsigned char) pixel,q);
2090                         }
2091                       p++;
2092                     }
2093                   else
2094                     for (x=0; x < (long) image->columns; x++)
2095                     {
2096                       pixel=ScaleQuantumToAny(p->red,range);
2097                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2098                       pixel=ScaleQuantumToAny(p->green,range);
2099                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2100                       pixel=ScaleQuantumToAny(p->blue,range);
2101                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2102                       pixel=ScaleQuantumToAny(indexes[x],range);
2103                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2104                       if (image->matte != MagickFalse)
2105                         {
2106                           pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
2107                             GetOpacityPixelComponent(p)),range);
2108                           q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2109                         }
2110                       p++;
2111                     }
2112                   break;
2113                 }
2114                 default:
2115                 {
2116                   if (image->depth <= 8)
2117                     for (x=0; x < (long) image->columns; x++)
2118                     {
2119                       pixel=ScaleQuantumToAny(p->red,range);
2120                       q=PopCharPixel((unsigned char) pixel,q);
2121                       pixel=ScaleQuantumToAny(p->green,range);
2122                       q=PopCharPixel((unsigned char) pixel,q);
2123                       pixel=ScaleQuantumToAny(p->blue,range);
2124                       q=PopCharPixel((unsigned char) pixel,q);
2125                       if (image->matte != MagickFalse)
2126                         {
2127                           pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
2128                             GetOpacityPixelComponent(p)),range);
2129                           q=PopCharPixel((unsigned char) pixel,q);
2130                         }
2131                       p++;
2132                     }
2133                   else
2134                     for (x=0; x < (long) image->columns; x++)
2135                     {
2136                       pixel=ScaleQuantumToAny(p->red,range);
2137                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2138                       pixel=ScaleQuantumToAny(p->green,range);
2139                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2140                       pixel=ScaleQuantumToAny(p->blue,range);
2141                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2142                       if (image->matte != MagickFalse)
2143                         {
2144                           pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
2145                             GetOpacityPixelComponent(p)),range);
2146                           q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2147                         }
2148                       p++;
2149                     }
2150                   break;
2151                 }
2152               }
2153               extent=(size_t) (q-pixels);
2154             }
2155           count=WriteBlob(image,extent,pixels);
2156           if (count != (ssize_t) extent)
2157             break;
2158           if (image->previous == (Image *) NULL)
2159             {
2160               status=SetImageProgress(image,SaveImageTag,y,image->rows);
2161               if (status == MagickFalse)
2162                 break;
2163             }
2164         }
2165         quantum_info=DestroyQuantumInfo(quantum_info);
2166         break;
2167       }
2168       case 'F':
2169       case 'f':
2170       {
2171         (void) WriteBlobString(image,image->endian != LSBEndian ? "1.0\n" :
2172           "-1.0\n");
2173         image->depth=32;
2174         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
2175         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
2176         if (quantum_info == (QuantumInfo *) NULL)
2177           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2178         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2179         if (status == MagickFalse)
2180           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2181         pixels=GetQuantumPixels(quantum_info);
2182         for (y=(long) image->rows-1; y >= 0; y--)
2183         {
2184           register const PixelPacket
2185             *restrict p;
2186
2187           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2188           if (p == (const PixelPacket *) NULL)
2189             break;
2190           extent=ExportQuantumPixels(image,(const CacheView *) NULL,
2191             quantum_info,quantum_type,pixels,&image->exception);
2192           (void) WriteBlob(image,extent,pixels);
2193           if (image->previous == (Image *) NULL)
2194             {
2195               status=SetImageProgress(image,SaveImageTag,y,image->rows);
2196               if (status == MagickFalse)
2197                 break;
2198             }
2199         }
2200         quantum_info=DestroyQuantumInfo(quantum_info);
2201         break;
2202       }
2203     }
2204     if (GetNextImageInList(image) == (Image *) NULL)
2205       break;
2206     image=SyncNextImageInList(image);
2207     status=SetImageProgress(image,SaveImagesTag,scene++,
2208       GetImageListLength(image));
2209     if (status == MagickFalse)
2210       break;
2211   } while (image_info->adjoin != MagickFalse);
2212   (void) CloseBlob(image);
2213   return(MagickTrue);
2214 }