]> granicus.if.org Git - imagemagick/blobdiff - coders/png.c
(no commit message)
[imagemagick] / coders / png.c
index 1ec018682d46d0dd647d54b246ae0b3d7f466e56..26380352b1beb92b6d2849f26c07ed52e5aa4e81 100644 (file)
@@ -93,6 +93,9 @@
 /* #define PNG_ALLOCATED    The result of the function is new memory */
 /* #define PNG_DEPSTRUCT    Access to this struct member is deprecated */
 
+/* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */
+#define PNG_PTR_NORETURN
+
 #include "png.h"
 #include "zlib.h"
 \f
 #undef MNG_BASI_SUPPORTED
 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
 #define MNG_INSERT_LAYERS   /* Troublesome, but seem to work as of 5.4.4 */
-#define PNG_BUILD_PALETTE   /* This works as of 6.6.6 */
 #if defined(MAGICKCORE_JPEG_DELEGATE)
 #  define JNG_SUPPORTED /* Not finished as of 5.5.2.  See "To do" comments. */
 #endif
 #if !defined(RGBColorMatchExact)
 #define IsPNGColorEqual(color,target) \
-   (((color).red == (target).red) && \
-    ((color).green == (target).green) && \
-    ((color).blue == (target).blue))
+       (((color).red == (target).red) && \
+        ((color).green == (target).green) && \
+        ((color).blue == (target).blue))
 #endif
 
+/* Convenience macros for copying RGB or RGB+opacity components
+ * between a pixel and a PixelPacket.
+ */
+
+#define GetRGBOPixelComponents(pixel, packet) \
+        (packet).red = GetRedPixelComponent((pixel)); \
+        (packet).green = GetGreenPixelComponent((pixel)); \
+        (packet).red = GetBluePixelComponent((pixel)); \
+        (packet).opacity = GetOpacityPixelComponent((pixel)); \
+
+#define SetRGBOPixelComponents(pixel, packet) \
+        SetRedPixelComponent((pixel),(packet).red); \
+        SetGreenPixelComponent((pixel),(packet).green); \
+        SetBluePixelComponent((pixel),(packet).blue); \
+        SetOpacityPixelComponent((pixel),(packet).opacity); \
+
+
+#define GetRGBPixelComponents(pixel, packet) \
+        (packet).red = GetRedPixelComponent((pixel)); \
+        (packet).green = GetGreenPixelComponent((pixel)); \
+        (packet).red = GetBluePixelComponent((pixel));
+
+#define SetRGBPixelComponents(pixel, packet) \
+        SetRedPixelComponent((pixel),(packet).red); \
+        SetGreenPixelComponent((pixel),(packet).green); \
+        SetBluePixelComponent((pixel),(packet).blue);
+
 /*
   Establish thread safety.
   setjmp/longjmp is claimed to be safe on these platforms:
 
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
 static SemaphoreInfo
-  *png_semaphore = (SemaphoreInfo *) NULL;
+  *ping_semaphore = (SemaphoreInfo *) NULL;
 #endif
 
 /*
@@ -241,16 +270,6 @@ static png_byte FARDATA mng_tIME[5]={116,  73,  77,  69, (png_byte) '\0'};
 static png_byte FARDATA mng_zTXt[5]={122,  84,  88, 116, (png_byte) '\0'};
 */
 
-typedef struct _UShortPixelPacket
-{
-  unsigned short
-    red,
-    green,
-    blue,
-    opacity,
-    index;
-} UShortPixelPacket;
-
 typedef struct _MngBox
 {
   long
@@ -466,6 +485,7 @@ typedef struct _MngInfo
   MagickBooleanType
     ping_exclude_bKGD,
     ping_exclude_cHRM,
+    ping_exclude_date,
     ping_exclude_EXIF,
     ping_exclude_gAMA,
     ping_exclude_iCCP,
@@ -477,7 +497,8 @@ typedef struct _MngInfo
     ping_exclude_tRNS,
     ping_exclude_vpAg,
     ping_exclude_zCCP, /* hex-encoded iCCP */
-    ping_exclude_zTXt;
+    ping_exclude_zTXt,
+    ping_preserve_colormap;
 
 } MngInfo;
 #endif /* VER */
@@ -498,34 +519,39 @@ static MagickBooleanType
 
 #if PNG_LIBPNG_VER > 10011
 
+
 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
 static MagickBooleanType
-  LosslessReduceDepthOK(Image *image)
+LosslessReduceDepthOK(Image *image)
 {
+    /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
+     *
+     * This is true if the high byte and the next highest byte of
+     * each sample of the image, the colormap, and the background color
+     * are equal to each other.  We check this by seeing if the samples
+     * are unchanged when we scale them down to 8 and back up to Quantum.
+     *
+     * We don't use the method GetImageDepth() because it doesn't check
+     * background and doesn't handle PseudoClass specially.
+     */
+
+#define QuantumToCharToQuantumEqQuantum(quantum) \
+  ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
+
     MagickBooleanType
       ok_to_reduce=MagickFalse;
 
-    /* Reduce bit depth if it can be reduced losslessly from 16 to 8.
-     * Note that the method GetImageDepth doesn't check background
-     * and doesn't handle PseudoClass specially.  Also it uses
-     * multiplication and division by 257 instead of shifting, so
-     * might be slower.
-     */
-
-    if (image->depth == 16)
+    if (image->depth >= 16)
       {
 
         const PixelPacket
           *p;
 
         ok_to_reduce=
-          (((((size_t) image->background_color.red >> 8) & 0xff)
-          == ((size_t) image->background_color.red & 0xff)) &&
-           ((((size_t) image->background_color.green >> 8) & 0xff)
-          == ((size_t) image->background_color.green & 0xff)) &&
-           ((((size_t) image->background_color.blue >> 8) & 0xff)
-          == ((size_t) image->background_color.blue & 0xff))) ? MagickTrue :
-          MagickFalse;
+           QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
+           QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
+           QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
+           MagickTrue : MagickFalse;
 
         if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
           {
@@ -533,18 +559,17 @@ static MagickBooleanType
 
             for (indx=0; indx < (ssize_t) image->colors; indx++)
               {
-                ok_to_reduce=(((((size_t) image->colormap[indx].red >>
-                    8) & 0xff)
-                  == ((size_t) image->colormap[indx].red & 0xff)) &&
-                  ((((size_t) image->colormap[indx].green >> 8) & 0xff)
-                  == ((size_t) image->colormap[indx].green & 0xff)) &&
-                  ((((size_t) image->colormap[indx].blue >> 8) & 0xff)
-                  == ((size_t) image->colormap[indx].blue & 0xff)) &&
-                  ((((size_t) image->colormap[indx].opacity >> 8) & 0xff)
-                  == ((size_t) image->colormap[indx].opacity & 0xff))) ?
-                  MagickTrue : MagickFalse;
+                ok_to_reduce=(
+                   QuantumToCharToQuantumEqQuantum(
+                   image->colormap[indx].red) &&
+                   QuantumToCharToQuantumEqQuantum(
+                   image->colormap[indx].green) &&
+                   QuantumToCharToQuantumEqQuantum(
+                   image->colormap[indx].blue)) ?
+                   MagickTrue : MagickFalse;
+
                 if (ok_to_reduce == MagickFalse)
-                  break;
+                   break;
               }
           }
 
@@ -569,16 +594,11 @@ static MagickBooleanType
 
               for (x=(ssize_t) image->columns-1; x >= 0; x--)
               {
-                ok_to_reduce=((
-                  (((size_t) p->red >> 8) & 0xff) ==
-                  ((size_t) p->red & 0xff)) &&
-                  ((((size_t) p->green >> 8) & 0xff) ==
-                  ((size_t) p->green & 0xff)) &&
-                  ((((size_t) p->blue >> 8) & 0xff) ==
-                  ((size_t) p->blue & 0xff)) &&
-                  (((!image->matte ||
-                  (((size_t) p->opacity >> 8) & 0xff) ==
-                  ((size_t) p->opacity & 0xff))))) ? MagickTrue : MagickFalse;
+                ok_to_reduce=
+                   QuantumToCharToQuantumEqQuantum(GetRedPixelComponent(p)) &&
+                   QuantumToCharToQuantumEqQuantum(GetGreenPixelComponent(p)) &&
+                   QuantumToCharToQuantumEqQuantum(GetBluePixelComponent(p)) ?
+                   MagickTrue : MagickFalse;
 
                 if (ok_to_reduce == MagickFalse)
                   break;
@@ -593,7 +613,12 @@ static MagickBooleanType
         if (ok_to_reduce != MagickFalse)
           {
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "  OK to reduce PNG bit depth to 8 without loss of info");
+                "    OK to reduce PNG bit depth to 8 without loss of info");
+          }
+        else
+          {
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                "    Not OK to reduce PNG bit depth to 8 without loss of info");
           }
       }
 
@@ -602,7 +627,7 @@ static MagickBooleanType
 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
 
 static int
-PNG_RenderingIntent_from_Magick_RenderingIntent(const RenderingIntent intent)
+Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
 {
   switch (intent)
   {
@@ -624,9 +649,9 @@ PNG_RenderingIntent_from_Magick_RenderingIntent(const RenderingIntent intent)
 }
 
 static RenderingIntent
-PNG_RenderingIntent_to_Magick_RenderingIntent(const int png_intent)
+Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
 {
-  switch (png_intent)
+  switch (ping_intent)
   {
     case 0:
       return PerceptualIntent;
@@ -713,70 +738,6 @@ static MagickBooleanType ImageIsGray(Image *image)
   }
   return(MagickTrue);
 }
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%   I m a g e I s M o n o c h r o m e                                         %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%   Like IsMonochromeImage except does not change DirectClass to PseudoClass  %
-%   and is more accurate.                                                     %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-*/
-static MagickBooleanType ImageIsMonochrome(Image *image)
-{
-  register const PixelPacket
-    *p;
-
-  register ssize_t
-    i,
-    x,
-    y;
-
-  assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if (image->storage_class == PseudoClass)
-    {
-      for (i=0; i < (ssize_t) image->colors; i++)
-      {
-        if ((IsGray(image->colormap+i) == MagickFalse) ||
-            ((image->colormap[i].red != 0) &&
-             (image->colormap[i].red != (Quantum) QuantumRange)))
-          return(MagickFalse);
-      }
-      return(MagickTrue);
-    }
-  for (y=0; y < (ssize_t) image->rows; y++)
-  {
-    p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
-    if (p == (const PixelPacket *) NULL)
-      return(MagickFalse);
-    for (x=(ssize_t) image->columns-1; x >= 0; x--)
-    {
-      if ((p->red != 0) && (p->red != (Quantum) QuantumRange))
-        return(MagickFalse);
-
-      if (IsGray(p) == MagickFalse)
-        return(MagickFalse);
-
-      if ((p->opacity != OpaqueOpacity) &&
-          (p->opacity != (Quantum) TransparentOpacity))
-        return(MagickFalse);
-
-      p++;
-    }
-  }
-  return(MagickTrue);
-}
 #endif /* PNG_LIBPNG_VER > 10011 */
 #endif /* MAGICKCORE_PNG_DELEGATE */
 \f
@@ -1334,7 +1295,7 @@ static long mng_get_long(unsigned char *p)
   return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
 }
 
-static void PNGErrorHandler(png_struct *ping,png_const_charp message)
+static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
 {
   Image
     *image;
@@ -1349,13 +1310,16 @@ static void PNGErrorHandler(png_struct *ping,png_const_charp message)
     message,"`%s'",image->filename);
 
 #if (PNG_LIBPNG_VER < 10500)
+  /* A warning about deprecated use of jmpbuf here is unavoidable if you
+   * are building with libpng-1.4.x and can be ignored.
+   */
   longjmp(ping->jmpbuf,1);
 #else
   png_longjmp(ping,1);
 #endif
 }
 
-static void PNGWarningHandler(png_struct *ping,png_const_charp message)
+static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
 {
   Image
     *image;
@@ -1373,7 +1337,7 @@ static void PNGWarningHandler(png_struct *ping,png_const_charp message)
 }
 
 #ifdef PNG_USER_MEM_SUPPORTED
-static png_voidp png_IM_malloc(png_structp png_ptr,png_uint_32 size)
+static png_voidp Magick_png_malloc(png_structp png_ptr,png_uint_32 size)
 {
 #if (PNG_LIBPNG_VER < 10011)
   png_voidp
@@ -1395,7 +1359,7 @@ static png_voidp png_IM_malloc(png_structp png_ptr,png_uint_32 size)
 /*
   Free a pointer.  It is removed from the list at the same time.
 */
-static png_free_ptr png_IM_free(png_structp png_ptr,png_voidp ptr)
+static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
 {
   png_ptr=png_ptr;
   ptr=RelinquishMagickMemory(ptr);
@@ -1408,7 +1372,7 @@ static png_free_ptr png_IM_free(png_structp png_ptr,png_voidp ptr)
 #endif
 
 static int
-png_read_raw_profile(Image *image, const ImageInfo *image_info,
+Magick_png_read_raw_profile(Image *image, const ImageInfo *image_info,
    png_textp text,int ii)
 {
   register ssize_t
@@ -1446,6 +1410,9 @@ png_read_raw_profile(Image *image, const ImageInfo *image_info,
 
   length=(png_uint_32) StringToLong(sp);
 
+  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+       "      length: %lu",(unsigned long) length);
+
   while (*sp != ' ' && *sp != '\n')
      sp++;
 
@@ -1584,11 +1551,17 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 {
   /* Read one PNG image */
 
+  /* To do: Read the tIME chunk into the date:modify property */
+  /* To do: Read the tEXt/Creation Time chunk into the date:create property */
+
   Image
     *image;
 
   int
+    intent,
+    num_raw_profiles,
     num_text,
+    num_text_total,
     num_passes,
     pass,
     ping_bit_depth,
@@ -1596,15 +1569,19 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
     ping_interlace_method,
     ping_compression_method,
     ping_filter_method,
-    ping_num_trans;
+    ping_num_trans,
+    unit_type;
+
+  double
+    file_gamma;
+
+  LongPixelPacket
+    transparent_color;
 
   MagickBooleanType
     logging,
     status;
 
-  UShortPixelPacket
-    transparent_color;
-
   png_bytep
      ping_trans_alpha;
 
@@ -1625,13 +1602,15 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   png_uint_32
     ping_height,
     ping_width,
-    ping_rowbytes;
+    ping_rowbytes,
+    x_resolution,
+    y_resolution;
 
   QuantumInfo
     *quantum_info;
 
   unsigned char
-    *png_pixels;
+    *ping_pixels;
 
   ssize_t
     y;
@@ -1653,6 +1632,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
     length,
     row_offset;
 
+  ssize_t
+    j;
+
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   png_byte unused_chunks[]=
   {
@@ -1666,10 +1648,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 #endif
 
   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
-    "  enter ReadOnePNGImage()");
+    "  Enter ReadOnePNGImage()");
 
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-  LockSemaphoreInfo(png_semaphore);
+  LockSemaphoreInfo(ping_semaphore);
 #endif
 
 #if (PNG_LIBPNG_VER < 10200)
@@ -1693,16 +1675,30 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   quantum_info = (QuantumInfo *) NULL;
   image=mng_info->image;
 
+  if (logging != MagickFalse)
+    (void)LogMagickEvent(CoderEvent,GetMagickModule(),
+      "  image->matte=%d",(int) image->matte);
+
+  /* Set to an out-of-range color unless tRNS chunk is present */
+  transparent_color.red=65537;
+  transparent_color.green=65537;
+  transparent_color.blue=65537;
+  transparent_color.opacity=65537;
+
+  num_text = 0;
+  num_text_total = 0;
+  num_raw_profiles = 0;
+
   /*
     Allocate the PNG structures
   */
 #ifdef PNG_USER_MEM_SUPPORTED
  ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
-   PNGErrorHandler,PNGWarningHandler, NULL,
-   (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free);
+   MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
+   (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
 #else
   ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
-    PNGErrorHandler,PNGWarningHandler);
+    MagickPNGErrorHandler,MagickPNGWarningHandler);
 #endif
   if (ping == (png_struct *) NULL)
     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
@@ -1723,7 +1719,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
     }
 
-  png_pixels=(unsigned char *) NULL;
+  ping_pixels=(unsigned char *) NULL;
 
   if (setjmp(png_jmpbuf(ping)))
     {
@@ -1732,7 +1728,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       */
       png_destroy_read_struct(&ping,&ping_info,&end_info);
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-      UnlockSemaphoreInfo(png_semaphore);
+      UnlockSemaphoreInfo(ping_semaphore);
 #endif
       if (logging != MagickFalse)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -1887,17 +1883,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 #endif
 #if defined(PNG_READ_sRGB_SUPPORTED)
   {
-    int
-      intent;
-
     if (mng_info->have_global_srgb)
-      image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent(
-        mng_info->global_srgb_intent);
+      image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
+        (mng_info->global_srgb_intent);
 
     if (png_get_sRGB(ping,ping_info,&intent))
       {
-        image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent(
-          intent);
+        image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
+          (intent);
 
         if (logging != MagickFalse)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -1906,9 +1899,6 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   }
 #endif
   {
-     double
-        file_gamma;
-
      if (!png_get_gAMA(ping,ping_info,&file_gamma))
        if (mng_info->have_global_gama)
          png_set_gAMA(ping,ping_info,mng_info->global_gamma);
@@ -1957,8 +1947,8 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   if (image->rendering_intent != UndefinedIntent)
     {
       png_set_sRGB(ping,ping_info,
-         PNG_RenderingIntent_from_Magick_RenderingIntent(
-         image->rendering_intent));
+         Magick_RenderingIntent_to_PNG_RenderingIntent
+         (image->rendering_intent));
       png_set_gAMA(ping,ping_info,0.45455f);
       png_set_cHRM(ping,ping_info,
                   0.6400f, 0.3300f, 0.3000f, 0.6000f,
@@ -1967,8 +1957,8 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 #if defined(PNG_oFFs_SUPPORTED)
   if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
     {
-      image->page.x=png_get_x_offset_pixels(ping, ping_info);
-      image->page.y=png_get_y_offset_pixels(ping, ping_info);
+      image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
+      image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
 
       if (logging != MagickFalse)
         if (image->page.x || image->page.y)
@@ -1991,13 +1981,6 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
   if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
     {
-      int
-        unit_type;
-
-      png_uint_32
-        x_resolution,
-        y_resolution;
-
       /*
         Set image resolution.
       */
@@ -2019,6 +2002,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           (double) x_resolution,(double) y_resolution,unit_type);
     }
 #endif
+
   if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
     {
       int
@@ -2049,7 +2033,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                     png_set_tRNS(ping,ping_info,mng_info->global_trns,
                       (int) mng_info->global_trns_length,NULL);
                   }
-#if defined(PNG_READ_bKGD_SUPPORTED)
+#ifdef PNG_READ_bKGD_SUPPORTED
               if (
 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
                    mng_info->have_saved_bkgd_index ||
@@ -2075,6 +2059,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                       background.blue=(png_uint_16)
                         mng_info->global_plte[background.index].blue;
 
+                      background.gray=(png_uint_16)
+                        mng_info->global_plte[background.index].green;
+
                       png_set_bKGD(ping,ping_info,&background);
                     }
 #endif
@@ -2086,13 +2073,16 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
             }
         }
 
-#if defined(PNG_READ_bKGD_SUPPORTED)
+#ifdef PNG_READ_bKGD_SUPPORTED
   if (mng_info->have_global_bkgd &&
           (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
       image->background_color=mng_info->mng_global_bkgd;
 
   if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
     {
+      unsigned int
+        bkgd_scale;
+
       /*
         Set image background color.
       */
@@ -2100,79 +2090,66 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "    Reading PNG bKGD chunk.");
 
-      if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
-        {
-          image->background_color.red=ping_background->red;
-          image->background_color.green=ping_background->green;
-          image->background_color.blue=ping_background->blue;
-        }
-
-      else /* Scale background components to 16-bit */
-        {
-          unsigned int
-            bkgd_scale;
-
-          if (logging != MagickFalse)
-            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "    raw ping_background=(%d,%d,%d).",ping_background->red,
-              ping_background->green,ping_background->blue);
+      /* Scale background components to 16-bit, then scale
+       * to quantum depth
+       */
+        if (logging != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    raw ping_background=(%d,%d,%d).",ping_background->red,
+            ping_background->green,ping_background->blue);
 
-          bkgd_scale = 1;
+        bkgd_scale = 1;
 
-          if (ping_bit_depth == 1)
-             bkgd_scale = 255;
+        if (ping_bit_depth == 1)
+           bkgd_scale = 255;
 
-          else if (ping_bit_depth == 2)
-             bkgd_scale = 85;
+        else if (ping_bit_depth == 2)
+           bkgd_scale = 85;
 
-          else if (ping_bit_depth == 4)
-             bkgd_scale = 17;
+        else if (ping_bit_depth == 4)
+           bkgd_scale = 17;
 
-          if (ping_bit_depth <= 8)
-             bkgd_scale *= 257;
+        if (ping_bit_depth <= 8)
+           bkgd_scale *= 257;
 
-          ping_background->red *= bkgd_scale;
-          ping_background->green *= bkgd_scale;
-          ping_background->blue *= bkgd_scale;
+        ping_background->red *= bkgd_scale;
+        ping_background->green *= bkgd_scale;
+        ping_background->blue *= bkgd_scale;
 
-          if (logging != MagickFalse)
-            {
+        if (logging != MagickFalse)
+          {
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "    bkgd_scale=%d.",bkgd_scale);
 
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "    ping_background=(%d,%d,%d).",ping_background->red,
               ping_background->green,ping_background->blue);
-            }
+          }
 
-          image->background_color.red=
+        image->background_color.red=
             ScaleShortToQuantum(ping_background->red);
 
-          image->background_color.green=
+        image->background_color.green=
             ScaleShortToQuantum(ping_background->green);
 
-          image->background_color.blue=
-            ScaleShortToQuantum(ping_background->blue);
+        image->background_color.blue=
+          ScaleShortToQuantum(ping_background->blue);
 
-          image->background_color.opacity=OpaqueOpacity;
+        image->background_color.opacity=OpaqueOpacity;
 
-          if (logging != MagickFalse)
-            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "    image->background_color=(%.20g,%.20g,%.20g).",
-              (double) image->background_color.red,
-              (double) image->background_color.green,
-              (double) image->background_color.blue);
-        }
+        if (logging != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    image->background_color=(%.20g,%.20g,%.20g).",
+            (double) image->background_color.red,
+            (double) image->background_color.green,
+            (double) image->background_color.blue);
     }
-#endif
-  transparent_color.red=0;
-  transparent_color.green=0;
-  transparent_color.blue=0;
-  transparent_color.opacity=0;
+#endif /* PNG_READ_bKGD_SUPPORTED */
+
   if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
     {
       /*
-        Image has a transparent background.
+        Image has a tRNS chunk.
       */
       int
         max_sample;
@@ -2202,26 +2179,19 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         }
       else
         {
-          transparent_color.red= (unsigned short)(ping_trans_color->red);
-          transparent_color.green= (unsigned short) (ping_trans_color->green);
-          transparent_color.blue= (unsigned short) (ping_trans_color->blue);
-          transparent_color.opacity= (unsigned short) (ping_trans_color->gray);
+          int
+             scale_to_short;
+
+          scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
+
+          /* Scale transparent_color to short */
+          transparent_color.red= scale_to_short*ping_trans_color->red;
+          transparent_color.green= scale_to_short*ping_trans_color->green;
+          transparent_color.blue= scale_to_short*ping_trans_color->blue;
+          transparent_color.opacity= scale_to_short*ping_trans_color->gray;
 
           if (ping_color_type == PNG_COLOR_TYPE_GRAY)
             {
-#if (MAGICKCORE_QUANTUM_DEPTH == 8)
-              if (ping_bit_depth < MAGICKCORE_QUANTUM_DEPTH)
-#endif
-              transparent_color.opacity=(unsigned short) (
-                  ping_trans_color->gray *
-                  (65535L/((1UL << ping_bit_depth)-1)));
-
-#if (MAGICKCORE_QUANTUM_DEPTH == 8)
-              else
-                transparent_color.opacity=(unsigned short) (
-                    (ping_trans_color->gray * 65535L)/
-                   ((1UL << ping_bit_depth)-1));
-#endif
               if (logging != MagickFalse)
               {
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -2273,7 +2243,6 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   image->columns=ping_width;
   image->rows=ping_height;
   if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
-      ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
       ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
     {
       size_t
@@ -2324,12 +2293,19 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
           (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
 
-          for (i=0; i < (ssize_t) image->colors; i++)
+          for (i=0; i < (ssize_t) number_colors; i++)
           {
             image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
             image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
             image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
           }
+
+          for ( ; i < (ssize_t) image->colors; i++)
+          {
+            image->colormap[i].red=0;
+            image->colormap[i].green=0;
+            image->colormap[i].blue=0;
+          }
         }
 
       else
@@ -2350,6 +2326,30 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           }
        }
     }
+
+   /* Set some properties for reporting by "identify" */
+    {
+      char
+        msg[MaxTextExtent];
+
+     /* encode ping_width, ping_height, ping_bit_depth, ping_color_type,
+        ping_interlace_method in value */
+
+     (void) FormatMagickString(msg,MaxTextExtent,
+         "%d, %d",(int) ping_width, (int) ping_height);
+     (void) SetImageProperty(image,"PNG:IHDR.width,height    ",msg);
+
+     (void) FormatMagickString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
+     (void) SetImageProperty(image,"PNG:IHDR.bit_depth       ",msg);
+
+     (void) FormatMagickString(msg,MaxTextExtent,"%d",(int) ping_color_type);
+     (void) SetImageProperty(image,"PNG:IHDR.color_type      ",msg);
+
+     (void) FormatMagickString(msg,MaxTextExtent,"%d",
+        (int) ping_interlace_method);
+     (void) SetImageProperty(image,"PNG:IHDR.interlace_method",msg);
+   }
+
   /*
     Read image scanlines.
   */
@@ -2366,7 +2366,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           mng_info->scenes_found-1);
       png_destroy_read_struct(&ping,&ping_info,&end_info);
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-      UnlockSemaphoreInfo(png_semaphore);
+      UnlockSemaphoreInfo(ping_semaphore);
 #endif
       if (logging != MagickFalse)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -2380,14 +2380,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       "    Reading PNG IDAT chunk(s)");
 
   if (num_passes > 1)
-    png_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
-      ping_rowbytes*sizeof(*png_pixels));
+    ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
+      ping_rowbytes*sizeof(*ping_pixels));
 
   else
-    png_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
-      sizeof(*png_pixels));
+    ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
+      sizeof(*ping_pixels));
 
-  if (png_pixels == (unsigned char *) NULL)
+  if (ping_pixels == (unsigned char *) NULL)
     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
 
   if (logging != MagickFalse)
@@ -2403,13 +2403,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       */
       png_destroy_read_struct(&ping,&ping_info,&end_info);
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-      UnlockSemaphoreInfo(png_semaphore);
+      UnlockSemaphoreInfo(ping_semaphore);
 #endif
       if (quantum_info != (QuantumInfo *) NULL)
         quantum_info = DestroyQuantumInfo(quantum_info);
 
-      if (png_pixels != (unsigned char *) NULL)
-        png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
+      if (ping_pixels != (unsigned char *) NULL)
+        ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
 
       if (logging != MagickFalse)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -2462,54 +2462,64 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           else
             row_offset=0;
 
-          png_read_row(ping,png_pixels+row_offset,NULL);
+          png_read_row(ping,ping_pixels+row_offset,NULL);
           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
 
           if (q == (PixelPacket *) NULL)
             break;
 
-#if  (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT))
-/* code deleted from version 6.6.6-8 */
-#else  /* (MAGICKCORE_QUANTUM_DEPTH != 8) */
-
           if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-              GrayQuantum,png_pixels+row_offset,exception);
+              GrayQuantum,ping_pixels+row_offset,exception);
 
           else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-              GrayAlphaQuantum,png_pixels+row_offset,exception);
+              GrayAlphaQuantum,ping_pixels+row_offset,exception);
 
           else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-              RGBAQuantum,png_pixels+row_offset,exception);
+              RGBAQuantum,ping_pixels+row_offset,exception);
 
           else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-              IndexQuantum,png_pixels+row_offset,exception);
+              IndexQuantum,ping_pixels+row_offset,exception);
 
           else /* ping_color_type == PNG_COLOR_TYPE_RGB */
             (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
-              RGBQuantum,png_pixels+row_offset,exception);
-#endif
+              RGBQuantum,ping_pixels+row_offset,exception);
+
           if (found_transparent_pixel == MagickFalse)
             {
               /* Is there a transparent pixel in the row? */
+              if (y== 0 && logging != MagickFalse)
+                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "    Looking for cheap transparent pixel");
+
               for (x=(ssize_t) image->columns-1; x >= 0; x--)
               {
                 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
                     ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
-                   (q->opacity != OpaqueOpacity))
+                   (GetOpacityPixelComponent(q) != OpaqueOpacity))
                   {
+                    if (logging != MagickFalse)
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                        "    ...got one.");
+
                     found_transparent_pixel = MagickTrue;
                     break;
                   }
                 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
                     ping_color_type == PNG_COLOR_TYPE_GRAY) &&
-                    (q->red == transparent_color.red &&
-                    q->green == transparent_color.green &&
-                    q->blue == transparent_color.blue))
+                    (ScaleQuantumToShort(GetRedPixelComponent(q))
+                    == transparent_color.red &&
+                    ScaleQuantumToShort(GetGreenPixelComponent(q))
+                    == transparent_color.green &&
+                    ScaleQuantumToShort(GetBluePixelComponent(q))
+                    == transparent_color.blue))
                   {
+                    if (logging != MagickFalse)
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                        "    ...got one.");
                     found_transparent_pixel = MagickTrue;
                     break;
                   }
@@ -2568,14 +2578,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         else
           row_offset=0;
 
-        png_read_row(ping,png_pixels+row_offset,NULL);
+        png_read_row(ping,ping_pixels+row_offset,NULL);
         q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
 
         if (q == (PixelPacket *) NULL)
           break;
 
         indexes=GetAuthenticIndexQueue(image);
-        p=png_pixels+row_offset;
+        p=ping_pixels+row_offset;
         r=quantum_scanline;
 
         switch (ping_bit_depth)
@@ -2645,8 +2655,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                  * In a PNG datastream, Opaque is QuantumRange
                  * and Transparent is 0.
                  */
-                q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++)));
-                if (q->opacity != OpaqueOpacity)
+                SetOpacityPixelComponent(q,
+                    ScaleCharToQuantum((unsigned char) (255-(*p++))));
+                if (GetOpacityPixelComponent(q) != OpaqueOpacity)
                   found_transparent_pixel = MagickTrue;
                 q++;
               }
@@ -2681,8 +2692,8 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                 {
                   quantum=((*p++) << 8);
                   quantum|=(*p++);
-                  q->opacity=(Quantum) (QuantumRange-quantum);
-                  if (q->opacity != OpaqueOpacity)
+                  SetOpacityPixelComponent(q,(Quantum) (QuantumRange-quantum));
+                  if (GetOpacityPixelComponent(q) != OpaqueOpacity)
                     found_transparent_pixel = MagickTrue;
                   q++;
                 }
@@ -2704,10 +2715,11 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
               if (ping_color_type == 4)
                 {
-                  q->opacity=(*p << 8) | *(p+1);
-                  q->opacity*=65537L;
-                  q->opacity=(Quantum) GetAlphaPixelComponent(q);
-                  if (q->opacity != OpaqueOpacity)
+                  quantum=(*p << 8) | *(p+1);
+                  quantum*=65537L;
+                  SetOpacityPixelComponent(q,
+                    (Quantum) GetAlphaPixelComponent(q));
+                  if (GetOpacityPixelComponent(q) != OpaqueOpacity)
                     found_transparent_pixel = MagickTrue;
                   p+=2;
                   q++;
@@ -2719,8 +2731,8 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
               if (ping_color_type == 4)
                 {
-                  q->opacity=(Quantum) (QuantumRange-(*p++));
-                  if (q->opacity != OpaqueOpacity)
+                  SetOpacityPixelComponent(q,(Quantum) (QuantumRange-(*p++)));
+                  if (GetOpacityPixelComponent(q) != OpaqueOpacity)
                     found_transparent_pixel = MagickTrue;
                   p++;
                   q++;
@@ -2735,13 +2747,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           default:
             break;
         }
+
         /*
           Transfer image scanline.
         */
         r=quantum_scanline;
 
         for (x=0; x < (ssize_t) image->columns; x++)
-          indexes[x]=(IndexPacket) (*r++);
+          SetIndexPixelComponent(indexes+x,*r++);
 
         if (SyncAuthenticPixels(image,exception) == MagickFalse)
           break;
@@ -2749,7 +2762,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         if ((image->previous == (Image *) NULL) && (num_passes == 1))
           {
             status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
-                image->rows);
+              image->rows);
 
             if (status == MagickFalse)
               break;
@@ -2778,6 +2791,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           {
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "    No transparent pixel was found");
+          
             ping_color_type&=0x03;
           }
       }
@@ -2797,17 +2811,17 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       image->matte=matte;
     }
 
-  png_read_end(ping,ping_info);
+  png_read_end(ping,end_info);
 
   if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
       (ssize_t) image_info->first_scene && image->delay != 0)
     {
       png_destroy_read_struct(&ping,&ping_info,&end_info);
-      png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
+      ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
       image->colors=2;
       (void) SetImageBackgroundColor(image);
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-      UnlockSemaphoreInfo(png_semaphore);
+      UnlockSemaphoreInfo(ping_semaphore);
 #endif
       if (logging != MagickFalse)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -2853,6 +2867,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           (void) SyncImage(image);
         }
 
+#if 1 /* Should have already been done above, but glennrp problem P10
+       * needs this.
+       */
       else
         {
           for (y=0; y < (ssize_t) image->rows; y++)
@@ -2865,19 +2882,27 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
             indexes=GetAuthenticIndexQueue(image);
 
+            /* Caution: on a Q8 build, this does not distinguish between
+             * 16-bit colors that differ only in the low byte
+             */
             for (x=(ssize_t) image->columns-1; x >= 0; x--)
             {
-              if (ScaleQuantumToChar(q->red) == transparent_color.red &&
-                  ScaleQuantumToChar(q->green) == transparent_color.green &&
-                  ScaleQuantumToChar(q->blue) == transparent_color.blue)
+              if (ScaleQuantumToShort(GetRedPixelComponent(q))
+                  == transparent_color.red &&
+                  ScaleQuantumToShort(GetGreenPixelComponent(q))
+                  == transparent_color.green &&
+                  ScaleQuantumToShort(GetBluePixelComponent(q))
+                  == transparent_color.blue)
                 {
-                  q->opacity=(Quantum) TransparentOpacity;
+                  SetOpacityPixelComponent(q,TransparentOpacity);
                 }
 
+#if 0 /* I have not found a case where this is needed. */
               else
                 {
-                  q->opacity=(Quantum) OpaqueOpacity;
+                  SetOpacityPixelComponent(q)=(Quantum) OpaqueOpacity;
                 }
+#endif
 
               q++;
             }
@@ -2886,6 +2911,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                break;
           }
         }
+#endif
 
       image->storage_class=DirectClass;
     }
@@ -2894,43 +2920,68 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
     image->colorspace=GRAYColorspace;
 
-  if (png_get_text(ping,ping_info,&text,&num_text) != 0)
-    for (i=0; i < (ssize_t) num_text; i++)
-    {
-      /* Check for a profile */
+  for (j = 0; j < 2; j++)
+  {
+    if (j == 0)
+      status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
+          MagickTrue : MagickFalse;
+    else
+      status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
+          MagickTrue : MagickFalse;
 
-      if (logging != MagickFalse)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "    Reading PNG text chunk");
+    if (status != MagickFalse)
+      for (i=0; i < (ssize_t) num_text; i++)
+      {
+        /* Check for a profile */
 
-      if (memcmp(text[i].key, "Raw profile type ",17) == 0)
-          (void) png_read_raw_profile(image,image_info,text,(int) i);
+        if (logging != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    Reading PNG text chunk");
 
-      else
-        {
-          char
-            *value;
+        if (memcmp(text[i].key, "Raw profile type ",17) == 0)
+          {
+            (void) Magick_png_read_raw_profile(image,image_info,text,(int) i);
+            num_raw_profiles++;
+          }
+
+        else
+          {
+            char
+              *value;
+
+            length=text[i].text_length;
+            value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
+              sizeof(*value));
+            if (value == (char *) NULL)
+              {
+                (void) ThrowMagickException(&image->exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                  image->filename);
+                break;
+              }
+            *value='\0';
+            (void) ConcatenateMagickString(value,text[i].text,length+2);
+
+            /* Don't save "density" or "units" property if we have a pHYs
+             * chunk
+             */
+            if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
+                (LocaleCompare(text[i].key,"density") != 0 &&
+                LocaleCompare(text[i].key,"units") != 0))
+               (void) SetImageProperty(image,text[i].key,value);
 
-          length=text[i].text_length;
-          value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
-            sizeof(*value));
-          if (value == (char *) NULL)
+            if (logging != MagickFalse)
             {
-              (void) ThrowMagickException(&image->exception,GetMagickModule(),
-                ResourceLimitError,"MemoryAllocationFailed","`%s'",
-                image->filename);
-              break;
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                "      length: %lu",(unsigned long) length);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                "      Keyword: %s",text[i].key);
             }
-          *value='\0';
-          (void) ConcatenateMagickString(value,text[i].text,length+2);
-          (void) SetImageProperty(image,text[i].key,value);
-
-          if (logging != MagickFalse)
-            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "      Keyword: %s",text[i].key);
 
-          value=DestroyString(value);
-        }
+            value=DestroyString(value);
+          }
+      }
+      num_text_total += num_text;
     }
 
 #ifdef MNG_OBJECT_BUFFERS
@@ -3023,14 +3074,114 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         }
     }
 #endif
+
+   /* Set image->matte to MagickTrue if the input colortype supports
+    * alpha or if a valid tRNS chunk is present, no matter whether there
+    * is actual transparency present.
+    */
+    image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
+        ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
+        (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
+        MagickTrue : MagickFalse;
+
+   /* Set more properties for identify to retrieve */
+   {
+     char
+       msg[MaxTextExtent];
+
+     if (num_text_total != 0)
+       {
+         /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
+         (void) FormatMagickString(msg,MaxTextExtent,
+            "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
+         (void) SetImageProperty(image,"PNG:text                 ",msg);
+       }
+
+     if (num_raw_profiles != 0)
+       {
+         (void) FormatMagickString(msg,MaxTextExtent,
+            "%d were found", num_raw_profiles);
+         (void) SetImageProperty(image,"PNG:text-encoded profiles",msg);
+       }
+
+     if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
+       {
+         (void) FormatMagickString(msg,MaxTextExtent,"%s",
+            "chunk was found (see Chromaticity, above)");
+         (void) SetImageProperty(image,"PNG:cHRM                 ",msg);
+       }
+
+     if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
+       {
+         (void) FormatMagickString(msg,MaxTextExtent,"%s",
+            "chunk was found (see Background color, above)");
+         (void) SetImageProperty(image,"PNG:bKGD                 ",msg);
+       }
+
+     (void) FormatMagickString(msg,MaxTextExtent,"%s",
+        "chunk was found");
+
+     if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
+        (void) SetImageProperty(image,"PNG:iCCP                 ",msg);
+
+     if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
+        (void) SetImageProperty(image,"PNG:tRNS                 ",msg);
+
+#if defined(PNG_sRGB_SUPPORTED)
+     if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
+       {
+         (void) FormatMagickString(msg,MaxTextExtent,
+            "intent=%d (See Rendering intent)",
+            (int) intent);
+         (void) SetImageProperty(image,"PNG:sRGB                 ",msg);
+       }
+#endif
+
+     if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
+       {
+         (void) FormatMagickString(msg,MaxTextExtent,
+            "gamma=%.8g (See Gamma, above)",
+            file_gamma);
+         (void) SetImageProperty(image,"PNG:gAMA                 ",msg);
+       }
+
+#if defined(PNG_pHYs_SUPPORTED)
+     if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
+       {
+         (void) FormatMagickString(msg,MaxTextExtent,
+            "x_res=%.10g, y_res=%.10g, units=%d",
+            (double) x_resolution,(double) y_resolution, unit_type);
+         (void) SetImageProperty(image,"PNG:pHYs                 ",msg);
+       }
+#endif
+
+#if defined(PNG_oFFs_SUPPORTED)
+     if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
+       {
+         (void) FormatMagickString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
+            (double) image->page.x,(double) image->page.y);
+         (void) SetImageProperty(image,"PNG:oFFs                 ",msg);
+       }
+#endif
+
+     if ((image->page.width != 0 && image->page.width != image->columns) ||
+         (image->page.height != 0 && image->page.height != image->rows))
+       {
+         (void) FormatMagickString(msg,MaxTextExtent,
+            "width=%.20g, height=%.20g",
+            (double) image->page.width,(double) image->page.height);
+         (void) SetImageProperty(image,"PNG:vpAg                 ",msg);
+       }
+   }
+
   /*
     Relinquish resources.
   */
   png_destroy_read_struct(&ping,&ping_info,&end_info);
 
-  png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
+  ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-  UnlockSemaphoreInfo(png_semaphore);
+  UnlockSemaphoreInfo(ping_semaphore);
 #endif
 
   if (logging != MagickFalse)
@@ -3074,7 +3225,7 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
+  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
   image=AcquireImage(image_info);
   mng_info=(MngInfo *) NULL;
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
@@ -3087,7 +3238,7 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   */
   count=ReadBlob(image,8,(unsigned char *) magic_number);
 
-  if (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
+  if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
 
   /*
@@ -3139,6 +3290,7 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
       ThrowReaderException(CorruptImageError,"CorruptImage");
     }
 
+#if 0 /* This is probably redundant now */
   if (LocaleCompare(image_info->magick,"PNG8") == 0)
     {
       (void) SetImageType(image,PaletteType);
@@ -3148,6 +3300,7 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
           /* To do: Reduce to binary transparency */
         }
     }
+#endif
 
   if (LocaleCompare(image_info->magick,"PNG24") == 0)
     {
@@ -3158,6 +3311,12 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   if (LocaleCompare(image_info->magick,"PNG32") == 0)
     (void) SetImageType(image,TrueColorMatteType);
 
+  if (logging != MagickFalse)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+        "  page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
+            (double) image->page.width,(double) image->page.height,
+            (double) image->page.x,(double) image->page.y);
+
   if (logging != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
 
@@ -3267,7 +3426,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
   color_image_info=(ImageInfo *) NULL;
 
   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
-    "  enter ReadOneJNGImage()");
+    "  Enter ReadOneJNGImage()");
 
   image=mng_info->image;
 
@@ -3640,7 +3799,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
         if (length == 1)
           {
             image->rendering_intent=
-              PNG_RenderingIntent_to_Magick_RenderingIntent(p[0]);
+              Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
             image->gamma=0.45455f;
             image->chromaticity.red_primary.x=0.6400f;
             image->chromaticity.red_primary.y=0.3300f;
@@ -3660,8 +3819,8 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
       {
         if (length > 8)
           {
-            image->page.x=mng_get_long(p);
-            image->page.y=mng_get_long(&p[4]);
+            image->page.x=(ssize_t) mng_get_long(p);
+            image->page.y=(ssize_t) mng_get_long(&p[4]);
 
             if ((int) p[8] != 0)
               {
@@ -3697,7 +3856,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
 #if 0
     if (memcmp(type,mng_iCCP,4) == 0)
       {
-        /* To do. */
+        /* To do: */
         if (length)
           chunk=(unsigned char *) RelinquishMagickMemory(chunk);
 
@@ -3815,13 +3974,15 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
 
              if (image->matte != MagickFalse)
                for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
-                  q->opacity=(Quantum) QuantumRange-s->red;
+                  SetOpacityPixelComponent(q,(Quantum) QuantumRange-
+                      GetRedPixelComponent(s));
 
              else
                for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
                {
-                  q->opacity=(Quantum) QuantumRange-s->red;
-                  if (q->opacity != OpaqueOpacity)
+                  SetOpacityPixelComponent(q,(Quantum) QuantumRange-
+                      GetRedPixelComponent(s));
+                  if (GetOpacityPixelComponent(q) != OpaqueOpacity)
                     image->matte=MagickTrue;
                }
 
@@ -3931,7 +4092,7 @@ static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
+  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
   image=AcquireImage(image_info);
   mng_info=(MngInfo *) NULL;
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
@@ -3946,7 +4107,7 @@ static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
   count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
 
-  if (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
+  if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
 
   /* Allocate a MngInfo structure.  */
@@ -4107,7 +4268,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
+  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
   image=AcquireImage(image_info);
   mng_info=(MngInfo *) NULL;
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
@@ -4611,7 +4772,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
             if (length)
               {
                 mng_info->global_srgb_intent=
-                  PNG_RenderingIntent_to_Magick_RenderingIntent(p[0]);
+                  Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
                 mng_info->have_global_srgb=MagickTrue;
               }
             else
@@ -4623,7 +4784,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
         if (memcmp(type,mng_iCCP,4) == 0)
           {
-            /* To do. */
+            /* To do: */
 
             /*
               Read global iCCP.
@@ -5629,7 +5790,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 magn_methx=mng_info->magn_methx;
                 magn_methy=mng_info->magn_methy;
 
-#if (MAGICKCORE_QUANTUM_DEPTH == 32)
+#if (MAGICKCORE_QUANTUM_DEPTH > 16)
 #define QM unsigned short
                 if (magn_methx != 1 || magn_methy != 1)
                   {
@@ -5644,10 +5805,14 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
                        for (x=(ssize_t) image->columns-1; x >= 0; x--)
                        {
-                          q->red=ScaleQuantumToShort(q->red);
-                          q->green=ScaleQuantumToShort(q->green);
-                          q->blue=ScaleQuantumToShort(q->blue);
-                          q->opacity=ScaleQuantumToShort(q->opacity);
+                          SetRedPixelComponent(q,ScaleQuantumToShort(
+                            GetRedPixelComponent(q));
+                          SetGreenPixelComponent(q,ScaleQuantumToShort(
+                            GetGreenPixelComponent(q));
+                          SetBluePixelComponent(q,ScaleQuantumToShort(
+                            GetBluePixelComponent(q));
+                          SetOpacityPixelComponent(q,ScaleQuantumToShort(
+                            GetOpacityPixelComponent(q));
                           q++;
                        }
 
@@ -5733,6 +5898,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
                   for (i=0; i < m; i++, yy++)
                   {
+                    /* To do: Rewrite using Get/Set***PixelComponent() */
                     register PixelPacket
                       *pixels;
 
@@ -5740,12 +5906,12 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                     pixels=prev;
                     n=next;
                     q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
-                          1,exception);
+                      1,exception);
                     q+=(large_image->columns-image->columns);
 
                     for (x=(ssize_t) image->columns-1; x >= 0; x--)
                     {
-                      /* TO DO: get color as function of indexes[x] */
+                      /* To do: get color as function of indexes[x] */
                       /*
                       if (image->storage_class == PseudoClass)
                         {
@@ -5845,12 +6011,15 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                     *pixels;
 
                   q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+                  /* To do: Rewrite using Get/Set***PixelComponent() */
                   pixels=q+(image->columns-length);
                   n=pixels+1;
 
                   for (x=(ssize_t) (image->columns-length);
                     x < (ssize_t) image->columns; x++)
                   {
+                    /* To do: Rewrite using Get/Set***PixelComponent() */
+
                     if (x == (ssize_t) (image->columns-length))
                       m=(ssize_t) mng_info->magn_ml;
 
@@ -5871,6 +6040,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                       if (magn_methx <= 1)
                         {
                           /* replicate previous */
+                          /* To do: Rewrite using Get/Set***PixelComponent() */
                           *q=(*pixels);
                         }
 
@@ -5933,7 +6103,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
                     break;
                 }
-#if (MAGICKCORE_QUANTUM_DEPTH == 32)
+#if (MAGICKCORE_QUANTUM_DEPTH > 16)
               if (magn_methx != 1 || magn_methy != 1)
                 {
                 /*
@@ -5945,10 +6115,14 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
                      for (x=(ssize_t) image->columns-1; x >= 0; x--)
                      {
-                        q->red=ScaleShortToQuantum(q->red);
-                        q->green=ScaleShortToQuantum(q->green);
-                        q->blue=ScaleShortToQuantum(q->blue);
-                        q->opacity=ScaleShortToQuantum(q->opacity);
+                        SetRedPixelComponent(q,ScaleShortToQuantum(
+                            GetRedPixelComponent(q));
+                        SetGreenPixelComponent(q,ScaleShortToQuantum(
+                            GetGreenPixelComponent(q));
+                        SetBluePixelComponent(q,ScaleShortToQuantum(
+                            GetBluePixelComponent(q));
+                        SetOpacityPixelComponent(q,ScaleShortToQuantum(
+                            GetOpacityPixelComponent(q));
                         q++;
                      }
 
@@ -6051,7 +6225,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
          image->depth=16;
 #endif
 
-#if (MAGICKCORE_QUANTUM_DEPTH >= 16)
+#if (MAGICKCORE_QUANTUM_DEPTH > 8)
       if (LosslessReduceDepthOK(image) != MagickFalse)
          image->depth = 8;
 #endif
@@ -6512,7 +6686,7 @@ ModuleExport size_t RegisterPNGImage(void)
   (void) RegisterMagickInfo(entry);
 
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-  png_semaphore=AllocateSemaphoreInfo();
+  ping_semaphore=AllocateSemaphoreInfo();
 #endif
 
   return(MagickImageCoderSignature);
@@ -6547,8 +6721,8 @@ ModuleExport void UnregisterPNGImage(void)
   (void) UnregisterMagickInfo("JNG");
 
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-  if (png_semaphore != (SemaphoreInfo *) NULL)
-    DestroySemaphoreInfo(&png_semaphore);
+  if (ping_semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&ping_semaphore);
 #endif
 }
 \f
@@ -6584,9 +6758,6 @@ ModuleExport void UnregisterPNGImage(void)
 %  To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
 %    "To do" under ReadPNGImage):
 %
-%    Fix problem with palette sorting (when PNG_SORT_PALETTE is enabled,
-%    some GIF animations don't convert properly)
-%
 %    Preserve all unknown and not-yet-handled known chunks found in input
 %    PNG file and copy them  into output PNG files according to the PNG
 %    copying rules.
@@ -6632,7 +6803,7 @@ ModuleExport void UnregisterPNGImage(void)
 */
 
 static void
-png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
+Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
    png_info *ping_info, unsigned char *profile_type, unsigned char
    *profile_description, unsigned char *profile_data, png_uint_32 length)
 {
@@ -6708,7 +6879,7 @@ png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
    png_free(ping,text);
 }
 
-static MagickBooleanType png_write_chunk_from_profile(Image *image,
+static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
   const char *string, MagickBooleanType logging)
 {
   char
@@ -6731,7 +6902,7 @@ static MagickBooleanType png_write_chunk_from_profile(Image *image,
     if (profile != (const StringInfo *) NULL)
       {
         StringInfo
-          *png_profile;
+          *ping_profile;
 
         if (LocaleNCompare(name,string,11) == 0)
           {
@@ -6739,9 +6910,9 @@ static MagickBooleanType png_write_chunk_from_profile(Image *image,
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                    "  Found %s profile",name);
 
-            png_profile=CloneStringInfo(profile);
-            data=GetStringInfoDatum(png_profile),
-            length=(png_uint_32) GetStringInfoLength(png_profile);
+            ping_profile=CloneStringInfo(profile);
+            data=GetStringInfoDatum(ping_profile),
+            length=(png_uint_32) GetStringInfoLength(ping_profile);
             data[4]=data[3];
             data[3]=data[2];
             data[2]=data[1];
@@ -6749,7 +6920,7 @@ static MagickBooleanType png_write_chunk_from_profile(Image *image,
             (void) WriteBlobMSBULong(image,length-5);  /* data length */
             (void) WriteBlob(image,length-1,data+1);
             (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
-            png_profile=DestroyStringInfo(png_profile);
+            ping_profile=DestroyStringInfo(ping_profile);
           }
       }
 
@@ -6813,7 +6984,10 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     logging,
     matte,
 
+    ping_have_blob,
+    ping_have_cheap_transparency,
     ping_have_color,
+    ping_have_non_bw,
     ping_have_PLTE,
     ping_have_bKGD,
     ping_have_pHYs,
@@ -6821,7 +6995,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
     ping_exclude_bKGD,
     ping_exclude_cHRM,
-    ping_exclude_EXIF,
+    ping_exclude_date,
+    /* ping_exclude_EXIF, */
     ping_exclude_gAMA,
     ping_exclude_iCCP,
     /* ping_exclude_iTXt, */
@@ -6829,14 +7004,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     ping_exclude_pHYs,
     ping_exclude_sRGB,
     ping_exclude_tEXt,
-    ping_exclude_tRNS,
+    /* ping_exclude_tRNS, */
     ping_exclude_vpAg,
     ping_exclude_zCCP, /* hex-encoded iCCP */
     ping_exclude_zTXt,
 
+    ping_preserve_colormap,
     ping_need_colortype_warning,
 
-    status;
+    status,
+    tried_333,
+    tried_444;
 
   QuantumInfo
     *quantum_info;
@@ -6846,7 +7024,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     x;
 
   unsigned char
-    *png_pixels;
+    *ping_pixels;
 
   volatile int
     image_colors,
@@ -6867,6 +7045,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     save_image_depth;
 
   int
+    j,
     number_colors,
     number_opaque,
     number_semitransparent,
@@ -6878,24 +7057,15 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     ping_pHYs_y_resolution;
 
   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
-    "  enter WriteOnePNGImage()");
+    "  Enter WriteOnePNGImage()");
 
   image = CloneImage(IMimage,0,0,MagickFalse,&IMimage->exception);
   image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
-
-  if (mng_info->need_blob != MagickFalse)
-  {
-    if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
-       MagickFalse)
-    {
-      image_info=DestroyImageInfo(image_info);
-      image=DestroyImage(image);
-      return(MagickFalse);
-    }
-  }
+  if (image_info == (ImageInfo *) NULL)
+     ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
 
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-  LockSemaphoreInfo(png_semaphore);
+  LockSemaphoreInfo(ping_semaphore);
 #endif
 
   /* Initialize some stuff */
@@ -6921,7 +7091,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   ping_pHYs_x_resolution = 0;
   ping_pHYs_y_resolution = 0;
 
+  ping_have_blob=MagickFalse;
   ping_have_color=MagickTrue;
+  ping_have_non_bw=MagickTrue;
   ping_have_PLTE=MagickFalse;
   ping_have_bKGD=MagickFalse;
   ping_have_pHYs=MagickFalse;
@@ -6929,26 +7101,53 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
   ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
   ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
-  ping_exclude_EXIF=mng_info->ping_exclude_EXIF; /* hex-encoded EXIF in zTXt */
+  ping_exclude_date=mng_info->ping_exclude_date;
+  /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
   ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
-  ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
   ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
   /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
   ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
   ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
   ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
   ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
-  ping_exclude_tRNS=mng_info->ping_exclude_tRNS;
+  /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
   ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
   ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
   ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
 
+  ping_preserve_colormap = mng_info->ping_preserve_colormap;
   ping_need_colortype_warning = MagickFalse;
 
   number_opaque = 0;
   number_semitransparent = 0;
   number_transparent = 0;
 
+  if (logging != MagickFalse)
+    {
+      if (image->storage_class == UndefinedClass)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    storage_class=UndefinedClass");
+      if (image->storage_class == DirectClass)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    storage_class=DirectClass");
+      if (image->storage_class == PseudoClass)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    storage_class=PseudoClass");
+    }
+
+  if (ping_preserve_colormap == MagickFalse)
+    {
+      if (image->storage_class != PseudoClass && image->colormap != NULL)
+        {
+          /* Free the bogus colormap; it can cause trouble later */
+           if (logging != MagickFalse)
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "    Freeing bogus colormap");
+           (void *) RelinquishMagickMemory(image->colormap);
+           image->colormap=NULL;
+        }
+    }
+   
   if (image->colorspace != RGBColorspace)
     (void) TransformImageColorspace(image,RGBColorspace);
 
@@ -6959,6 +7158,33 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
      (void) SyncImage(image);
 
+#if (MAGICKCORE_QUANTUM_DEPTH == 8)
+  if (image->depth > 8)
+    {
+      if (logging != MagickFalse)
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    Reducing PNG bit depth to 8 since this is a Q8 build.");
+
+      image->depth=8;
+    }
+#endif
+
+#if 0 /* To do: Option to use the original colormap */
+  if (ping_preserve_colormap != MagickFalse)
+    {
+    }
+#endif
+
+#if 0 /* To do: respect the -depth option */
+  if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
+    {
+    }
+#endif
+
+  /* To do: set to next higher multiple of 8 */
+  if (image->depth < 8)
+     image->depth=8;
+
 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
   /* PNG does not handle depths greater than 16 so reduce it even
    * if lossy
@@ -6967,336 +7193,854 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
       image->depth=16;
 #endif
 
-#if (MAGICKCORE_QUANTUM_DEPTH >= 16)
-  if (image->depth == 16 && mng_info->write_png_colortype != 16)
+#if (MAGICKCORE_QUANTUM_DEPTH > 8)
+  if (image->depth == 16 && mng_info->write_png_depth != 16)
     if (mng_info->write_png8 || LosslessReduceDepthOK(image) != MagickFalse)
       image->depth = 8;
 #endif
 
-#ifdef PNG_BUILD_PALETTE
-  if (mng_info->write_png_colortype < 8 /* all */)
-    {
-      /*
-       * Sometimes we get DirectClass images that have 256 colors or fewer.
-       * This code will build a colormap.
-       *
-       * Also, sometimes we get PseudoClass images with an out-of-date
-       * colormap.  This code will replace the colormap with a new one.
-       * Sometimes we get PseudoClass images that have more than 256 colors.
-       * This code will delete the colormap and change the image to
-       * DirectClass.
-       *
-       * Also we gather some information (number of opaque, transparent,
-       * and semitransparent pixels, and whether the image has any non-gray
-       * pixels) that we might need later. If the user wants to force
-       * GrayAlpha or RGBA (colortype 4 or 6) we probably don't need any
-       * of that.
-       */
+  /* Normally we run this just once, but in the case of writing PNG8
+   * we reduce the transparency to binary and run again, then if there
+   * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
+   * RGBA palette and run again, and finally to a simple 3-3-2-1 RGBA
+   * palette.  The final reduction can only fail if there are still 256
+   * colors present and one of them has both transparent and opaque instances.
+   */
 
-     ExceptionInfo
-       *exception;
+  tried_333 = MagickFalse;
+  tried_444 = MagickFalse;
 
-     int
-       n;
+  for (j=0; j<5; j++)
+  {
+    /* BUILD_PALETTE
+     *
+     * Sometimes we get DirectClass images that have 256 colors or fewer.
+     * This code will build a colormap.
+     *
+     * Also, sometimes we get PseudoClass images with an out-of-date
+     * colormap.  This code will replace the colormap with a new one.
+     * Sometimes we get PseudoClass images that have more than 256 colors.
+     * This code will delete the colormap and change the image to
+     * DirectClass.
+     *
+     * If image->matte is MagickFalse, we ignore the opacity channel
+     * even though it sometimes contains left-over non-opaque values.
+     *
+     * Also we gather some information (number of opaque, transparent,
+     * and semitransparent pixels, and whether the image has any non-gray
+     * pixels or only black-and-white pixels) that we might need later.
+     *
+     * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
+     * we need to check for bogus non-opaque values, at least.
+     */
 
-     PixelPacket
-       colormap[800],
-       opaque[260],
-       semitransparent[260],
-       transparent[260];
+   ExceptionInfo
+     *exception;
 
-     register IndexPacket
-       *indexes;
+   int
+     n;
 
-     register const PixelPacket
-       *q;
+   PixelPacket
+     opaque[260],
+     semitransparent[260],
+     transparent[260];
 
-     if (logging != MagickFalse)
-       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-           "    Enter BUILD_PALETTE:");
+   register IndexPacket
+     *indexes;
 
-     image->colors=GetNumberColors(image,(FILE *) NULL,&image->exception);
-     image_colors=(int) image->colors;
+   register const PixelPacket
+     *s,
+     *q;
 
-     if (logging != MagickFalse)
+   register PixelPacket
+     *r;
+
+   if (logging != MagickFalse)
+     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+         "    Enter BUILD_PALETTE:");
+
+   if (logging != MagickFalse)
+     {
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             "      image->columns=%.20g",(double) image->columns);
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             "      image->rows=%.20g",(double) image->rows);
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             "      image->matte=%.20g",(double) image->matte);
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             "      image->depth=%.20g",(double) image->depth);
+
+       if (image->storage_class == PseudoClass && image->colormap != NULL)
        {
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "      image->columns=%.20g",(double) image->columns);
-         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "      image->rows=%.20g",(double) image->rows);
-         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "      image->matte=%.20g",(double) image->matte);
+             "      Original colormap:");
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "      image->depth=%.20g",(double) image->depth);
+             "        i    (red,green,blue,opacity)");
 
-         if (image->colormap != NULL)
+         for (i=0; i < 256; i++)
          {
-           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "      Original colormap:");
-           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "        i    (red,green,blue,opacity)");
+               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "        %d    (%d,%d,%d,%d)",
+                    (int) i,
+                    (int) image->colormap[i].red,
+                    (int) image->colormap[i].green,
+                    (int) image->colormap[i].blue,
+                    (int) image->colormap[i].opacity);
+         }
 
-           for (i=0; i < (ssize_t) image->colors; i++)
-           {
-             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                 "        %d    (%d,%d,%d,%d)",
-                  (int) i,
-                  (int) image->colormap[i].red,
-                  (int) image->colormap[i].green,
-                  (int) image->colormap[i].blue,
-                  (int) image->colormap[i].opacity);
-           }
+         for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
+         {
+           if (i > 255)
+             {
+               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "        %d    (%d,%d,%d,%d)",
+                    (int) i,
+                    (int) image->colormap[i].red,
+                    (int) image->colormap[i].green,
+                    (int) image->colormap[i].blue,
+                    (int) image->colormap[i].opacity);
+             }
          }
+       }
 
-         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-             "      image->colors=%d",(int) image->colors);
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+           "      image->colors=%d",(int) image->colors);
 
-         if (image->colors == 0)
-         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-             "        (zero means unknown)");
+       if (image->colors == 0)
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+           "        (zero means unknown)");
 
+       if (ping_preserve_colormap == MagickFalse)
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "      Regenerate the colormap");
-       }
+     }
 
-       exception=(&image->exception);
+     exception=(&image->exception);
 
-       ping_have_color=MagickFalse;
-       image_colors=0;
+     image_colors=0;
+     number_opaque = 0;
+     number_semitransparent = 0;
+     number_transparent = 0;
+
+     for (y=0; y < (ssize_t) image->rows; y++)
+     {
+       q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
 
-       for (y=0; y < (ssize_t) image->rows; y++)
+       if (q == (PixelPacket *) NULL)
+         break;
+
+       for (x=0; x < (ssize_t) image->columns; x++)
        {
-         q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+           if (image->matte == MagickFalse ||
+              GetOpacityPixelComponent(q) == OpaqueOpacity)
+             {
+               if (number_opaque < 259)
+                 {
+                   if (number_opaque == 0)
+                     {
+                       GetRGBPixelComponents(q, opaque[0]);
+                       opaque[0].opacity=OpaqueOpacity;
+                       number_opaque=1;
+                     }
 
-         if (q == (PixelPacket *) NULL)
-           break;
+                   for (i=0; i< (ssize_t) number_opaque; i++)
+                     {
+                       if (IsColorEqual(q, opaque+i))
+                         break;
+                     }
+
+                   if (i ==  (ssize_t) number_opaque &&
+                       number_opaque < 259)
+                     {
+                       number_opaque++;
+                       GetRGBPixelComponents(q, opaque[i]);
+                       opaque[i].opacity=OpaqueOpacity;
+                     }
+                 }
+             }
+           else if (q->opacity == TransparentOpacity)
+             {
+               if (number_transparent < 259)
+                 {
+                   if (number_transparent == 0)
+                     {
+                       GetRGBOPixelComponents(q, transparent[0]);
+                       ping_trans_color.red=
+                         (unsigned short) GetRedPixelComponent(q);
+                       ping_trans_color.green=
+                         (unsigned short) GetGreenPixelComponent(q);
+                       ping_trans_color.blue=
+                         (unsigned short) GetBluePixelComponent(q);
+                       ping_trans_color.gray=
+                         (unsigned short) GetRedPixelComponent(q);
+                       number_transparent = 1;
+                     }
+
+                   for (i=0; i< (ssize_t) number_transparent; i++)
+                     {
+                       if (IsColorEqual(q, transparent+i))
+                         break;
+                     }
+
+                   if (i ==  (ssize_t) number_transparent &&
+                       number_transparent < 259)
+                     {
+                       number_transparent++;
+                       GetRGBOPixelComponents(q, transparent[i]);
+                     }
+                 }
+             }
+           else
+             {
+               if (number_semitransparent < 259)
+                 {
+                   if (number_semitransparent == 0)
+                     {
+                       GetRGBOPixelComponents(q, semitransparent[0]);
+                       number_semitransparent = 1;
+                     }
+
+                   for (i=0; i< (ssize_t) number_semitransparent; i++)
+                     {
+                       if (IsColorEqual(q, semitransparent+i)
+                           && GetOpacityPixelComponent(q) ==
+                           semitransparent[i].opacity)
+                         break;
+                     }
+
+                   if (i ==  (ssize_t) number_semitransparent &&
+                       number_semitransparent < 259)
+                     {
+                       number_semitransparent++;
+                       GetRGBOPixelComponents(q, semitransparent[i]);
+                     }
+                 }
+             }
+           q++;
+        }
+     }
 
-         for (x=0; x < (ssize_t) image->columns; x++)
+     if (ping_exclude_bKGD == MagickFalse)
+       {
+         /* Add the background color to the palette, if it
+          * isn't already there.
+          */
+          if (logging != MagickFalse)
             {
-                if (q->red != q->green || q->red != q->blue)
-                  ping_have_color=MagickTrue;
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "      Check colormap for background (%d,%d,%d)",
+                  (int) image->background_color.red,
+                  (int) image->background_color.green,
+                  (int) image->background_color.blue);
+            }
+          for (i=0; i<number_opaque; i++)
+          {
+             if (opaque[i].red == image->background_color.red &&
+                 opaque[i].green == image->background_color.green &&
+                 opaque[i].blue == image->background_color.blue)
+               break;
+          }
+          if (number_opaque < 259 && i == number_opaque)
+            {
+               opaque[i] = image->background_color;
+               ping_background.index = i;
+               if (logging != MagickFalse)
+                 {
+                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                       "      background_color index is %d",(int) i);
+                 }
 
-                if (image_colors == 0)
-                  {
-                   /* Initialize the colormap */
-                    colormap[0]=*q;
+            }
+          else if (logging != MagickFalse)
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "      No room in the colormap to add background color");
+       }
+
+     image_colors=number_opaque+number_transparent+number_semitransparent;
+
+     if (mng_info->write_png8 != MagickFalse && image_colors > 256)
+       {
+         /* No room for the background color; remove it. */
+         number_opaque--;
+         image_colors--;
+       }
 
-                    if (image->matte == MagickFalse)
-                          colormap[0].opacity = OpaqueOpacity;
+     if (logging != MagickFalse)
+       {
+         if (image_colors > 256)
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "      image has more than 256 colors");
 
-                    image_colors=1;
+         else
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "      image has %d colors",image_colors);
+       }
+
+     if (ping_preserve_colormap != MagickFalse)
+       break;
+
+     if (mng_info->write_png_colortype != 7) /* We won't need this info */
+       {
+         ping_have_color=MagickFalse;
+         ping_have_non_bw=MagickFalse;
+
+         if(image_colors > 256)
+           {
+             for (y=0; y < (ssize_t) image->rows; y++)
+             {
+               q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+
+               if (q == (PixelPacket *) NULL)
+                 break;
+
+               /* Worst case is black-and-white; we are looking at every
+                * pixel twice.
+                */
+
+               if (ping_have_color == MagickFalse)
+                 {
+                   s=q;
+                   for (x=0; x < (ssize_t) image->columns; x++)
+                   {
+                     if (GetRedPixelComponent(s) != GetGreenPixelComponent(s)
+                        || GetRedPixelComponent(s) != GetBluePixelComponent(s))
+                       {
+                          ping_have_color=MagickTrue;
+                          ping_have_non_bw=MagickTrue;
+                          break;
+                       }
+                     s++;
                    }
+                 }
 
-                for (i=0; i< (ssize_t) image_colors; i++)
-                  {
-                    if (((image->matte == MagickFalse ||
-                        colormap[i].opacity == q->opacity)) &&
-                        (IsColorEqual(colormap+i, (PixelPacket *) q)))
-                      break;
-                  }
+               if (ping_have_non_bw == MagickFalse)
+                 {
+                   s=q;
+                   for (x=0; x < (ssize_t) image->columns; x++)
+                   {
+                     if (GetRedPixelComponent(s) != 0 &&
+                         GetRedPixelComponent(s) != QuantumRange)
+                       {
+                         ping_have_non_bw=MagickTrue;
+                       }
+                     s++;
+                   }
+                 }
+             }
+           } 
+       } 
 
-                if (i ==  (ssize_t) image_colors && image_colors < 299)
-                  {
+     if (image_colors < 257)
+       {
+         PixelPacket
+           colormap[260];
+             
+         /*
+          * Initialize image colormap.
+          */
+
+         if (logging != MagickFalse)
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "      Sort the new colormap");
+
+        /* Sort palette, transparent first */;
+
+         n = 0;
 
-                    image_colors++;
+         for (i=0; i<number_transparent; i++)
+            colormap[n++] = transparent[i];
 
-                    colormap[i]=*q;
+         for (i=0; i<number_semitransparent; i++)
+            colormap[n++] = semitransparent[i];
 
-                    if (image->matte == MagickFalse)
-                       colormap[i].opacity = OpaqueOpacity;
+         for (i=0; i<number_opaque; i++)
+            colormap[n++] = opaque[i];
+
+         ping_background.index +=
+           (number_transparent + number_semitransparent);
+         
+         /* image_colors < 257; search the colormap instead of the pixels
+          * to get ping_have_color and ping_have_non_bw
+          */
+         for (i=0; i<n; i++)
+         {
+           if (ping_have_color == MagickFalse)
+             {
+                if (colormap[i].red != colormap[i].green ||
+                    colormap[i].red != colormap[i].blue)
+                  {
+                     ping_have_color=MagickTrue;
+                     ping_have_non_bw=MagickTrue;
+                     break;
                   }
+              }
 
-                q++;
+           if (ping_have_non_bw == MagickFalse)
+             {
+               if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
+                   ping_have_non_bw=MagickTrue;
              }
           }
 
+        if ((mng_info->ping_exclude_tRNS == MagickFalse ||
+            (number_transparent == 0 && number_semitransparent == 0)) &&
+            (((mng_info->write_png_colortype-1) ==
+            PNG_COLOR_TYPE_PALETTE) ||
+            (mng_info->write_png_colortype == 0)))
+          {
+            if (logging != MagickFalse)
+              {
+                if (n !=  (ssize_t) image_colors)
+                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "   image_colors (%d) and n (%d)  don't match",
+                   image_colors, n);
 
-          if (logging != MagickFalse)
+                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      AcquireImageColormap");
+              }
+
+            image->colors = image_colors;
+
+            if (AcquireImageColormap(image,image_colors) ==
+                MagickFalse)
+               ThrowWriterException(ResourceLimitError,
+                   "MemoryAllocationFailed");
+
+            for (i=0; i< (ssize_t) image_colors; i++)
+               image->colormap[i] = colormap[i];
+
+            if (logging != MagickFalse)
+              {
+                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "      image->colors=%d (%d)",
+                      (int) image->colors, image_colors);
+                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "      Update the pixel indexes");
+              }
+
+            /* Sync the pixel indices with the new colormap */
+
+            for (y=0; y < (ssize_t) image->rows; y++)
             {
-              if (image_colors >= 800)
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                       "      image has more than 800 colors");
+              q=GetAuthenticPixels(image,0,y,image->columns,1,
+                  exception);
 
-              else
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                       "      image has %d colors",image_colors);
+              if (q == (PixelPacket *) NULL)
+                break;
+
+              indexes=GetAuthenticIndexQueue(image);
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                for (i=0; i< (ssize_t) image_colors; i++)
+                {
+                  if ((image->matte == MagickFalse ||
+                      image->colormap[i].opacity == 
+                      GetOpacityPixelComponent(q)) &&
+                      image->colormap[i].red == 
+                      GetRedPixelComponent(q) &&
+                      image->colormap[i].green == 
+                      GetGreenPixelComponent(q) &&
+                      image->colormap[i].blue == 
+                      GetBluePixelComponent(q))
+                  {
+                    SetIndexPixelComponent(indexes+x,i);
+                    break;
+                  }
+                }
+                q++;
+              }
+
+              if (SyncAuthenticPixels(image,exception) == MagickFalse)
+                 break;
             }
+          }
+       }
 
-          /*
-            Initialize image colormap.
-          */
+     if (logging != MagickFalse)
+       {
+         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "      image->colors=%d", (int) image->colors);
 
-          if (logging != MagickFalse)
+         if (image->colormap != NULL)
+           {
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                   "      Sort the new colormap");
+                 "       i     (red,green,blue,opacity)");
 
-          /* Sort palette, transparent first */;
-          for (i=0; i< (ssize_t) image_colors; i++)
-          {
-             if (colormap[i].opacity == OpaqueOpacity)
-                opaque[number_opaque++] = colormap[i];
+             for (i=0; i < (ssize_t) image->colors; i++)
+             {
+               if (i < 300 || i >= (ssize_t) image->colors - 10)
+                 {
+                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                       "       %d     (%d,%d,%d,%d)",
+                        (int) i,
+                        (int) image->colormap[i].red,
+                        (int) image->colormap[i].green,
+                        (int) image->colormap[i].blue,
+                        (int) image->colormap[i].opacity);
+                 }
+             }
+           }
 
-             else if (colormap[i].opacity == TransparentOpacity)
-                transparent[number_transparent++] = colormap[i];
+           if (number_transparent < 257)
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      number_transparent     = %d",
+                   number_transparent);
+           else
 
-             else
-                semitransparent[number_semitransparent++] =
-                    colormap[i];
-          }
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      number_transparent     > 256");
+
+           if (number_opaque < 257)
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      number_opaque          = %d",
+                   number_opaque);
 
+           else
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      number_opaque          > 256");
 
-          n = 0;
+           if (number_semitransparent < 257)
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      number_semitransparent = %d",
+                   number_semitransparent);
 
-          for (i=0; i<number_transparent; i++)
-             colormap[n++] = transparent[i];
+           else
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      number_semitransparent > 256");
 
-          for (i=0; i<number_semitransparent; i++)
-             colormap[n++] = semitransparent[i];
+           if (ping_have_non_bw == MagickFalse)
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                    "      All pixels and the background are black or white");
 
-          for (i=0; i<number_opaque; i++)
-             colormap[n++] = opaque[i];
+           else if (ping_have_color == MagickFalse)
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                    "      All pixels and the background are gray");
+
+           else
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                    "      At least one pixel or the background is non-gray");
+
+           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+               "    Exit BUILD_PALETTE:");
+       }
+
+   if (mng_info->write_png8 == MagickFalse)
+      break;
+
+   /* Make any reductions necessary for the PNG8 format */
+    if (image_colors <= 256 &&
+        image_colors != 0 && image->colormap != NULL &&
+        number_semitransparent == 0 &&
+        number_transparent <= 1)
+      break;
+
+    /* PNG8 can't have semitransparent colors so we threshold the
+     * opacity to 0 or OpaqueOpacity
+     */
+    if (number_semitransparent != 0)
+      {
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    Thresholding the alpha channel to binary");
+
+        for (y=0; y < (ssize_t) image->rows; y++)
+        {
+          r=GetAuthenticPixels(image,0,y,image->columns,1,
+              exception);
+
+          if (r == (PixelPacket *) NULL)
+            break;
+
+          for (x=0; x < (ssize_t) image->columns; x++)
+          {
+              SetOpacityPixelComponent(r,
+              (GetOpacityPixelComponent(r) > TransparentOpacity/2) ?
+                   TransparentOpacity : OpaqueOpacity);
+              r++;
+          }
+  
+          if (SyncAuthenticPixels(image,exception) == MagickFalse)
+             break;
+
+          if (image_colors != 0 && image_colors <= 256 &&
+             image->colormap != NULL)
+            for (i=0; i<image_colors; i++)
+                image->colormap[i].opacity =
+                    image->colormap[i].opacity > TransparentOpacity/2 ?
+                    TransparentOpacity : OpaqueOpacity;
+        }
+      continue;
+    }
+
+    /* PNG8 can't have more than 256 colors so we quantize the pixels and
+     * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette.  If the
+     * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
+     * colors or less.
+     */
+    if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
+      {
+        if (logging != MagickFalse)
+           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+               "    Quantizing the background color to 4-4-4");
+
+        tried_444 = MagickTrue;
+
+        image->background_color.red=
+            ScaleCharToQuantum(
+            (ScaleQuantumToChar(image->background_color.red) & 0xf0) |
+            (ScaleQuantumToChar(image->background_color.red) & 0xf0) >> 4);
+        image->background_color.green=
+            ScaleCharToQuantum(
+            (ScaleQuantumToChar(image->background_color.green) & 0xf0) |
+            (ScaleQuantumToChar(image->background_color.green) & 0xf0) >> 4);
+        image->background_color.blue=
+            ScaleCharToQuantum(
+            (ScaleQuantumToChar(image->background_color.blue) & 0xf0) |
+            (ScaleQuantumToChar(image->background_color.blue) & 0xf0) >> 4);
+
+        if (logging != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "    Quantizing the pixel colors to 4-4-4");
+
+        if (image->colormap == NULL)
+        {
+          for (y=0; y < (ssize_t) image->rows; y++)
+          {
+            r=GetAuthenticPixels(image,0,y,image->columns,1,
+                exception);
 
-          if (ping_exclude_bKGD == MagickFalse)
+            if (r == (PixelPacket *) NULL)
+              break;
+
+            for (x=0; x < (ssize_t) image->columns; x++)
             {
-              /* Add the background color to the palette, if it
-               * isn't already there.
-               */
-              for (i=0; i<number_opaque; i++)
-              {
-                 if (IsColorEqual(opaque+i,
-                    &image->background_color))
-                 break;
-              }
+              if (GetOpacityPixelComponent(r) == TransparentOpacity)
+                {
+                  SetRGBPixelComponents(r,image->background_color);
+                }
+              else
+                {
+                  SetRedPixelComponent(r,ScaleCharToQuantum(
+                    (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xf0) |
+                    (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xf0) >> 4));
+                  SetGreenPixelComponent(r,ScaleCharToQuantum(
+                    (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xf0) |
+                    (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xf0) >>
+                    4));
+                  SetBluePixelComponent(r,ScaleCharToQuantum(
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xf0) |
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xf0) >>
+                    4));
+                }
+              r++;
+            }
+    
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+               break;
+          }
+        }
+
+        else /* Should not reach this; colormap already exists and
+                must be <= 256 */
+        {
+          if (logging != MagickFalse)
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "    Quantizing the colormap to 4-4-4");
+          for (i=0; i<image_colors; i++)
+          {
+            image->colormap[i].red=ScaleCharToQuantum(
+                 (ScaleQuantumToChar(image->colormap[i].red) & 0xf0) |
+                 (ScaleQuantumToChar(image->colormap[i].red) & 0xf0) >> 4);
+            image->colormap[i].green=ScaleCharToQuantum(
+                 (ScaleQuantumToChar(image->colormap[i].green) & 0xf0) |
+                 (ScaleQuantumToChar(image->colormap[i].green) & 0xf0) >> 4);
+            image->colormap[i].blue=ScaleCharToQuantum(
+                 (ScaleQuantumToChar(image->colormap[i].blue) & 0xf0) |
+                 (ScaleQuantumToChar(image->colormap[i].blue) & 0xf0 >> 4));
+          }
+        }
+        continue;
+      }
+
+    if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
+      {
+        if (logging != MagickFalse)
+           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+               "    Quantizing the background color to 3-3-3");
+
+        tried_333 = MagickTrue;
+
+        image->background_color.red=
+            ScaleCharToQuantum(
+            (ScaleQuantumToChar(image->background_color.red) & 0xe0) |
+            (ScaleQuantumToChar(image->background_color.red) & 0xe0) >> 3 |
+            (ScaleQuantumToChar(image->background_color.red) & 0xc0) >> 6);
+        image->background_color.green=
+            ScaleCharToQuantum(
+            (ScaleQuantumToChar(image->background_color.green) & 0xe0) |
+            (ScaleQuantumToChar(image->background_color.green) & 0xe0) >> 3 |
+            (ScaleQuantumToChar(image->background_color.green) & 0xc0) >> 6);
+        image->background_color.blue=
+            ScaleCharToQuantum(
+            (ScaleQuantumToChar(image->background_color.blue) & 0xe0) |
+            (ScaleQuantumToChar(image->background_color.blue) & 0xe0) >> 3 |
+            (ScaleQuantumToChar(image->background_color.blue) & 0xc0) >> 6);
+
+        if (logging != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "    Quantizing the pixel colors to 3-3-3-1");
+
+        if (image->colormap == NULL)
+        {
+          for (y=0; y < (ssize_t) image->rows; y++)
+          {
+            r=GetAuthenticPixels(image,0,y,image->columns,1,
+                exception);
 
-              if (number_opaque < 257 && i == number_opaque)
-              {
-                 opaque[i]=image->background_color;
-                 opaque[i].opacity = OpaqueOpacity;
-                 number_opaque++;
-              }
-            }
+            if (r == (PixelPacket *) NULL)
+              break;
 
-          if (number_transparent == 1)
+            for (x=0; x < (ssize_t) image->columns; x++)
             {
-              ping_trans_color.red= (unsigned short)(transparent[0].red);
-              ping_trans_color.green= (unsigned short) (transparent[0].green);
-              ping_trans_color.blue= (unsigned short) (transparent[0].blue);
-              ping_trans_color.gray= (unsigned short) (transparent[0].blue);
+              if (GetOpacityPixelComponent(r) == TransparentOpacity)
+                {
+                  SetRGBPixelComponents(r,image->background_color);
+                }
+              else
+                {
+                  SetRedPixelComponent(r,ScaleCharToQuantum(
+                    (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xe0) |
+                    (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xe0) >> 3 |
+                    (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xc0) >>
+                    6));
+                  SetGreenPixelComponent(r,ScaleCharToQuantum(
+                    (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xe0) |
+                    (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xe0) >>
+                    3 |
+                    (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xc0) >>
+                    6));
+                  SetBluePixelComponent(r,ScaleCharToQuantum(
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xe0) |
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xe0) >> 3 |
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) >>
+                    6));
+                }
+              r++;
             }
+    
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+               break;
+          }
+        }
 
+        else /* Should not reach this; colormap already exists and
+                must be <= 256 */
+        {
           if (logging != MagickFalse)
-            {
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "      number_transparent     = %d",
-                    number_transparent);
-
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "      number_opaque          = %d",
-                    number_opaque);
-
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "      number_semitransparent = %d",
-                    number_semitransparent);
-            }
-
-          if ((mng_info->ping_exclude_tRNS == MagickFalse ||
-              (number_transparent == 0 && number_semitransparent == 0)) &&
-              (((mng_info->write_png_colortype-1) == PNG_COLOR_TYPE_PALETTE) ||
-              (mng_info->write_png_colortype == 0)))
+              "    Quantizing the colormap to 3-3-3-1");
+          for (i=0; i<image_colors; i++)
           {
-             if (logging != MagickFalse)
-               {
-                 if (n !=  (ssize_t) image_colors)
-                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "   image_colors (%d) and n (%d)  don't match",
-                    image_colors, n);
-
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "      AcquireImageColormap");
-                }
-
-          image->colors = image_colors;
+              image->colormap[i].red=ScaleCharToQuantum(
+                   (ScaleQuantumToChar(image->colormap[i].red) & 0xe0) |
+                   (ScaleQuantumToChar(image->colormap[i].red) & 0xe0) >> 3 |
+                   (ScaleQuantumToChar(image->colormap[i].red) & 0xc0) >> 6);
+              image->colormap[i].green=ScaleCharToQuantum(
+                   (ScaleQuantumToChar(image->colormap[i].green) & 0xe0) |
+                   (ScaleQuantumToChar(image->colormap[i].green) & 0xe0) >> 3 |
+                   (ScaleQuantumToChar(image->colormap[i].green) & 0xc0) >> 6);
+              image->colormap[i].blue=ScaleCharToQuantum(
+                   (ScaleQuantumToChar(image->colormap[i].blue) & 0xe0) |
+                   (ScaleQuantumToChar(image->colormap[i].blue) & 0xe0) >> 3 |
+                   (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) >> 6);
+          }
+        }
+        continue;
+      }
 
-          if (AcquireImageColormap(image,image_colors) ==
-              MagickFalse)
-             ThrowWriterException(ResourceLimitError,
-                "MemoryAllocationFailed");
+    if (image_colors == 0 || image_colors > 256)
+      {
+        if (logging != MagickFalse)
+           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+               "    Quantizing the background color to 3-3-2");
 
-          for (i=0; i< (ssize_t) image_colors; i++)
-             image->colormap[i] = colormap[i];
+        /* Red and green were already done so we only quantize the blue
+         * channel
+         */
 
-          if (logging != MagickFalse)
-            {
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "      image->colors=%d (%d)",
-                    (int) image->colors, image_colors);
+        image->background_color.blue=ScaleCharToQuantum(
+            (ScaleQuantumToChar(image->background_color.blue) & 0xc0) |
+            (ScaleQuantumToChar(image->background_color.blue) & 0xc0) >> 2 |
+            (ScaleQuantumToChar(image->background_color.blue) & 0xc0) >> 4 |
+            (ScaleQuantumToChar(image->background_color.blue) & 0xc0) >> 6);
 
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "      Update the pixel indexes");
-            }
+        if (logging != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "    Quantizing the pixel colors to 3-3-2-1");
 
+        if (image->colormap == NULL)
+        {
           for (y=0; y < (ssize_t) image->rows; y++)
           {
-            q=GetAuthenticPixels(image,0,y,image->columns,1,
+            r=GetAuthenticPixels(image,0,y,image->columns,1,
                 exception);
 
-            if (q == (PixelPacket *) NULL)
+            if (r == (PixelPacket *) NULL)
               break;
 
-            indexes=GetAuthenticIndexQueue(image);
-
             for (x=0; x < (ssize_t) image->columns; x++)
             {
-              for (i=0; i< (ssize_t) image_colors; i++)
-              {
-                if ((image->matte == MagickFalse ||
-                    image->colormap[i].opacity == q->opacity) &&
-                    (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
+              if (GetOpacityPixelComponent(r) == TransparentOpacity)
                 {
-                  indexes[x]=(IndexPacket) i;
-                  break;
+                  SetRGBPixelComponents(r,image->background_color);
                 }
-              }
-              q++;
+              else
+                {
+                  SetBluePixelComponent(r,ScaleCharToQuantum(
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) |
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) >> 2 |
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) >> 4 |
+                    (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) >>
+                    6));
+                }
+              r++;
             }
-
+    
             if (SyncAuthenticPixels(image,exception) == MagickFalse)
                break;
-         }
-       }
-
-       if (logging != MagickFalse)
-         {
-           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "      image->colors=%d", (int) image->colors);
-
-           if (image->colormap != NULL)
-             {
-               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                   "       i     (red,green,blue,opacity)");
-
-               for (i=0; i < (ssize_t) image->colors; i++)
-               {
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                     "       %d     (%d,%d,%d,%d)",
-                      (int) i,
-                      (int) image->colormap[i].red,
-                      (int) image->colormap[i].green,
-                      (int) image->colormap[i].blue,
-                      (int) image->colormap[i].opacity);
-               }
-             }
+          }
+        }
 
-           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "    Exit BUILD_PALETTE:");
-         }
+        else /* Should not reach this; colormap already exists and
+                must be <= 256 */
+        {
+          if (logging != MagickFalse)
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "    Quantizing the colormap to 3-3-2-1");
+          for (i=0; i<image_colors; i++)
+          {
+              image->colormap[i].blue=ScaleCharToQuantum(
+                  (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) |
+                  (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) >> 2 |
+                  (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) >> 4 |
+                  (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) >> 6);
+          }
+      }
+      continue;
     }
-#endif /* PNG_BUILD_PALETTE */
+    break;
+  }
+  /* END OF BUILD_PALETTE */
 
+  /* If we are excluding the tRNS chunk and there is transparency,
+   * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
+   * PNG.
+   */
   if (mng_info->ping_exclude_tRNS != MagickFalse &&
      (number_transparent != 0 || number_semitransparent != 0))
     {
-      int colortype=mng_info->write_png_colortype;
+      unsigned int colortype=mng_info->write_png_colortype;
 
       if (ping_have_color == MagickFalse)
         mng_info->write_png_colortype = 5;
@@ -7304,11 +8048,96 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
       else
         mng_info->write_png_colortype = 7;
 
-      if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
+      if (colortype != 0 &&
+         mng_info->write_png_colortype != colortype)
         ping_need_colortype_warning=MagickTrue;
 
     }
 
+  /* See if cheap transparency is possible.  It is only possible
+   * when there is a single transparent color, no semitransparent
+   * color, and no opaque color that has the same RGB components
+   * as the transparent color.  We only need this information if
+   * we are writing a PNG with colortype 0 or 2, and we have not
+   * excluded the tRNS chunk.
+   */
+  if (number_transparent == 1 &&
+      mng_info->write_png_colortype < 4)
+    {
+       ping_have_cheap_transparency = MagickTrue;
+
+       if (number_semitransparent != 0)
+         ping_have_cheap_transparency = MagickFalse;
+
+       else if (image_colors == 0 || image_colors > 256 ||
+           image->colormap == NULL)
+         {
+           ExceptionInfo
+             *exception;
+
+           register const PixelPacket
+             *q;
+
+           exception=(&image->exception);
+
+           for (y=0; y < (ssize_t) image->rows; y++)
+           {
+             q=GetVirtualPixels(image,0,y,image->columns,1, exception);
+
+             if (q == (PixelPacket *) NULL)
+               break;
+
+             for (x=0; x < (ssize_t) image->columns; x++)
+             {
+                 if (q->opacity != TransparentOpacity &&
+                     (unsigned short) GetRedPixelComponent(q) ==
+                     ping_trans_color.red &&
+                     (unsigned short) GetGreenPixelComponent(q) ==
+                     ping_trans_color.green &&
+                     (unsigned short) GetBluePixelComponent(q) ==
+                     ping_trans_color.blue)
+                   {
+                     ping_have_cheap_transparency = MagickFalse;
+                     break;
+                   }
+
+                 q++;
+             }
+    
+             if (ping_have_cheap_transparency == MagickFalse)
+                break;
+           }
+         }
+       else
+         {
+            /* Assuming that image->colormap[0] is the one transparent color
+             * and that all others are opaque.
+             */
+            if (image_colors > 1)
+              for (i=1; i<image_colors; i++)
+                if (image->colormap[i].red == image->colormap[0].red &&
+                    image->colormap[i].green == image->colormap[0].green &&
+                    image->colormap[i].blue == image->colormap[0].blue)
+                  {
+                     ping_have_cheap_transparency = MagickFalse;
+                     break;
+                  }
+         }
+       
+       if (logging != MagickFalse)
+         {
+           if (ping_have_cheap_transparency == MagickFalse)
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                 "   Cheap transparency is not possible.");
+
+           else
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                 "   Cheap transparency is possible.");
+         }
+     }
+  else
+    ping_have_cheap_transparency = MagickFalse;
+
   image_depth=image->depth;
 
   quantum_info = (QuantumInfo *) NULL;
@@ -7317,19 +8146,34 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   image_matte=image->matte;
 
   mng_info->IsPalette=image->storage_class == PseudoClass &&
-    image_colors <= 256;
+    image_colors <= 256 && image->colormap != NULL;
+
+  if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
+     (image->colors == 0 || image->colormap == NULL))
+    {
+      image_info=DestroyImageInfo(image_info);
+      image=DestroyImage(image);
+      (void) ThrowMagickException(&IMimage->exception,
+          GetMagickModule(),CoderError,
+          "Cannot write PNG8 or color-type 3; colormap is NULL",
+          "`%s'",IMimage->filename);
+#if defined(PNG_SETJMP_NOT_THREAD_SAFE)
+      UnlockSemaphoreInfo(ping_semaphore);
+#endif
+      return(MagickFalse);
+    }
 
   /*
     Allocate the PNG structures
   */
 #ifdef PNG_USER_MEM_SUPPORTED
   ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image,
-    PNGErrorHandler,PNGWarningHandler,(void *) NULL,
-    (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free);
+    MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
+    (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
 
 #else
   ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image,
-    PNGErrorHandler,PNGWarningHandler);
+    MagickPNGErrorHandler,MagickPNGWarningHandler);
 
 #endif
   if (ping == (png_struct *) NULL)
@@ -7344,7 +8188,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     }
 
   png_set_write_fn(ping,image,png_put_data,png_flush_data);
-  png_pixels=(unsigned char *) NULL;
+  ping_pixels=(unsigned char *) NULL;
 
   if (setjmp(png_jmpbuf(ping)))
     {
@@ -7357,9 +8201,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 #endif
       png_destroy_write_struct(&ping,&ping_info);
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-      UnlockSemaphoreInfo(png_semaphore);
+      UnlockSemaphoreInfo(ping_semaphore);
 #endif
-      if (mng_info->need_blob != MagickFalse)
+      if (ping_have_blob != MagickFalse)
           (void) CloseBlob(image);
       image_info=DestroyImageInfo(image_info);
       image=DestroyImage(image);
@@ -7432,15 +8276,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
       if (image->units == PixelsPerInchResolution)
         {
           ping_pHYs_unit_type=PNG_RESOLUTION_METER;
-          ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
-          ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
+          ping_pHYs_x_resolution=
+             (png_uint_32) ((100.0*image->x_resolution+0.5)/2.54);
+          ping_pHYs_y_resolution=
+             (png_uint_32) ((100.0*image->y_resolution+0.5)/2.54);
         }
 
       else if (image->units == PixelsPerCentimeterResolution)
         {
           ping_pHYs_unit_type=PNG_RESOLUTION_METER;
-          ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
-          ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
+          ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution+0.5);
+          ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution+0.5);
         }
 
       else
@@ -7450,6 +8296,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
         }
 
+      if (logging != MagickFalse)
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
+          (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
+          (int) ping_pHYs_unit_type);
        ping_have_pHYs = MagickTrue;
     }
   }
@@ -7483,12 +8334,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
        ping_background.blue=(png_uint_16)
          (ScaleQuantumToShort(image->background_color.blue) & mask);
+
+       ping_background.gray=(png_uint_16) ping_background.green;
     }
 
   if (logging != MagickFalse)
     {
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "    Setting up bKGD chunk (1)");
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "      background_color index is %d",
+          (int) ping_background.index);
 
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "    ping_bit_depth=%d",ping_bit_depth);
@@ -7503,10 +8359,10 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   matte=image_matte;
   old_bit_depth=0;
 
-  if (mng_info->write_png8)
+  if (mng_info->IsPalette && mng_info->write_png8)
     {
 
-      /* TO DO: make this a function cause it's used twice, except
+      /* To do: make this a function cause it's used twice, except
          for reducing the sample depth from 8. */
 
       number_colors=image_colors;
@@ -7554,12 +8410,6 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           for (i=0; i < (ssize_t) number_transparent; i++)
              ping_trans_alpha[i]=0;
 
-          /* PNG8 can't have semitransparent colors so we threshold them
-           * to 0 or 255
-           */
-          for (; i < (ssize_t) number_semitransparent; i++)
-             ping_trans_alpha[i]=image->colormap[i].opacity >
-                OpaqueOpacity/2 ? 0 : 255;
 
           ping_num_trans=(unsigned short) (number_transparent +
              number_semitransparent);
@@ -7571,16 +8421,24 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
              ping_have_tRNS=MagickTrue;
       }
 
-    if (ping_exclude_bKGD == MagickFalse)
+      if (ping_exclude_bKGD == MagickFalse)
       {
-        /*
-         * Identify which colormap entry is the background color.
-         */
+       /*
+        * Identify which colormap entry is the background color.
+        */
+
         for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
           if (IsPNGColorEqual(ping_background,image->colormap[i]))
             break;
 
         ping_background.index=(png_byte) i;
+
+        if (logging != MagickFalse)
+          {
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                 "      background_color index is %d",
+                 (int) ping_background.index);
+          }
       }
     } /* end of write_png8 */
 
@@ -7610,9 +8468,13 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
           else
             image_matte=MagickFalse;
+
+          if (logging != MagickFalse)
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             "   PNG colortype %d was specified:",(int) ping_color_type);
         }
 
-      else /* write_ping_colortype not specified */
+      else /* write_png_colortype not specified */
         {
           if (logging != MagickFalse)
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -7637,8 +8499,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
               image_info->type == PaletteMatteType)
             ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
 
-          if (image_info->type == UndefinedType ||
-             image_info->type == OptimizeType)
+          if (mng_info->write_png_colortype == 0 &&
+             (image_info->type == UndefinedType ||
+             image_info->type == OptimizeType))
             {
               if (ping_have_color == MagickFalse)
                 {
@@ -7688,13 +8551,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
       if (ping_color_type == PNG_COLOR_TYPE_GRAY)
         {
-          if (image->matte == MagickFalse && image->colors < 256)
-            {
-              if (ImageIsMonochrome(image))
-                {
-                  ping_bit_depth=1;
-                }
-            }
+          if (image->matte == MagickFalse && ping_have_non_bw == MagickFalse)
+             ping_bit_depth=1;
         }
 
       if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
@@ -7752,11 +8610,13 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     {
       if (mng_info->IsPalette)
         {
+          if (mng_info->write_png_colortype == 0)
+            {
+              ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
 
-          ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
-
-          if (ping_have_color != MagickFalse)
-             ping_color_type=PNG_COLOR_TYPE_RGBA;
+              if (ping_have_color != MagickFalse)
+                 ping_color_type=PNG_COLOR_TYPE_RGBA;
+            }
 
           /*
            * Determine if there is any transparent color.
@@ -7766,14 +8626,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
               /*
                 No transparent pixels are present.  Change 4 or 6 to 0 or 2.
               */
+
               image_matte=MagickFalse;
-              ping_color_type&=0x03;
+
+              if (mng_info->write_png_colortype == 0)
+                ping_color_type&=0x03;
             }
 
           else
             {
               unsigned int
-                mask;
+                mask; 
 
               mask=0xffff;
 
@@ -7810,35 +8673,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           if (ping_have_tRNS != MagickFalse)
             {
               /*
-                Determine if there is one and only one transparent color
-                and if so if it is fully transparent.
-              */
-              if (logging != MagickFalse)
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "  Is there a single fully transparent color?");
-
-              if (number_transparent > 1 || number_semitransparent > 0)
-              {
-                ping_have_tRNS = MagickFalse;
-                if (logging != MagickFalse)
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "  ... No.");
-              }
-              else
-              {
-                if (logging != MagickFalse)
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "  ... Yes: (%d,%d,%d), (gray: %d)",
-                    (int) ping_trans_color.red,
-                    (int) ping_trans_color.green,
-                    (int) ping_trans_color.blue,
-                    (int) ping_trans_color.gray);
-              }
+               * Determine if there is one and only one transparent color
+               * and if so if it is fully transparent.
+               */
+              if (ping_have_cheap_transparency == MagickFalse)
+                ping_have_tRNS=MagickFalse;
             }
 
           if (ping_have_tRNS != MagickFalse)
             {
-              ping_color_type &= 0x03;  /* changes 4 or 6 to 0 or 2 */
+              if (mng_info->write_png_colortype == 0)
+                ping_color_type &= 0x03;  /* changes 4 or 6 to 0 or 2 */
 
               if (image_depth == 8)
                 {
@@ -7868,14 +8713,15 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
     if ((mng_info->IsPalette) &&
         mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
-        ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
+        ping_have_color == MagickFalse &&
+        (image_matte == MagickFalse || image_depth >= 8))
       {
         size_t one=1;
 
         if (image_matte != MagickFalse)
           ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
 
-        else
+        else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
           {
             ping_color_type=PNG_COLOR_TYPE_GRAY;
 
@@ -7893,7 +8739,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
         if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
           image_depth=MAGICKCORE_QUANTUM_DEPTH;
 
-        if (image_colors == 0 || image_colors-1 > MaxColormapSize)
+        if ((image_colors == 0) ||
+             ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
           image_colors=(int) (one << image_depth);
 
         if (image_depth > 8)
@@ -7918,8 +8765,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
                 mng_info->IsPalette)
               {
-
               /* Check if grayscale is reducible */
+
                 int
                   depth_4_ok=MagickTrue,
                   depth_2_ok=MagickTrue,
@@ -7934,10 +8781,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
                    if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
                      depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
-
                    else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
                      depth_2_ok=depth_1_ok=MagickFalse;
-
                    else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
                      depth_1_ok=MagickFalse;
                 }
@@ -8004,7 +8849,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                 ping_bit_depth=1;
                 one=1;
 
-                while ((one << ping_bit_depth) < number_colors)
+                while ((one << ping_bit_depth) < (ssize_t) number_colors)
                   ping_bit_depth <<= 1;
               }
 
@@ -8101,6 +8946,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
          if (logging != MagickFalse)
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
              "  Setting up bKGD chunk (2)");
+         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             "      background_color index is %d",
+             (int) ping_background.index);
 
          ping_have_bKGD = MagickTrue;
          }
@@ -8111,7 +8959,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
   if (ping_exclude_bKGD == MagickFalse)
   {
-    if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
+    if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
       {
         /*
            Identify which colormap entry is the background color.
@@ -8258,7 +9106,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
   }
 
-  if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
+  if ((ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse) &&
+     (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
     {
       ResetImageProfileIterator(image);
       for (name=GetNextImageProfile(image); name != (const char *) NULL; )
@@ -8288,7 +9137,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 #endif
               if (ping_exclude_zCCP == MagickFalse)
                 {
-                  png_write_raw_profile(image_info,ping,ping_info,
+                  Magick_png_write_raw_profile(image_info,ping,ping_info,
                     (unsigned char *) name,(unsigned char *) name,
                     GetStringInfoDatum(profile),
                     (png_uint_32) GetStringInfoLength(profile));
@@ -8318,8 +9167,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                 "  Setting up sRGB chunk");
 
           (void) png_set_sRGB(ping,ping_info,(
-            PNG_RenderingIntent_from_Magick_RenderingIntent(
-            image->rendering_intent)));
+            Magick_RenderingIntent_to_PNG_RenderingIntent(
+              image->rendering_intent)));
 
           if (ping_exclude_gAMA == MagickFalse)
             png_set_gAMA(ping,ping_info,0.45455);
@@ -8387,7 +9236,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   if (mng_info->write_png_colortype != 0)
     {
      if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
-       if (ImageIsGray(image) == MagickFalse)
+       if (ping_have_color != MagickFalse)
          {
            ping_color_type = PNG_COLOR_TYPE_RGB;
 
@@ -8396,7 +9245,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
          }
 
      if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
-       if (ImageIsGray(image) == MagickFalse)
+       if (ping_have_color != MagickFalse)
          ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
     }
 
@@ -8448,10 +9297,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           "  Added an opaque matte channel");
     }
 
-  if (image->matte == MagickTrue)
+  if (number_transparent != 0 || number_semitransparent != 0)
     {
       if (ping_color_type < 4)
-        if (ping_color_type != 3 || ping_num_trans > 0)
         {
            ping_have_tRNS=MagickTrue;
            if (logging != MagickFalse)
@@ -8500,7 +9348,23 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   if (ping_exclude_bKGD == MagickFalse)
     {
       if (ping_have_bKGD != MagickFalse)
+        {
           png_set_bKGD(ping,ping_info,&ping_background);
+          if (logging)
+            {
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "    Setting up bKGD chunk");
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      background color = (%d,%d,%d)",
+                        (int) ping_background.red,
+                        (int) ping_background.green,
+                        (int) ping_background.blue);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      index = %d, gray=%d",
+                        (int) ping_background.index,
+                        (int) ping_background.gray);
+            }
+         }
     }
 
   if (ping_exclude_pHYs == MagickFalse)
@@ -8511,6 +9375,21 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
              ping_pHYs_x_resolution,
              ping_pHYs_y_resolution,
              ping_pHYs_unit_type);
+
+          if (logging)
+            {
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "    Setting up pHYs chunk");
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      x_resolution=%lu",
+                   (unsigned long) ping_pHYs_x_resolution);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      y_resolution=%lu",
+                   (unsigned long) ping_pHYs_y_resolution);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "      unit_type=%lu",
+                   (unsigned long) ping_pHYs_unit_type);
+            }
         }
     }
 
@@ -8530,6 +9409,15 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     }
 #endif
 
+  if (mng_info->need_blob != MagickFalse)
+  {
+    if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
+       MagickFalse)
+       png_error(ping,"WriteBlob Failed");
+
+     ping_have_blob=MagickTrue;
+  }
+
   png_write_info_before_PLTE(ping, ping_info);
 
   if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
@@ -8565,11 +9453,12 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     }
 
   /* write any png-chunk-b profiles */
-  (void) png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
+  (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
+
   png_write_info(ping,ping_info);
 
   /* write any PNG-chunk-m profiles */
-  (void) png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
+  (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
 
   if (ping_exclude_vpAg == MagickFalse)
     {
@@ -8630,10 +9519,10 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
         "    Allocating %.20g bytes of memory for pixels",(double) rowbytes);
     }
-  png_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
-    sizeof(*png_pixels));
+  ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
+    sizeof(*ping_pixels));
 
-  if (png_pixels == (unsigned char *) NULL)
+  if (ping_pixels == (unsigned char *) NULL)
     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
 
   /*
@@ -8651,12 +9540,12 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
       png_destroy_write_struct(&ping,&ping_info);
       if (quantum_info != (QuantumInfo *) NULL)
         quantum_info=DestroyQuantumInfo(quantum_info);
-      if (png_pixels != (unsigned char *) NULL)
-        png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
+      if (ping_pixels != (unsigned char *) NULL)
+        ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-      UnlockSemaphoreInfo(png_semaphore);
+      UnlockSemaphoreInfo(ping_semaphore);
 #endif
-      if (mng_info->need_blob != MagickFalse)
+      if (ping_have_blob != MagickFalse)
           (void) CloseBlob(image);
       image_info=DestroyImageInfo(image_info);
       image=DestroyImage(image);
@@ -8673,7 +9562,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
        !mng_info->write_png32) &&
        (mng_info->IsPalette ||
        (image_info->type == BilevelType)) &&
-       image_matte == MagickFalse && ImageIsMonochrome(image))
+       image_matte == MagickFalse &&
+       ping_have_non_bw == MagickFalse)
     {
       /* Palette, Bilevel, or Opaque Monochrome */
       register const PixelPacket
@@ -8687,8 +9577,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
         */
         for (y=0; y < (ssize_t) image->rows; y++)
         {
-
-          if (logging != MagickFalse)
+          if (logging != MagickFalse && y == 0)
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                  "    Writing row of pixels (0)");
 
@@ -8700,14 +9589,14 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           if (mng_info->IsPalette)
             {
               (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                quantum_info,GrayQuantum,png_pixels,&image->exception);
+                quantum_info,GrayQuantum,ping_pixels,&image->exception);
               if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
                   mng_info->write_png_depth &&
                   mng_info->write_png_depth != old_bit_depth)
                 {
                   /* Undo pixel scaling */
                   for (i=0; i < (ssize_t) image->columns; i++)
-                     *(png_pixels+i)=(unsigned char) (*(png_pixels+i)
+                     *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
                      >> (8-old_bit_depth));
                 }
             }
@@ -8715,19 +9604,19 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           else
             {
               (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                quantum_info,RedQuantum,png_pixels,&image->exception);
+                quantum_info,RedQuantum,ping_pixels,&image->exception);
             }
 
           if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
             for (i=0; i < (ssize_t) image->columns; i++)
-               *(png_pixels+i)=(unsigned char) ((*(png_pixels+i) > 127) ?
+               *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
                       255 : 0);
 
           if (logging != MagickFalse && y == 0)
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                 "    Writing row of pixels (1)");
 
-          png_write_row(ping,png_pixels);
+          png_write_row(ping,ping_pixels);
         }
         if (image->previous == (Image *) NULL)
           {
@@ -8744,7 +9633,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
          !mng_info->write_png32) &&
          (image_matte != MagickFalse ||
          (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
-         (mng_info->IsPalette) && ImageIsGray(image))
+         (mng_info->IsPalette) && ping_have_color == MagickFalse)
         {
           register const PixelPacket
             *p;
@@ -8763,11 +9652,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
               {
                 if (mng_info->IsPalette)
                   (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                    quantum_info,GrayQuantum,png_pixels,&image->exception);
+                    quantum_info,GrayQuantum,ping_pixels,&image->exception);
 
                 else
                   (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                    quantum_info,RedQuantum,png_pixels,&image->exception);
+                    quantum_info,RedQuantum,ping_pixels,&image->exception);
 
                 if (logging != MagickFalse && y == 0)
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -8781,14 +9670,14 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                          "    Writing GRAY_ALPHA PNG pixels (2)");
 
                 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                  quantum_info,GrayAlphaQuantum,png_pixels,&image->exception);
+                  quantum_info,GrayAlphaQuantum,ping_pixels,&image->exception);
               }
 
             if (logging != MagickFalse && y == 0)
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                   "    Writing row of pixels (2)");
 
-            png_write_row(ping,png_pixels);
+            png_write_row(ping,ping_pixels);
           }
 
           if (image->previous == (Image *) NULL)
@@ -8823,17 +9712,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                   {
                     if (image->storage_class == DirectClass)
                       (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                        quantum_info,RedQuantum,png_pixels,&image->exception);
+                        quantum_info,RedQuantum,ping_pixels,&image->exception);
 
                     else
                       (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                        quantum_info,GrayQuantum,png_pixels,&image->exception);
+                        quantum_info,GrayQuantum,ping_pixels,&image->exception);
                   }
 
                 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
                   {
                     (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                      quantum_info,GrayAlphaQuantum,png_pixels,
+                      quantum_info,GrayAlphaQuantum,ping_pixels,
                       &image->exception);
 
                     if (logging != MagickFalse && y == 0)
@@ -8843,17 +9732,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
                 else if (image_matte != MagickFalse)
                   (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                    quantum_info,RGBAQuantum,png_pixels,&image->exception);
+                    quantum_info,RGBAQuantum,ping_pixels,&image->exception);
 
                 else
                   (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                    quantum_info,RGBQuantum,png_pixels,&image->exception);
+                    quantum_info,RGBQuantum,ping_pixels,&image->exception);
 
                 if (logging != MagickFalse && y == 0)
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                       "    Writing row of pixels (3)");
 
-                png_write_row(ping,png_pixels);
+                png_write_row(ping,ping_pixels);
               }
             }
 
@@ -8879,14 +9768,19 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                     "  pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
 
-                p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+                p=GetVirtualPixels(image,0,y,image->columns,1,
+                   &image->exception);
 
                 if (p == (const PixelPacket *) NULL)
                   break;
 
                 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
-                  (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                       quantum_info,GrayQuantum,png_pixels,&image->exception);
+                  {
+                    quantum_info->depth=image->depth;
+
+                    (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                       quantum_info,GrayQuantum,ping_pixels,&image->exception);
+                  }
 
                 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
                   {
@@ -8895,24 +9789,26 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                            "  Writing GRAY_ALPHA PNG pixels (4)");
 
                     (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                         quantum_info,GrayAlphaQuantum,png_pixels,
+                         quantum_info,GrayAlphaQuantum,ping_pixels,
                          &image->exception);
                   }
 
                 else
-                  (void) ExportQuantumPixels(image,(const CacheView *) NULL,
-                    quantum_info,IndexQuantum,png_pixels,&image->exception);
-
-                  if (logging != MagickFalse && y <= 2)
                   {
-                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                        "  Writing row of pixels (4)");
+                    (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                      quantum_info,IndexQuantum,ping_pixels,&image->exception);
 
-                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                        "  png_pixels[0]=%d,png_pixels[1]=%d",
-                        (int)png_pixels[0],(int)png_pixels[1]);
+                    if (logging != MagickFalse && y <= 2)
+                    {
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "  Writing row of non-gray pixels (4)");
+
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "  ping_pixels[0]=%d,ping_pixels[1]=%d",
+                          (int)ping_pixels[0],(int)ping_pixels[1]);
+                    }
                   }
-                png_write_row(ping,png_pixels);
+                png_write_row(ping,ping_pixels);
               }
             }
 
@@ -8962,9 +9858,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
         "    PNG Interlace method: %d",ping_interlace_method);
     }
   /*
-    Generate text chunks.
+    Generate text chunks after IDAT.
   */
-  if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
+  if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
   {
     ResetImagePropertyIterator(image);
     property=GetNextImageProperty(image);
@@ -8974,45 +9870,59 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
         text;
 
       value=GetImageProperty(image,property);
-      if (value != (const char *) NULL)
-        {
-          text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
-          text[0].key=(char *) property;
-          text[0].text=(char *) value;
-          text[0].text_length=strlen(value);
 
-          if (ping_exclude_tEXt != MagickFalse)
-             text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
+      /* Don't write any "png:" properties; those are just for "identify" */
+      if (LocaleNCompare(property,"png:",4) != 0 &&
 
-          else if (ping_exclude_zTXt != MagickFalse)
-             text[0].compression=PNG_TEXT_COMPRESSION_NONE;
+          /* Suppress density and units if we wrote a pHYs chunk */
+          (ping_exclude_pHYs != MagickFalse      ||
+          LocaleCompare(property,"density") != 0 ||
+          LocaleCompare(property,"units") != 0) &&
 
-          else
+          /* Suppress the IM-generated Date:create and Date:modify */
+          (ping_exclude_date == MagickFalse      ||
+          LocaleNCompare(property, "Date:",5) != 0))
+        {
+        if (value != (const char *) NULL)
           {
-             text[0].compression=image_info->compression == NoCompression ||
-               (image_info->compression == UndefinedCompression &&
-               text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
-               PNG_TEXT_COMPRESSION_zTXt ;
-          }
+            text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
+            text[0].key=(char *) property;
+            text[0].text=(char *) value;
+            text[0].text_length=strlen(value);
 
-          if (logging != MagickFalse)
-            {
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "  Setting up text chunk");
+            if (ping_exclude_tEXt != MagickFalse)
+               text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
 
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "    keyword: %s",text[0].key);
+            else if (ping_exclude_zTXt != MagickFalse)
+               text[0].compression=PNG_TEXT_COMPRESSION_NONE;
+
+            else
+            {
+               text[0].compression=image_info->compression == NoCompression ||
+                 (image_info->compression == UndefinedCompression &&
+                 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
+                 PNG_TEXT_COMPRESSION_zTXt ;
             }
 
-          png_set_text(ping,ping_info,text,1);
-          png_free(ping,text);
+            if (logging != MagickFalse)
+              {
+                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "  Setting up text chunk");
+
+                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "    keyword: %s",text[0].key);
+              }
+
+            png_set_text(ping,ping_info,text,1);
+            png_free(ping,text);
+          }
         }
       property=GetNextImageProperty(image);
     }
   }
 
   /* write any PNG-chunk-e profiles */
-  (void) png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
+  (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
 
   if (logging != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -9070,13 +9980,13 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
   png_destroy_write_struct(&ping,&ping_info);
 
-  png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
+  ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
 
 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
-  UnlockSemaphoreInfo(png_semaphore);
+  UnlockSemaphoreInfo(ping_semaphore);
 #endif
 
-  if (mng_info->need_blob != MagickFalse)
+  if (ping_have_blob != MagickFalse)
      (void) CloseBlob(image);
 
   image_info=DestroyImageInfo(image_info);
@@ -9130,22 +10040,38 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %  be given the "png" file extension, this method also writes the following
 %  pseudo-formats which are subsets of PNG:
 %
-%    o PNG8:    An 8-bit indexed PNG datastream is written.  If transparency
+%    o PNG8:    An 8-bit indexed PNG datastream is written.  If the image has
+%               a depth greater than 8, the depth is reduced. If transparency
 %               is present, the tRNS chunk must only have values 0 and 255
 %               (i.e., transparency is binary: fully opaque or fully
-%               transparent).  The pixels contain 8-bit indices even if
-%               they could be represented with 1, 2, or 4 bits. Note: grayscale
+%               transparent).  If other values are present they will be
+%               50%-thresholded to binary transparency.  If more than 256
+%               colors are present, they will be quantized to the 4-4-4-1,
+%               3-3-3-1, or  3-3-2-1 palette.
+%
+%               If you want better quantization or dithering of the colors
+%               or alpha than that, you need to do it before calling the
+%               PNG encoder. The pixels contain 8-bit indices even if
+%               they could be represented with 1, 2, or 4 bits.  Grayscale
 %               images will be written as indexed PNG files even though the
-%               PNG grayscale type might be slightly more efficient.
+%               PNG grayscale type might be slightly more efficient.  Please
+%               note that writing to the PNG8 format may result in loss
+%               of color and alpha data.
 %
 %    o PNG24:   An 8-bit per sample RGB PNG datastream is written.  The tRNS
 %               chunk can be present to convey binary transparency by naming
-%               one of the colors as transparent.
+%               one of the colors as transparent.  The only loss incurred
+%               is reduction of sample depth to 8.  If the image has more
+%               than one transparent color, has semitransparent pixels, or
+%               has an opaque pixel with the same RGB components as the
+%               transparent color, an image is not written.
 %
 %    o PNG32:   An 8-bit per sample RGBA PNG is written.  Partial
 %               transparency is permitted, i.e., the alpha sample for
 %               each pixel can have any value from 0 to 255. The alpha
 %               channel is present even if the image is fully opaque.
+%               The only loss in data is the reduction of the sample depth
+%               to 8.
 %
 %    o -define: For more precise control of the PNG output, you can use the
 %               Image options "png:bit-depth" and "png:color-type".  These
@@ -9170,16 +10096,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %               When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
 %               png:bit-depth can be 8 or 16.
 %
-%  If the image cannot be written without loss in the requested PNG8, PNG24,
-%  or PNG32 format or with the requested bit-depth and color-type without loss,
-%  a PNG file will not be written, and the encoder will return MagickFalse.
+%  If the image cannot be written without loss with the requested bit-depth
+%  and color-type, a PNG file will not be written, and the encoder will
+%  return MagickFalse.
+%
 %  Since image encoders should not be responsible for the "heavy lifting",
 %  the user should make sure that ImageMagick has already reduced the
 %  image depth and number of colors and limit transparency to binary
-%  transparency prior to attempting to write the image in a format that
-%  is subject to depth, color, or transparency limitations.
+%  transparency prior to attempting to write the image with depth, color,
+%   or transparency limitations.
 %
-%  TODO: Enforce the previous paragraph.
+%  To do: Enforce the previous paragraph.
 %
 %  Note that another definition, "png:bit-depth-written" exists, but it
 %  is not intended for external use.  It is only used internally by the
@@ -9210,7 +10137,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %   o  16-bit depth is reduced to 8 if all pixels contain samples whose
 %      high byte and low byte are identical.
 %   o  Palette is sorted to remove unused entries and to put a
-%      transparent color first, if PNG_BUILD_PALETTE is defined.
+%      transparent color first, if BUILD_PNG_PALETTE is defined.
 %   o  Opaque matte channel is removed when writing an indexed PNG.
 %   o  Grayscale images are reduced to 1, 2, or 4 bit depth if
 %      this can be done without loss and a larger bit depth N was not
@@ -9249,7 +10176,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
+  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
   /*
     Allocate a MngInfo structure.
   */
@@ -9373,7 +10300,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
 
   /* Check for chunks to be excluded:
    *
-   * The default is to not exclude any chunks except for any
+   * The default is to not exclude any known chunks except for any
    * listed in the "unused_chunks" array, above.
    *
    * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
@@ -9387,7 +10314,10 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
    * A "PNG:include-chunk" define takes  priority over both the
    * mng_info and the "PNG:exclude-chunk" define.  Like the
    * "exclude-chunk" string, it can define "all" or "none" as
-   * well as a comma-separated list.
+   * well as a comma-separated list.  Chunks that are unknown to
+   * ImageMagick are always excluded, regardless of their "copy-safe"
+   * status according to the PNG specification, and even if they
+   * appear in the "include-chunk" list.
    *
    * Finally, all chunks listed in the "unused_chunks" array are
    * automatically excluded, regardless of the other instructions
@@ -9406,9 +10336,9 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
 
   mng_info->ping_exclude_bKGD=MagickFalse;
   mng_info->ping_exclude_cHRM=MagickFalse;
+  mng_info->ping_exclude_date=MagickFalse;
   mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
   mng_info->ping_exclude_gAMA=MagickFalse;
-  mng_info->ping_exclude_cHRM=MagickFalse;
   mng_info->ping_exclude_iCCP=MagickFalse;
   /* mng_info->ping_exclude_iTXt=MagickFalse; */
   mng_info->ping_exclude_oFFs=MagickFalse;
@@ -9420,6 +10350,14 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
   mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
   mng_info->ping_exclude_zTXt=MagickFalse;
 
+  mng_info->ping_preserve_colormap=MagickFalse;
+
+  value=GetImageArtifact(image,"png:preserve-colormap");
+  if (value == NULL)
+     value=GetImageOption(image_info,"png:preserve-colormap");
+  if (value != NULL)
+     mng_info->ping_preserve_colormap=MagickTrue;
+
   excluding=MagickFalse;
 
   for (source=0; source<1; source++)
@@ -9466,6 +10404,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       {
         mng_info->ping_exclude_bKGD=MagickTrue;
         mng_info->ping_exclude_cHRM=MagickTrue;
+        mng_info->ping_exclude_date=MagickTrue;
         mng_info->ping_exclude_EXIF=MagickTrue;
         mng_info->ping_exclude_gAMA=MagickTrue;
         mng_info->ping_exclude_iCCP=MagickTrue;
@@ -9485,6 +10424,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       {
         mng_info->ping_exclude_bKGD=MagickFalse;
         mng_info->ping_exclude_cHRM=MagickFalse;
+        mng_info->ping_exclude_date=MagickFalse;
         mng_info->ping_exclude_EXIF=MagickFalse;
         mng_info->ping_exclude_gAMA=MagickFalse;
         mng_info->ping_exclude_iCCP=MagickFalse;
@@ -9505,6 +10445,9 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       if (LocaleNCompare(value+i,"chrm",4) == 0)
         mng_info->ping_exclude_cHRM=MagickTrue;
 
+      if (LocaleNCompare(value+i,"date",4) == 0)
+        mng_info->ping_exclude_date=MagickTrue;
+
       if (LocaleNCompare(value+i,"exif",4) == 0)
         mng_info->ping_exclude_EXIF=MagickTrue;
 
@@ -9592,6 +10535,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
         {
           mng_info->ping_exclude_bKGD=MagickFalse;
           mng_info->ping_exclude_cHRM=MagickFalse;
+          mng_info->ping_exclude_date=MagickFalse;
           mng_info->ping_exclude_EXIF=MagickFalse;
           mng_info->ping_exclude_gAMA=MagickFalse;
           mng_info->ping_exclude_iCCP=MagickFalse;
@@ -9611,6 +10555,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
         {
           mng_info->ping_exclude_bKGD=MagickTrue;
           mng_info->ping_exclude_cHRM=MagickTrue;
+          mng_info->ping_exclude_date=MagickTrue;
           mng_info->ping_exclude_EXIF=MagickTrue;
           mng_info->ping_exclude_gAMA=MagickTrue;
           mng_info->ping_exclude_iCCP=MagickTrue;
@@ -9631,6 +10576,9 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       if (LocaleNCompare(value+i,"chrm",4) == 0)
         mng_info->ping_exclude_cHRM=MagickFalse;
 
+      if (LocaleNCompare(value+i,"date",4) == 0)
+        mng_info->ping_exclude_date=MagickFalse;
+
       if (LocaleNCompare(value+i,"exif",4) == 0)
         mng_info->ping_exclude_EXIF=MagickFalse;
 
@@ -9686,6 +10634,9 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
     if (mng_info->ping_exclude_cHRM != MagickFalse)
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "    cHRM");
+    if (mng_info->ping_exclude_date != MagickFalse)
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    date");
     if (mng_info->ping_exclude_EXIF != MagickFalse)
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "    EXIF");
@@ -9772,7 +10723,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
     jng_quality;
 
   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
-    "  enter WriteOneJNGImage()");
+    "  Enter WriteOneJNGImage()");
 
   blob=(unsigned char *) NULL;
   jpeg_image=(Image *) NULL;
@@ -9948,7 +10899,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
     }
 
   /* Write any JNG-chunk-b profiles */
-  (void) png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
+  (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
 
   /*
      Write leading ancillary chunks
@@ -9999,12 +10950,12 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
 
       if (image->rendering_intent != UndefinedIntent)
         chunk[4]=(unsigned char)
-          PNG_RenderingIntent_from_Magick_RenderingIntent(
+          Magick_RenderingIntent_to_PNG_RenderingIntent(
           (image->rendering_intent));
 
       else
         chunk[4]=(unsigned char)
-          PNG_RenderingIntent_from_Magick_RenderingIntent(
+          Magick_RenderingIntent_to_PNG_RenderingIntent(
           (PerceptualIntent));
 
       (void) WriteBlob(image,5,chunk);
@@ -10252,7 +11203,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
   blob=(unsigned char *) RelinquishMagickMemory(blob);
 
   /* Write any JNG-chunk-e profiles */
-  (void) png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
+  (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
 
   /* Write IEND chunk */
   (void) WriteBlobMSBULong(image,0L);
@@ -10314,7 +11265,7 @@ static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
+  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
   if (status == MagickFalse)
     return(status);
@@ -10411,7 +11362,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
+  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
   if (status == MagickFalse)
     return(status);
@@ -10693,7 +11644,8 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
                mng_info->ticks_per_second=0;
            }
          if (final_delay != 0)
-           mng_info->ticks_per_second=(png_uint_32) (image->ticks_per_second/final_delay);
+           mng_info->ticks_per_second=(png_uint_32)
+              (image->ticks_per_second/final_delay);
          if (final_delay > 50)
            mng_info->ticks_per_second=2;
 
@@ -10843,13 +11795,13 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
 
          if (image->rendering_intent != UndefinedIntent)
            chunk[4]=(unsigned char)
-             PNG_RenderingIntent_from_Magick_RenderingIntent(
+             Magick_RenderingIntent_to_PNG_RenderingIntent(
              (image->rendering_intent));
 
          else
            chunk[4]=(unsigned char)
-             PNG_RenderingIntent_from_Magick_RenderingIntent(
-             (PerceptualIntent));
+             Magick_RenderingIntent_to_PNG_RenderingIntent(
+               (PerceptualIntent));
 
          (void) WriteBlob(image,5,chunk);
          (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
@@ -11161,13 +12113,14 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
            "  Writing PNG object.");
 
        mng_info->need_blob = MagickFalse;
+       mng_info->ping_preserve_colormap = MagickFalse;
 
        /* We don't want any ancillary chunks written */
        mng_info->ping_exclude_bKGD=MagickTrue;
        mng_info->ping_exclude_cHRM=MagickTrue;
+       mng_info->ping_exclude_date=MagickTrue;
        mng_info->ping_exclude_EXIF=MagickTrue;
        mng_info->ping_exclude_gAMA=MagickTrue;
-       mng_info->ping_exclude_cHRM=MagickTrue;
        mng_info->ping_exclude_iCCP=MagickTrue;
        /* mng_info->ping_exclude_iTXt=MagickTrue; */
        mng_info->ping_exclude_oFFs=MagickTrue;