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