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