]> granicus.if.org Git - imagemagick/blobdiff - coders/pnm.c
(no commit message)
[imagemagick] / coders / pnm.c
index b5b555b5e7507fcfc99f5fcf8e93e72be041fe4c..edb28874ab1fdd7bac5595ab76213697b7a36f9a 100644 (file)
@@ -17,7 +17,7 @@
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -47,6 +47,7 @@
 #include "MagickCore/color.h"
 #include "MagickCore/color-private.h"
 #include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
 #include "MagickCore/exception.h"
 #include "MagickCore/exception-private.h"
 #include "MagickCore/image.h"
@@ -69,7 +70,7 @@
   Forward declarations.
 */
 static MagickBooleanType
-  WritePNMImage(const ImageInfo *,Image *);
+  WritePNMImage(const ImageInfo *,Image *,ExceptionInfo *);
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -136,18 +137,19 @@ static MagickBooleanType IsPNM(const unsigned char *magick,const size_t extent)
 */
 
 static inline ssize_t ConstrainPixel(Image *image,const ssize_t offset,
-  const size_t extent)
+  const size_t extent,ExceptionInfo *exception)
 {
   if ((offset < 0) || (offset > (ssize_t) extent))
     {
-      (void) ThrowMagickException(&image->exception,GetMagickModule(),
-        CorruptImageError,"InvalidPixel","`%s'",image->filename);
+      (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
+        "InvalidPixel","`%s'",image->filename);
       return(0);
     }
   return(offset);
 }
 
-static size_t PNMInteger(Image *image,const unsigned int base)
+static size_t PNMInteger(Image *image,const unsigned int base,
+  ExceptionInfo *exception)
 {
   char
     *comment;
@@ -193,8 +195,11 @@ static size_t PNMInteger(Image *image,const unsigned int base)
               p=comment+strlen(comment);
             }
           c=ReadBlobByte(image);
-          *p=(char) c;
-          *(p+1)='\0';
+          if (c != (int) '\n')
+            {
+              *p=(char) c;
+              *(p+1)='\0';
+            }
         }
         if (comment == (char *) NULL)
           return(0);
@@ -203,7 +208,7 @@ static size_t PNMInteger(Image *image,const unsigned int base)
   } while (isdigit(c) == MagickFalse);
   if (comment != (char *) NULL)
     {
-      (void) SetImageProperty(image,"comment",comment);
+      (void) SetImageProperty(image,"comment",comment,exception);
       comment=DestroyString(comment);
     }
   if (base == 2)
@@ -270,7 +275,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
       image_info->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  image=AcquireImage(image_info);
+  image=AcquireImage(image_info,exception);
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   if (status == MagickFalse)
     {
@@ -297,22 +302,22 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           PBM, PGM, PPM, and PNM.
         */
-        image->columns=PNMInteger(image,10);
-        image->rows=PNMInteger(image,10);
+        image->columns=PNMInteger(image,10,exception);
+        image->rows=PNMInteger(image,10,exception);
         if ((format == 'f') || (format == 'F'))
           {
             char
               scale[MaxTextExtent];
 
             (void) ReadBlobString(image,scale);
-            quantum_scale=InterpretLocaleValue(scale,(char **) NULL);
+            quantum_scale=StringToDouble(scale,(char **) NULL);
           }
         else
           {
             if ((format == '1') || (format == '4'))
               max_value=1;  /* bitmap */
             else
-              max_value=PNMInteger(image,10);
+              max_value=PNMInteger(image,10,exception);
           }
       }
     else
@@ -367,34 +372,42 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
           if (LocaleCompare(keyword,"TUPLTYPE") == 0)
             {
               if (LocaleCompare(value,"BLACKANDWHITE") == 0)
-                quantum_type=GrayQuantum;
+                {
+                  SetImageColorspace(image,GRAYColorspace,exception);
+                  quantum_type=GrayQuantum;
+                }
               if (LocaleCompare(value,"BLACKANDWHITE_ALPHA") == 0)
                 {
+                  SetImageColorspace(image,GRAYColorspace,exception);
+                  image->alpha_trait=BlendPixelTrait;
                   quantum_type=GrayAlphaQuantum;
-                  image->matte=MagickTrue;
                 }
               if (LocaleCompare(value,"GRAYSCALE") == 0)
-                quantum_type=GrayQuantum;
+                {
+                  quantum_type=GrayQuantum;
+                  SetImageColorspace(image,GRAYColorspace,exception);
+                }
               if (LocaleCompare(value,"GRAYSCALE_ALPHA") == 0)
                 {
+                  SetImageColorspace(image,GRAYColorspace,exception);
+                  image->alpha_trait=BlendPixelTrait;
                   quantum_type=GrayAlphaQuantum;
-                  image->matte=MagickTrue;
                 }
               if (LocaleCompare(value,"RGB_ALPHA") == 0)
                 {
+                  image->alpha_trait=BlendPixelTrait;
                   quantum_type=RGBAQuantum;
-                  image->matte=MagickTrue;
                 }
               if (LocaleCompare(value,"CMYK") == 0)
                 {
+                  SetImageColorspace(image,CMYKColorspace,exception);
                   quantum_type=CMYKQuantum;
-                  image->colorspace=CMYKColorspace;
                 }
               if (LocaleCompare(value,"CMYK_ALPHA") == 0)
                 {
+                  SetImageColorspace(image,CMYKColorspace,exception);
+                  image->alpha_trait=BlendPixelTrait;
                   quantum_type=CMYKAQuantum;
-                  image->colorspace=CMYKColorspace;
-                  image->matte=MagickTrue;
                 }
             }
           if (LocaleCompare(keyword,"width") == 0)
@@ -422,6 +435,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Convert PBM image to pixel packets.
         */
+        SetImageColorspace(image,GRAYColorspace,exception);
         for (y=0; y < (ssize_t) image->rows; y++)
         {
           register ssize_t
@@ -431,13 +445,12 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
             *restrict q;
 
           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
-          if (q == (const Quantum *) NULL)
+          if (q == (Quantum *) NULL)
             break;
           for (x=0; x < (ssize_t) image->columns; x++)
           {
-            SetPixelRed(image,PNMInteger(image,2) == 0 ? QuantumRange : 0,q);
-            SetPixelGreen(image,GetPixelRed(image,q),q);
-            SetPixelBlue(image,GetPixelRed(image,q),q);
+            SetPixelGray(image,PNMInteger(image,2,exception) == 0 ?
+              QuantumRange : 0,q);
             q+=GetPixelChannels(image);
           }
           if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -461,6 +474,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Convert PGM image to pixel packets.
         */
+        SetImageColorspace(image,GRAYColorspace,exception);
         scale=(Quantum *) NULL;
         if (max_value != (1U*QuantumRange))
           {
@@ -483,17 +497,15 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
             *restrict q;
 
           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
-          if (q == (const Quantum *) NULL)
+          if (q == (Quantum *) NULL)
             break;
           for (x=0; x < (ssize_t) image->columns; x++)
           {
-            intensity=PNMInteger(image,10);
-            SetPixelRed(image,intensity,q);
+            intensity=PNMInteger(image,10,exception);
+            SetPixelGray(image,intensity,q);
             if (scale != (Quantum *) NULL)
-              SetPixelRed(image,scale[ConstrainPixel(image,(ssize_t) intensity,
-                max_value)],q);
-            SetPixelGreen(image,GetPixelRed(image,q),q);
-            SetPixelBlue(image,GetPixelRed(image,q),q);
+              SetPixelGray(image,scale[ConstrainPixel(image,(ssize_t) intensity,
+                max_value,exception)],q);
             q+=GetPixelChannels(image);
           }
           if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -541,25 +553,25 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
             *restrict q;
 
           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
-          if (q == (const Quantum *) NULL)
+          if (q == (Quantum *) NULL)
             break;
           for (x=0; x < (ssize_t) image->columns; x++)
           {
-            pixel.red=(MagickRealType) PNMInteger(image,10);
-            pixel.green=(MagickRealType) PNMInteger(image,10);
-            pixel.blue=(MagickRealType) PNMInteger(image,10);
+            pixel.red=(double) PNMInteger(image,10,exception);
+            pixel.green=(double) PNMInteger(image,10,exception);
+            pixel.blue=(double) PNMInteger(image,10,exception);
             if (scale != (Quantum *) NULL)
               {
-                pixel.red=(MagickRealType) scale[ConstrainPixel(image,(ssize_t)
-                  pixel.red,max_value)];
-                pixel.green=(MagickRealType) scale[ConstrainPixel(image,
-                  (ssize_t) pixel.green,max_value)];
-                pixel.blue=(MagickRealType) scale[ConstrainPixel(image,(ssize_t)
-                  pixel.blue,max_value)];
+                pixel.red=(double) scale[ConstrainPixel(image,(ssize_t)
+                  pixel.red,max_value,exception)];
+                pixel.green=(double) scale[ConstrainPixel(image,
+                  (ssize_t) pixel.green,max_value,exception)];
+                pixel.blue=(double) scale[ConstrainPixel(image,(ssize_t)
+                  pixel.blue,max_value,exception)];
               }
-            SetPixelRed(image,pixel.red,q);
-            SetPixelGreen(image,pixel.green,q);
-            SetPixelBlue(image,pixel.blue,q);
+            SetPixelRed(image,ClampToQuantum(pixel.red),q);
+            SetPixelGreen(image,ClampToQuantum(pixel.green),q);
+            SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
             q+=GetPixelChannels(image);
           }
           if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -581,6 +593,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Convert PBM raw image to pixel packets.
         */
+        SetImageColorspace(image,GRAYColorspace,exception);
         quantum_type=GrayQuantum;
         if (image->storage_class == PseudoClass)
           quantum_type=IndexQuantum;
@@ -628,7 +641,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
           if (count != (ssize_t) extent)
             status=MagickFalse;
           q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
-          if (q == (const Quantum *) NULL)
+          if (q == (Quantum *) NULL)
             {
               status=MagickFalse;
               continue;
@@ -655,6 +668,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Convert PGM raw image to pixel packets.
         */
+        SetImageColorspace(image,GRAYColorspace,exception);
         range=GetQuantumRange(image->depth);
         quantum_type=GrayQuantum;
         extent=(image->depth <= 8 ? 1 : 2)*image->columns;
@@ -703,7 +717,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
           if (count != (ssize_t) extent)
             status=MagickFalse;
           q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
-          if (q == (const Quantum *) NULL)
+          if (q == (Quantum *) NULL)
             {
               status=MagickFalse;
               continue;
@@ -721,9 +735,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 for (x=0; x < (ssize_t) image->columns; x++)
                 {
                   p=PushCharPixel(p,&pixel);
-                  SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
-                  SetPixelGreen(image,GetPixelRed(image,q),q);
-                  SetPixelBlue(image,GetPixelRed(image,q),q);
+                  SetPixelGray(image,ScaleAnyToQuantum(pixel,range),q);
                   q+=GetPixelChannels(image);
                 }
               }
@@ -735,9 +747,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 for (x=0; x < (ssize_t) image->columns; x++)
                 {
                   p=PushShortPixel(MSBEndian,p,&pixel);
-                  SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
-                  SetPixelGreen(image,GetPixelRed(image,q),q);
-                  SetPixelBlue(image,GetPixelRed(image,q),q);
+                  SetPixelGray(image,ScaleAnyToQuantum(pixel,range),q);
                   q+=GetPixelChannels(image);
                 }
               }
@@ -753,22 +763,19 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
       }
       case '6':
       {
-        ImageType
-          type;
-
         QuantumAny
           range;
 
         /*
           Convert PNM raster image to pixel packets.
         */
-        type=BilevelType;
         quantum_type=RGBQuantum;
         extent=3*(image->depth <= 8 ? 1 : 2)*image->columns;
         range=GetQuantumRange(image->depth);
         quantum_info=AcquireQuantumInfo(image_info,image);
         if (quantum_info == (QuantumInfo *) NULL)
           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+        (void) SetQuantumEndian(image,quantum_info,MSBEndian);
         for (y=0; y < (ssize_t) image->rows; y++)
         {
           MagickBooleanType
@@ -811,7 +818,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
           if (count != (ssize_t) extent)
             status=MagickFalse;
           q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
-          if (q == (const Quantum *) NULL)
+          if (q == (Quantum *) NULL)
             {
               status=MagickFalse;
               continue;
@@ -879,23 +886,6 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                     q+=GetPixelChannels(image);
                   }
                 }
-          if ((type == BilevelType) || (type == GrayscaleType))
-            {
-              q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
-              for (x=0; x < (ssize_t) image->columns; x++)
-              {
-                if ((type == BilevelType) &&
-                    (IsPixelMonochrome(image,q) == MagickFalse))
-                  type=IsPixelGray(image,q) == MagickFalse ? UndefinedType :
-                    GrayscaleType;
-                if ((type == GrayscaleType) &&
-                    (IsPixelGray(image,q) == MagickFalse))
-                  type=UndefinedType;
-                if ((type != BilevelType) && (type != GrayscaleType))
-                  break;
-                q+=GetPixelChannels(image);
-              }
-            }
           sync=SyncAuthenticPixels(image,exception);
           if (sync == MagickFalse)
             status=MagickFalse;
@@ -903,8 +893,6 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         quantum_info=DestroyQuantumInfo(quantum_info);
         if (status == MagickFalse)
           ThrowReaderException(CorruptImageError,"UnableToReadImageData");
-        if (type != UndefinedType)
-          image->type=type;
         break;
       }
       case '7':
@@ -939,7 +927,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
             break;
           }
         }
-        if (image->matte != MagickFalse)
+        if (image->alpha_trait == BlendPixelTrait)
           channels++;
         extent=channels*(image->depth <= 8 ? 1 : 2)*image->columns;
         quantum_info=AcquireQuantumInfo(image_info,image);
@@ -987,7 +975,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
           if (count != (ssize_t) extent)
             status=MagickFalse;
           q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
-          if (q == (const Quantum *) NULL)
+          if (q == (Quantum *) NULL)
             {
               status=MagickFalse;
               continue;
@@ -1010,11 +998,9 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                     for (x=0; x < (ssize_t) image->columns; x++)
                     {
                       p=PushCharPixel(p,&pixel);
-                      SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
-                      SetPixelGreen(image,GetPixelRed(image,q),q);
-                      SetPixelBlue(image,GetPixelRed(image,q),q);
+                      SetPixelGray(image,ScaleAnyToQuantum(pixel,range),q);
                       SetPixelAlpha(image,OpaqueAlpha,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           p=PushCharPixel(p,&pixel);
                           SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
@@ -1030,11 +1016,9 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                     for (x=0; x < (ssize_t) image->columns; x++)
                     {
                       p=PushShortPixel(MSBEndian,p,&pixel);
-                      SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
-                      SetPixelGreen(image,GetPixelRed(image,q),q);
-                      SetPixelBlue(image,GetPixelRed(image,q),q);
+                      SetPixelGray(image,ScaleAnyToQuantum(pixel,range),q);
                       SetPixelAlpha(image,OpaqueAlpha,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           p=PushShortPixel(MSBEndian,p,&pixel);
                           SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
@@ -1063,7 +1047,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                       p=PushCharPixel(p,&pixel);
                       SetPixelBlack(image,ScaleAnyToQuantum(pixel,range),q);
                       SetPixelAlpha(image,OpaqueAlpha,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           p=PushCharPixel(p,&pixel);
                           SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
@@ -1087,7 +1071,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                       p=PushShortPixel(MSBEndian,p,&pixel);
                       SetPixelBlack(image,ScaleAnyToQuantum(pixel,range),q);
                       SetPixelAlpha(image,OpaqueAlpha,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           p=PushShortPixel(MSBEndian,p,&pixel);
                           SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
@@ -1113,7 +1097,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                       p=PushCharPixel(p,&pixel);
                       SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
                       SetPixelAlpha(image,OpaqueAlpha,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           p=PushCharPixel(p,&pixel);
                           SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
@@ -1135,7 +1119,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
                       p=PushShortPixel(MSBEndian,p,&pixel);
                       SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
                       SetPixelAlpha(image,OpaqueAlpha,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           p=PushShortPixel(MSBEndian,p,&pixel);
                           SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
@@ -1162,6 +1146,8 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Convert PFM raster image to pixel packets.
         */
+        if (format == 'f')
+          SetImageColorspace(image,GRAYColorspace,exception);
         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
         image->endian=quantum_scale < 0.0 ? LSBEndian : MSBEndian;
         image->depth=32;
@@ -1174,8 +1160,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
         if (status == MagickFalse)
           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-        SetQuantumScale(quantum_info,(MagickRealType) QuantumRange*
-          fabs(quantum_scale));
+        SetQuantumScale(quantum_info,(double) QuantumRange*fabs(quantum_scale));
         extent=GetQuantumExtent(image,quantum_info,quantum_type);
         for (y=0; y < (ssize_t) image->rows; y++)
         {
@@ -1217,7 +1202,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
             status=MagickFalse;
           q=QueueAuthenticPixels(image,0,(ssize_t) (image->rows-offset-1),
             image->columns,1,exception);
-          if (q == (const Quantum *) NULL)
+          if (q == (Quantum *) NULL)
             {
               status=MagickFalse;
               continue;
@@ -1240,8 +1225,11 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
     }
     if (EOFBlob(image) != MagickFalse)
-      (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
-        "UnexpectedEndOfFile","`%s'",image->filename);
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          CorruptImageError,"UnexpectedEndOfFile","`%s'",image->filename);
+        break;
+      }
     /*
       Proceed to next image.
     */
@@ -1266,7 +1254,7 @@ static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Allocate next image structure.
         */
-        AcquireNextImage(image_info,image);
+        AcquireNextImage(image_info,image,exception);
         if (GetNextImageInList(image) == (Image *) NULL)
           {
             image=DestroyImageList(image);
@@ -1395,7 +1383,8 @@ ModuleExport void UnregisterPNMImage(void)
 %
 %  The format of the WritePNMImage method is:
 %
-%      MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
+%      MagickBooleanType WritePNMImage(const ImageInfo *image_info,
+%        Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows.
 %
@@ -1403,8 +1392,11 @@ ModuleExport void UnregisterPNMImage(void)
 %
 %    o image:  The image.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
+static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image,
+  ExceptionInfo *exception)
 {
   char
     buffer[MaxTextExtent],
@@ -1453,7 +1445,9 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   if (status == MagickFalse)
     return(status);
   scene=0;
@@ -1485,7 +1479,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
       case 'f':
       {
         format='F';
-        if (IsImageGray(image,&image->exception) != MagickFalse)
+        if (IsImageGray(image,exception) != MagickFalse)
           format='f';
         break;
       }
@@ -1501,12 +1495,12 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
       case 'n':
       {
         if ((image_info->type != TrueColorType) &&
-            (IsImageGray(image,&image->exception) != MagickFalse))
+            (IsImageGray(image,exception) != MagickFalse))
           {
             format='5';
             if (image_info->compression == NoCompression)
               format='2';
-            if (IsImageMonochrome(image,&image->exception) != MagickFalse)
+            if (IsImageMonochrome(image,exception) != MagickFalse)
               {
                 format='4';
                 if (image_info->compression == NoCompression)
@@ -1525,7 +1519,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
     }
     (void) FormatLocaleString(buffer,MaxTextExtent,"P%c\n",format);
     (void) WriteBlobString(image,buffer);
-    value=GetImageProperty(image,"comment");
+    value=GetImageProperty(image,"comment",exception);
     if (value != (const char *) NULL)
       {
         register const char
@@ -1547,8 +1541,6 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
       }
     if (format != '7')
       {
-        if (image->colorspace != RGBColorspace)
-          (void) TransformImageColorspace(image,RGBColorspace);
         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n",
           (double) image->columns,(double) image->rows);
         (void) WriteBlobString(image,buffer);
@@ -1565,7 +1557,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           "WIDTH %.20g\nHEIGHT %.20g\n",(double) image->columns,(double)
           image->rows);
         (void) WriteBlobString(image,buffer);
-        quantum_type=GetQuantumType(image,&image->exception);
+        quantum_type=GetQuantumType(image,exception);
         switch (quantum_type)
         {
           case CMYKQuantum:
@@ -1585,14 +1577,14 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           default:
           {
             quantum_type=RGBQuantum;
-            if (image->matte != MagickFalse)
+            if (image->alpha_trait == BlendPixelTrait)
               quantum_type=RGBAQuantum;
             packet_size=3;
             (void) CopyMagickString(type,"RGB",MaxTextExtent);
             break;
           }
         }
-        if (image->matte != MagickFalse)
+        if (image->alpha_trait == BlendPixelTrait)
           {
             packet_size++;
             (void) ConcatenateMagickString(type,"_ALPHA",MaxTextExtent);
@@ -1620,6 +1612,8 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
         /*
           Convert image to a PBM image.
         */
+        if (IsImageGray(image,exception) == MagickFalse)
+          (void) TransformImageColorspace(image,GRAYColorspace,exception);
         q=pixels;
         for (y=0; y < (ssize_t) image->rows; y++)
         {
@@ -1629,7 +1623,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           register ssize_t
             x;
 
-          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
           if (p == (const Quantum *) NULL)
             break;
           for (x=0; x < (ssize_t) image->columns; x++)
@@ -1669,6 +1663,8 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
         /*
           Convert image to a PGM image.
         */
+        if (IsImageGray(image,exception) == MagickFalse)
+          (void) TransformImageColorspace(image,GRAYColorspace,exception);
         if (image->depth <= 8)
           (void) WriteBlobString(image,"255\n");
         else
@@ -1682,7 +1678,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           register ssize_t
             x;
 
-          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
           if (p == (const Quantum *) NULL)
             break;
           for (x=0; x < (ssize_t) image->columns; x++)
@@ -1728,6 +1724,8 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
         /*
           Convert image to a PNM image.
         */
+        if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+          (void) TransformImageColorspace(image,sRGBColorspace,exception);
         if (image->depth <= 8)
           (void) WriteBlobString(image,"255\n");
         else
@@ -1741,7 +1739,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           register ssize_t
             x;
 
-          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
           if (p == (const Quantum *) NULL)
             break;
           for (x=0; x < (ssize_t) image->columns; x++)
@@ -1787,6 +1785,8 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
         /*
           Convert image to a PBM image.
         */
+        if (IsImageGray(image,exception) == MagickFalse)
+          (void) TransformImageColorspace(image,GRAYColorspace,exception);
         image->depth=1;
         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
         if (quantum_info == (QuantumInfo *) NULL)
@@ -1798,11 +1798,11 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           register const Quantum
             *restrict p;
 
-          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
           if (p == (const Quantum *) NULL)
             break;
           extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-            GrayQuantum,pixels,&image->exception);
+            GrayQuantum,pixels,exception);
           count=WriteBlob(image,extent,pixels);
           if (count != (ssize_t) extent)
             break;
@@ -1825,6 +1825,8 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
         /*
           Convert image to a PGM image.
         */
+        if (IsImageGray(image,exception) == MagickFalse)
+          (void) TransformImageColorspace(image,GRAYColorspace,exception);
         if (image->depth > 8)
           image->depth=16;
         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
@@ -1845,13 +1847,13 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           register ssize_t
             x;
 
-          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
           if (p == (const Quantum *) NULL)
             break;
           q=pixels;
           if ((image->depth == 8) || (image->depth == 16))
             extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-              GrayQuantum,pixels,&image->exception);
+              GrayQuantum,pixels,exception);
           else
             {
               if (image->depth <= 8)
@@ -1908,6 +1910,8 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
         /*
           Convert image to a PNM image.
         */
+        if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+          (void) TransformImageColorspace(image,sRGBColorspace,exception);
         if (image->depth > 8)
           image->depth=16;
         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
@@ -1916,6 +1920,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
         if (quantum_info == (QuantumInfo *) NULL)
           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+        (void) SetQuantumEndian(image,quantum_info,MSBEndian);
         pixels=GetQuantumPixels(quantum_info);
         extent=GetQuantumExtent(image,quantum_info,quantum_type);
         range=GetQuantumRange(image->depth);
@@ -1927,13 +1932,13 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           register ssize_t
             x;
 
-          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
           if (p == (const Quantum *) NULL)
             break;
           q=pixels;
           if ((image->depth == 8) || (image->depth == 16))
             extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-              quantum_type,pixels,&image->exception);
+              quantum_type,pixels,exception);
           else
             {
               if (image->depth <= 8)
@@ -1995,13 +2000,13 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           register ssize_t
             x;
 
-          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
           if (p == (const Quantum *) NULL)
             break;
           q=pixels;
           if ((image->depth == 8) || (image->depth == 16))
             extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-              quantum_type,pixels,&image->exception);
+              quantum_type,pixels,exception);
           else
             {
               switch (quantum_type)
@@ -2014,7 +2019,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
                     {
                       pixel=ScaleQuantumToAny(GetPixelIntensity(image,p),range);
                       q=PopCharPixel((unsigned char) pixel,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           pixel=(unsigned char) ScaleQuantumToAny(
                             GetPixelAlpha(image,p),range);
@@ -2027,7 +2032,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
                     {
                       pixel=ScaleQuantumToAny(GetPixelIntensity(image,p),range);
                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           pixel=(unsigned char) ScaleQuantumToAny(
                             GetPixelAlpha(image,p),range);
@@ -2051,7 +2056,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
                       q=PopCharPixel((unsigned char) pixel,q);
                       pixel=ScaleQuantumToAny(GetPixelBlack(image,p),range);
                       q=PopCharPixel((unsigned char) pixel,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),range);
                           q=PopCharPixel((unsigned char) pixel,q);
@@ -2069,7 +2074,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
                       pixel=ScaleQuantumToAny(GetPixelBlack(image,p),range);
                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),range);
                           q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
@@ -2089,7 +2094,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
                       q=PopCharPixel((unsigned char) pixel,q);
                       pixel=ScaleQuantumToAny(GetPixelBlue(image,p),range);
                       q=PopCharPixel((unsigned char) pixel,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),range);
                           q=PopCharPixel((unsigned char) pixel,q);
@@ -2105,7 +2110,7 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
                       pixel=ScaleQuantumToAny(GetPixelBlue(image,p),range);
                       q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
-                      if (image->matte != MagickFalse)
+                      if (image->alpha_trait == BlendPixelTrait)
                         {
                           pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),range);
                           q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
@@ -2134,8 +2139,8 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
       case 'F':
       case 'f':
       {
-        (void) WriteBlobString(image,image->endian != LSBEndian ? "1.0\n" :
-          "-1.0\n");
+        (void) WriteBlobString(image,image->endian == LSBEndian ? "-1.0\n" :
+          "1.0\n");
         image->depth=32;
         quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
         quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
@@ -2150,11 +2155,11 @@ static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
           register const Quantum
             *restrict p;
 
-          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
           if (p == (const Quantum *) NULL)
             break;
           extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-            quantum_type,pixels,&image->exception);
+            quantum_type,pixels,exception);
           (void) WriteBlob(image,extent,pixels);
           if (image->previous == (Image *) NULL)
             {