]> granicus.if.org Git - imagemagick/blobdiff - coders/png.c
(no commit message)
[imagemagick] / coders / png.c
index aef59edbb1b4ff25b6a060deed865e89a7f9ccda..883f70d120a4ef066bbfb4f9a7494bac9be4f764 100644 (file)
 /*
   Include declarations.
 */
-#include "magick/studio.h"
-#include "magick/artifact.h"
-#include "magick/attribute.h"
-#include "magick/blob.h"
-#include "magick/blob-private.h"
-#include "magick/cache.h"
-#include "magick/color.h"
-#include "magick/color-private.h"
-#include "magick/colormap.h"
-#include "magick/colorspace.h"
-#include "magick/constitute.h"
-#include "magick/enhance.h"
-#include "magick/exception.h"
-#include "magick/exception-private.h"
-#include "magick/geometry.h"
-#include "magick/histogram.h"
-#include "magick/image.h"
-#include "magick/image-private.h"
-#include "magick/layer.h"
-#include "magick/list.h"
-#include "magick/log.h"
-#include "magick/magick.h"
-#include "magick/memory_.h"
-#include "magick/module.h"
-#include "magick/monitor.h"
-#include "magick/monitor-private.h"
-#include "magick/option.h"
-#include "magick/quantum-private.h"
-#include "magick/profile.h"
-#include "magick/property.h"
-#include "magick/resource_.h"
-#include "magick/semaphore.h"
-#include "magick/quantum-private.h"
-#include "magick/static.h"
-#include "magick/statistic.h"
-#include "magick/string_.h"
-#include "magick/string-private.h"
-#include "magick/transform.h"
-#include "magick/utility.h"
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/MagickCore.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/module.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/static.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
 #if defined(MAGICKCORE_PNG_DELEGATE)
 
 /* Suppress libpng pedantic warnings that were added in
         ((color).blue == (target).blue))
 #endif
 
-/* Convenience macros for copying RGB or RGB+opacity components
- * between a pixel and a PixelPacket.
+/* Macros for left-bit-replication to ensure that pixels
+ * and PixelPackets all have the image->depth, and for use
+ * in PNG8 quantization.
  */
 
-#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); \
+/* LBR01: Replicate top bit */
 
+#define LBR01PacketRed(pixelpacket) \
+     (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \
+        0 : QuantumRange);
 
-#define GetRGBPixelComponents(pixel, packet) \
-        (packet).red = GetRedPixelComponent((pixel)); \
-        (packet).green = GetGreenPixelComponent((pixel)); \
-        (packet).red = GetBluePixelComponent((pixel));
+#define LBR01PacketGreen(pixelpacket) \
+     (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \
+        0 : QuantumRange);
 
-#define SetRGBPixelComponents(pixel, packet) \
-        SetRedPixelComponent((pixel),(packet).red); \
-        SetGreenPixelComponent((pixel),(packet).green); \
-        SetBluePixelComponent((pixel),(packet).blue);
+#define LBR01PacketBlue(pixelpacket) \
+     (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \
+        0 : QuantumRange);
+
+#define LBR01PacketAlpha(pixelpacket) \
+     (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \
+        0 : QuantumRange);
+
+#define LBR01PacketRGB(pixelpacket) \
+        { \
+        LBR01PacketRed((pixelpacket)); \
+        LBR01PacketGreen((pixelpacket)); \
+        LBR01PacketBlue((pixelpacket)); \
+        }
+
+#define LBR01PacketRGBO(pixelpacket) \
+        { \
+        LBR01PacketRGB((pixelpacket)); \
+        LBR01PacketAlpha((pixelpacket)); \
+        }
+
+#define LBR01PixelRed(pixel) \
+        (ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
+        0 : QuantumRange);
+
+#define LBR01PixelGreen(pixel) \
+        (ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
+        0 : QuantumRange);
+
+#define LBR01PixelBlue(pixel) \
+        (ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
+        0 : QuantumRange);
+
+#define LBR01PixelAlpha(pixel) \
+        (ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
+        0 : QuantumRange);
+
+#define LBR01PixelRGB(pixel) \
+        { \
+        LBR01PixelRed((pixel)); \
+        LBR01PixelGreen((pixel)); \
+        LBR01PixelBlue((pixel)); \
+        }
+
+#define LBR01PixelRGBA(pixel) \
+        { \
+        LBR01PixelRGB((pixel)); \
+        LBR01PixelAlpha((pixel)); \
+        }
+
+/* LBR02: Replicate top 2 bits */
+
+#define LBR02PacketRed(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
+     (pixelpacket).red=ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
+   }
+#define LBR02PacketGreen(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
+     (pixelpacket).green=ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
+   }
+#define LBR02PacketBlue(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
+     (pixelpacket).blue=ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
+   }
+#define LBR02PacketAlpha(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
+     (pixelpacket).alpha=ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
+   }
+
+#define LBR02PacketRGB(pixelpacket) \
+        { \
+        LBR02PacketRed((pixelpacket)); \
+        LBR02PacketGreen((pixelpacket)); \
+        LBR02PacketBlue((pixelpacket)); \
+        }
+
+#define LBR02PacketRGBO(pixelpacket) \
+        { \
+        LBR02PacketRGB((pixelpacket)); \
+        LBR02PacketAlpha((pixelpacket)); \
+        }
+
+#define LBR02PixelRed(pixel) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
+       & 0xc0; \
+     SetPixelRed(image, ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
+       (pixel)); \
+   }
+#define LBR02PixelGreen(pixel) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
+       & 0xc0; \
+     SetPixelGreen(image, ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
+       (pixel)); \
+   }
+#define LBR02PixelBlue(pixel) \
+   { \
+     unsigned char lbr_bits= \
+       ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
+     SetPixelBlue(image, ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
+       (pixel)); \
+   }
+#define LBR02PixelAlpha(pixel) \
+   { \
+     unsigned char lbr_bits= \
+       ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
+     SetPixelAlpha(image, ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
+       (pixel) ); \
+   }
+
+#define LBR02PixelRGB(pixel) \
+        { \
+        LBR02PixelRed((pixel)); \
+        LBR02PixelGreen((pixel)); \
+        LBR02PixelBlue((pixel)); \
+        }
+
+#define LBR02PixelRGBA(pixel) \
+        { \
+        LBR02PixelRGB((pixel)); \
+        LBR02PixelAlpha((pixel)); \
+        }
+
+/* LBR03: Replicate top 3 bits (only used with opaque pixels during
+   PNG8 quantization) */
+
+#define LBR03PacketRed(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
+     (pixelpacket).red=ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
+   }
+#define LBR03PacketGreen(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
+     (pixelpacket).green=ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
+   }
+#define LBR03PacketBlue(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
+     (pixelpacket).blue=ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
+   }
+
+#define LBR03PacketRGB(pixelpacket) \
+        { \
+        LBR03PacketRed((pixelpacket)); \
+        LBR03PacketGreen((pixelpacket)); \
+        LBR03PacketBlue((pixelpacket)); \
+        }
+
+#define LBR03PixelRed(pixel) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
+       & 0xe0; \
+     SetPixelRed(image, ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
+   }
+#define LBR03Green(pixel) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
+       & 0xe0; \
+     SetPixelGreen(image, ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
+   }
+#define LBR03Blue(pixel) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
+       & 0xe0; \
+     SetPixelBlue(image, ScaleCharToQuantum( \
+       (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
+   }
+
+#define LBR03RGB(pixel) \
+        { \
+        LBR03PixelRed((pixel)); \
+        LBR03Green((pixel)); \
+        LBR03Blue((pixel)); \
+        }
+
+/* LBR04: Replicate top 4 bits */
+
+#define LBR04PacketRed(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
+     (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
+   }
+#define LBR04PacketGreen(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
+     (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
+   }
+#define LBR04PacketBlue(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
+     (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
+   }
+#define LBR04PacketAlpha(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
+     (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
+   }
+
+#define LBR04PacketRGB(pixelpacket) \
+        { \
+        LBR04PacketRed((pixelpacket)); \
+        LBR04PacketGreen((pixelpacket)); \
+        LBR04PacketBlue((pixelpacket)); \
+        }
+
+#define LBR04PacketRGBO(pixelpacket) \
+        { \
+        LBR04PacketRGB((pixelpacket)); \
+        LBR04PacketAlpha((pixelpacket)); \
+        }
+
+#define LBR04PixelRed(pixel) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
+       & 0xf0; \
+     SetPixelRed(image,\
+       ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
+   }
+#define LBR04PixelGreen(pixel) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
+       & 0xf0; \
+     SetPixelGreen(image,\
+       ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
+   }
+#define LBR04PixelBlue(pixel) \
+   { \
+     unsigned char lbr_bits= \
+       ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
+     SetPixelBlue(image,\
+       ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
+   }
+#define LBR04PixelAlpha(pixel) \
+   { \
+     unsigned char lbr_bits= \
+       ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
+     SetPixelAlpha(image,\
+       ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
+   }
+
+#define LBR04PixelRGB(pixel) \
+        { \
+        LBR04PixelRed((pixel)); \
+        LBR04PixelGreen((pixel)); \
+        LBR04PixelBlue((pixel)); \
+        }
+
+#define LBR04PixelRGBA(pixel) \
+        { \
+        LBR04PixelRGB((pixel)); \
+        LBR04PixelAlpha((pixel)); \
+        }
+
+
+/* LBR08: Replicate top 8 bits */
+
+#define LBR08PacketRed(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
+     (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
+   }
+#define LBR08PacketGreen(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
+     (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
+   }
+#define LBR08PacketBlue(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
+     (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
+   }
+#define LBR08PacketAlpha(pixelpacket) \
+   { \
+     unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
+     (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
+   }
+
+#define LBR08PacketRGB(pixelpacket) \
+        { \
+        LBR08PacketRed((pixelpacket)); \
+        LBR08PacketGreen((pixelpacket)); \
+        LBR08PacketBlue((pixelpacket)); \
+        }
+
+#define LBR08PacketRGBO(pixelpacket) \
+        { \
+        LBR08PacketRGB((pixelpacket)); \
+        LBR08PacketAlpha((pixelpacket)); \
+        }
+
+#define LBR08PixelRed(pixel) \
+   { \
+     unsigned char lbr_bits= \
+       ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
+     SetPixelRed(image,\
+       ScaleCharToQuantum((lbr_bits)), (pixel)); \
+   }
+#define LBR08PixelGreen(pixel) \
+   { \
+     unsigned char lbr_bits= \
+       ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
+     SetPixelGreen(image,\
+       ScaleCharToQuantum((lbr_bits)), (pixel)); \
+   }
+#define LBR08PixelBlue(pixel) \
+   { \
+     unsigned char lbr_bits= \
+       ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
+     SetPixelBlue(image,\
+       ScaleCharToQuantum((lbr_bits)), (pixel)); \
+   }
+#define LBR08PixelAlpha(pixel) \
+   { \
+     unsigned char lbr_bits= \
+       ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
+     SetPixelAlpha(image,\
+       ScaleCharToQuantum((lbr_bits)), (pixel)); \
+   }
+
+#define LBR08PixelRGB(pixel) \
+        { \
+        LBR08PixelRed((pixel)); \
+        LBR08PixelGreen((pixel)); \
+        LBR08PixelBlue((pixel)); \
+        }
+
+#define LBR08PixelRGBA(pixel) \
+        { \
+        LBR08PixelRGB((pixel)); \
+        LBR08PixelAlpha((pixel)); \
+        }
+
+
+/* LBR16: Replicate top 16 bits */
+
+#define LBR16PacketRed(pixelpacket) \
+   { \
+     unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
+     (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
+   }
+#define LBR16PacketGreen(pixelpacket) \
+   { \
+     unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
+     (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
+   }
+#define LBR16PacketBlue(pixelpacket) \
+   { \
+     unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
+     (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
+   }
+#define LBR16PacketAlpha(pixelpacket) \
+   { \
+     unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
+     (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
+   }
+
+#define LBR16PacketRGB(pixelpacket) \
+        { \
+        LBR16PacketRed((pixelpacket)); \
+        LBR16PacketGreen((pixelpacket)); \
+        LBR16PacketBlue((pixelpacket)); \
+        }
+
+#define LBR16PacketRGBO(pixelpacket) \
+        { \
+        LBR16PacketRGB((pixelpacket)); \
+        LBR16PacketAlpha((pixelpacket)); \
+        }
+
+#define LBR16PixelRed(pixel) \
+   { \
+     unsigned short lbr_bits= \
+       ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
+     SetPixelRed(image,\
+       ScaleShortToQuantum((lbr_bits)),(pixel)); \
+   }
+#define LBR16PixelGreen(pixel) \
+   { \
+     unsigned short lbr_bits= \
+       ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
+     SetPixelGreen(image,\
+       ScaleShortToQuantum((lbr_bits)),(pixel)); \
+   }
+#define LBR16PixelBlue(pixel) \
+   { \
+     unsigned short lbr_bits= \
+       ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
+     SetPixelBlue(image,\
+       ScaleShortToQuantum((lbr_bits)),(pixel)); \
+   }
+#define LBR16PixelAlpha(pixel) \
+   { \
+     unsigned short lbr_bits= \
+       ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
+     SetPixelAlpha(image,\
+       ScaleShortToQuantum((lbr_bits)),(pixel)); \
+   }
+
+#define LBR16PixelRGB(pixel) \
+        { \
+        LBR16PixelRed((pixel)); \
+        LBR16PixelGreen((pixel)); \
+        LBR16PixelBlue((pixel)); \
+        }
+
+#define LBR16PixelRGBA(pixel) \
+        { \
+        LBR16PixelRGB((pixel)); \
+        LBR16PixelAlpha((pixel)); \
+        }
 
 /*
   Establish thread safety.
@@ -444,6 +866,9 @@ typedef struct _MngInfo
     write_mng,
     write_png_colortype,
     write_png_depth,
+    write_png_compression_level,
+    write_png_compression_strategy,
+    write_png_compression_filter,
     write_png8,
     write_png24,
     write_png32;
@@ -507,14 +932,14 @@ typedef struct _MngInfo
   Forward declarations.
 */
 static MagickBooleanType
-  WritePNGImage(const ImageInfo *,Image *);
+  WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
 
 static MagickBooleanType
-  WriteMNGImage(const ImageInfo *,Image *);
+  WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
 
 #if defined(JNG_SUPPORTED)
 static MagickBooleanType
-  WriteJNGImage(const ImageInfo *,Image *);
+  WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
 #endif
 
 #if PNG_LIBPNG_VER > 10011
@@ -544,7 +969,7 @@ LosslessReduceDepthOK(Image *image)
     if (image->depth >= 16)
       {
 
-        const PixelPacket
+        const Quantum
           *p;
 
         ok_to_reduce=
@@ -586,7 +1011,7 @@ LosslessReduceDepthOK(Image *image)
             {
               p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
 
-              if (p == (const PixelPacket *) NULL)
+              if (p == (const Quantum *) NULL)
                 {
                   ok_to_reduce = MagickFalse;
                   break;
@@ -595,15 +1020,15 @@ LosslessReduceDepthOK(Image *image)
               for (x=(ssize_t) image->columns-1; x >= 0; x--)
               {
                 ok_to_reduce=
-                   QuantumToCharToQuantumEqQuantum(GetRedPixelComponent(p)) &&
-                   QuantumToCharToQuantumEqQuantum(GetGreenPixelComponent(p)) &&
-                   QuantumToCharToQuantumEqQuantum(GetBluePixelComponent(p)) ?
+                   QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
+                   QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
+                   QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
                    MagickTrue : MagickFalse;
 
                 if (ok_to_reduce == MagickFalse)
                   break;
 
-                p++;
+                p+=GetPixelChannels(image);
               }
               if (x >= 0)
                 break;
@@ -698,13 +1123,13 @@ static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
-%   Like IsGrayImage except does not change DirectClass to PseudoClass        %
+%   Like IsImageGray except does not change DirectClass to PseudoClass        %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 */
 static MagickBooleanType ImageIsGray(Image *image)
 {
-  register const PixelPacket
+  register const Quantum
     *p;
 
   register ssize_t
@@ -720,20 +1145,20 @@ static MagickBooleanType ImageIsGray(Image *image)
   if (image->storage_class == PseudoClass)
     {
       for (i=0; i < (ssize_t) image->colors; i++)
-        if (IsGray(image->colormap+i) == MagickFalse)
+        if (IsPixelPacketGray(image->colormap+i) == MagickFalse)
           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)
+    if (p == (const Quantum *) NULL)
       return(MagickFalse);
     for (x=(ssize_t) image->columns-1; x >= 0; x--)
     {
-       if (IsGray(p) == MagickFalse)
+       if (IsPixelGray(image,p) == MagickFalse)
           return(MagickFalse);
-       p++;
+       p+=GetPixelChannels(image);
     }
   }
   return(MagickTrue);
@@ -996,7 +1421,7 @@ static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
 %    We will not attempt to read files containing the CgBI chunk.
 %    They are really Xcode files meant for display on the iPhone.
 %    These are not valid PNG files and it is impossible to recover
-%    the orginal PNG from files that have been converted to Xcode-PNG,
+%    the original PNG from files that have been converted to Xcode-PNG,
 %    since irretrievable loss of color data has occurred due to the
 %    use of premultiplied alpha.
 */
@@ -1027,7 +1452,7 @@ static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
           char
             msg[MaxTextExtent];
 
-          (void) FormatMagickString(msg,MaxTextExtent,
+          (void) FormatLocaleString(msg,MaxTextExtent,
             "Expected %.20g bytes; found %.20g bytes",(double) length,
             (double) check);
           png_warning(png_ptr,msg);
@@ -1424,7 +1849,7 @@ Magick_png_read_raw_profile(Image *image, const ImageInfo *image_info,
     return(MagickFalse);
   }
 
-  profile=AcquireStringInfo(length);
+  profile=BlobToStringInfo((const void *) NULL,length);
 
   if (profile == (StringInfo *) NULL)
   {
@@ -1575,7 +2000,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   double
     file_gamma;
 
-  LongPixelPacket
+  PixelLongPacket
     transparent_color;
 
   MagickBooleanType
@@ -1618,14 +2043,11 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   register unsigned char
     *p;
 
-  register IndexPacket
-    *indexes;
-
   register ssize_t
     i,
     x;
 
-  register PixelPacket
+  register Quantum
     *q;
 
   size_t
@@ -1683,7 +2105,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   transparent_color.red=65537;
   transparent_color.green=65537;
   transparent_color.blue=65537;
-  transparent_color.opacity=65537;
+  transparent_color.alpha=65537;
 
   num_text = 0;
   num_text_total = 0;
@@ -1874,7 +2296,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           if (logging != MagickFalse)
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "    Reading PNG iCCP chunk.");
-          profile=AcquireStringInfo(profile_length);
+          profile=BlobToStringInfo(info,profile_length);
+          if (profile == (StringInfo *) NULL)
+          {
+            (void) ThrowMagickException(&image->exception,GetMagickModule(),
+              ResourceLimitError,"MemoryAllocationFailed","`%s'",
+              "unable to copy profile");
+            return((Image *) NULL);
+          }
           SetStringInfoDatum(profile,(const unsigned char *) info);
           (void) SetImageProfile(image,"icc",profile);
           profile=DestroyStringInfo(profile);
@@ -2135,7 +2564,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         image->background_color.blue=
           ScaleShortToQuantum(ping_background->blue);
 
-        image->background_color.opacity=OpaqueOpacity;
+        image->background_color.alpha=OpaqueAlpha;
 
         if (logging != MagickFalse)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -2188,7 +2617,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           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;
+          transparent_color.alpha= scale_to_short*ping_trans_color->gray;
 
           if (ping_color_type == PNG_COLOR_TYPE_GRAY)
             {
@@ -2198,11 +2627,11 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                   "    Raw tRNS graylevel is %d.",ping_trans_color->gray);
 
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                  "    scaled graylevel is %d.",transparent_color.opacity);
+                  "    scaled graylevel is %d.",transparent_color.alpha);
               }
-              transparent_color.red=transparent_color.opacity;
-              transparent_color.green=transparent_color.opacity;
-              transparent_color.blue=transparent_color.opacity;
+              transparent_color.red=transparent_color.alpha;
+              transparent_color.green=transparent_color.alpha;
+              transparent_color.blue=transparent_color.alpha;
             }
         }
     }
@@ -2280,7 +2709,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       /*
         Initialize image colormap.
       */
-      if (AcquireImageColormap(image,image->colors) == MagickFalse)
+      if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
 
       if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
@@ -2335,17 +2764,17 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
      /* encode ping_width, ping_height, ping_bit_depth, ping_color_type,
         ping_interlace_method in value */
 
-     (void) FormatMagickString(msg,MaxTextExtent,
+     (void) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
      (void) SetImageProperty(image,"PNG:IHDR.color_type      ",msg);
 
-     (void) FormatMagickString(msg,MaxTextExtent,"%d",
+     (void) FormatLocaleString(msg,MaxTextExtent,"%d",
         (int) ping_interlace_method);
      (void) SetImageProperty(image,"PNG:IHDR.interlace_method",msg);
    }
@@ -2465,7 +2894,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           png_read_row(ping,ping_pixels+row_offset,NULL);
           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
 
-          if (q == (PixelPacket *) NULL)
+          if (q == (Quantum *) NULL)
             break;
 
           if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
@@ -2499,7 +2928,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
               {
                 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
                     ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
-                   (GetOpacityPixelComponent(q) != OpaqueOpacity))
+                   (GetPixelAlpha(image,q) != OpaqueAlpha))
                   {
                     if (logging != MagickFalse)
                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -2510,12 +2939,12 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                   }
                 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
                     ping_color_type == PNG_COLOR_TYPE_GRAY) &&
-                    (ScaleQuantumToShort(GetRedPixelComponent(q))
-                    == transparent_color.red &&
-                    ScaleQuantumToShort(GetGreenPixelComponent(q))
-                    == transparent_color.green &&
-                    ScaleQuantumToShort(GetBluePixelComponent(q))
-                    == transparent_color.blue))
+                    (ScaleQuantumToShort(GetPixelRed(image,q)) ==
+                    transparent_color.red &&
+                    ScaleQuantumToShort(GetPixelGreen(image,q)) ==
+                    transparent_color.green &&
+                    ScaleQuantumToShort(GetPixelBlue(image,q)) ==
+                    transparent_color.blue))
                   {
                     if (logging != MagickFalse)
                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -2523,7 +2952,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                     found_transparent_pixel = MagickTrue;
                     break;
                   }
-                q++;
+                q+=GetPixelChannels(image);
               }
             }
 
@@ -2561,6 +2990,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       /*
         Convert grayscale image to PseudoClass pixel packets.
       */
+      if (logging != MagickFalse)
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    Converting grayscale pixels to pixel packets");
+
       image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
         MagickTrue : MagickFalse;
 
@@ -2581,10 +3014,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         png_read_row(ping,ping_pixels+row_offset,NULL);
         q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
 
-        if (q == (PixelPacket *) NULL)
+        if (q == (Quantum *) NULL)
           break;
 
-        indexes=GetAuthenticIndexQueue(image);
         p=ping_pixels+row_offset;
         r=quantum_scanline;
 
@@ -2650,16 +3082,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
               for (x=(ssize_t) image->columns-1; x >= 0; x--)
               {
                 *r++=*p++;
-                /* In image.h, OpaqueOpacity is 0
-                 * TransparentOpacity is QuantumRange
-                 * In a PNG datastream, Opaque is QuantumRange
-                 * and Transparent is 0.
-                 */
-                SetOpacityPixelComponent(q,
-                    ScaleCharToQuantum((unsigned char) (255-(*p++))));
-                if (GetOpacityPixelComponent(q) != OpaqueOpacity)
+                SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *p++),q);
+                if (GetPixelAlpha(image,q) != OpaqueAlpha)
                   found_transparent_pixel = MagickTrue;
-                q++;
+                q+=GetPixelChannels(image);
               }
 
             else
@@ -2673,56 +3099,32 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           {
             for (x=(ssize_t) image->columns-1; x >= 0; x--)
             {
-#if (MAGICKCORE_QUANTUM_DEPTH == 16)
+#if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
               size_t
                 quantum;
 
               if (image->colors > 256)
-                *r=((*p++) << 8);
+                quantum=((*p++) << 8);
 
               else
-                *r=0;
+                quantum=0;
 
-              quantum=(*r);
               quantum|=(*p++);
-              *r=(Quantum) quantum;
+              *r=ScaleShortToQuantum(quantum);
               r++;
 
               if (ping_color_type == 4)
                 {
-                  quantum=((*p++) << 8);
-                  quantum|=(*p++);
-                  SetOpacityPixelComponent(q,(Quantum) (QuantumRange-quantum));
-                  if (GetOpacityPixelComponent(q) != OpaqueOpacity)
-                    found_transparent_pixel = MagickTrue;
-                  q++;
-                }
-#else
-#if (MAGICKCORE_QUANTUM_DEPTH == 32)
-              size_t
-                quantum;
-
-              if (image->colors > 256)
-                *r=((*p++) << 8);
-
-              else
-                *r=0;
-
-              quantum=(*r);
-              quantum|=(*p++);
-              *r=quantum;
-              r++;
+                  if (image->colors > 256)
+                    quantum=((*p++) << 8);
+                  else
+                    quantum=0;
 
-              if (ping_color_type == 4)
-                {
-                  quantum=(*p << 8) | *(p+1);
-                  quantum*=65537L;
-                  SetOpacityPixelComponent(q,
-                    (Quantum) GetAlphaPixelComponent(q));
-                  if (GetOpacityPixelComponent(q) != OpaqueOpacity)
+                  quantum|=(*p++);
+                  SetPixelAlpha(image,ScaleShortToQuantum(quantum),q);
+                  if (GetPixelAlpha(image,q) != OpaqueAlpha)
                     found_transparent_pixel = MagickTrue;
-                  p+=2;
-                  q++;
+                  q+=GetPixelChannels(image);
                 }
 
 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
@@ -2731,13 +3133,12 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
               if (ping_color_type == 4)
                 {
-                  SetOpacityPixelComponent(q,(Quantum) (QuantumRange-(*p++)));
-                  if (GetOpacityPixelComponent(q) != OpaqueOpacity)
+                  SetPixelAlpha(image,*p++,q);
+                  if (GetPixelAlpha(image,q) != OpaqueAlpha)
                     found_transparent_pixel = MagickTrue;
                   p++;
-                  q++;
+                  q+=GetPixelChannels(image);
                 }
-#endif
 #endif
             }
 
@@ -2753,8 +3154,15 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         */
         r=quantum_scanline;
 
+        q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+
+        if (q == (Quantum *) NULL)
+          break;
         for (x=0; x < (ssize_t) image->columns; x++)
-          indexes[x]=(IndexPacket) (*r++);
+        {
+          SetPixelIndex(image,*r++,q);
+          q+=GetPixelChannels(image);
+        }
 
         if (SyncAuthenticPixels(image,exception) == MagickFalse)
           break;
@@ -2762,7 +3170,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;
@@ -2791,7 +3199,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
           {
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "    No transparent pixel was found");
-          
+
             ping_color_type&=0x03;
           }
       }
@@ -2848,8 +3256,8 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
             {
               for (x=0; x < ping_num_trans; x++)
               {
-                 image->colormap[x].opacity =
-                   ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x]));
+                 image->colormap[x].alpha =
+                   ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
               }
             }
 
@@ -2858,9 +3266,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
               for (x=0; x < (int) image->colors; x++)
               {
                  if (ScaleQuantumToShort(image->colormap[x].red) ==
-                     transparent_color.opacity)
+                     transparent_color.alpha)
                  {
-                    image->colormap[x].opacity = (Quantum) TransparentOpacity;
+                    image->colormap[x].alpha = (Quantum) TransparentAlpha;
                  }
               }
             }
@@ -2877,34 +3285,33 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
             image->storage_class=storage_class;
             q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
 
-            if (q == (PixelPacket *) NULL)
+            if (q == (Quantum *) NULL)
               break;
 
-            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 (ScaleQuantumToShort(GetRedPixelComponent(q))
-                  == transparent_color.red &&
-                  ScaleQuantumToShort(GetGreenPixelComponent(q))
-                  == transparent_color.green &&
-                  ScaleQuantumToShort(GetBluePixelComponent(q))
-                  == transparent_color.blue)
+              if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
+                  transparent_color.red &&
+                  ScaleQuantumToShort(GetPixelGreen(image,q)) ==
+                  transparent_color.green &&
+                  ScaleQuantumToShort(GetPixelBlue(image,q)) ==
+                  transparent_color.blue)
                 {
-                  SetOpacityPixelComponent(q,TransparentOpacity);
+                  SetPixelAlpha(image,TransparentAlpha,q);
                 }
 
 #if 0 /* I have not found a case where this is needed. */
               else
                 {
-                  q->opacity=(Quantum) OpaqueOpacity;
+                  SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
                 }
 #endif
 
-              q++;
+              q+=GetPixelChannels(image);
             }
 
             if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -3092,33 +3499,33 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
      if (num_text_total != 0)
        {
          /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
-         (void) FormatMagickString(msg,MaxTextExtent,
+         (void) FormatLocaleString(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,
+         (void) FormatLocaleString(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",
+         (void) FormatLocaleString(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",
+         (void) FormatLocaleString(msg,MaxTextExtent,"%s",
             "chunk was found (see Background color, above)");
          (void) SetImageProperty(image,"PNG:bKGD                 ",msg);
        }
 
-     (void) FormatMagickString(msg,MaxTextExtent,"%s",
+     (void) FormatLocaleString(msg,MaxTextExtent,"%s",
         "chunk was found");
 
      if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
@@ -3130,7 +3537,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 #if defined(PNG_sRGB_SUPPORTED)
      if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
        {
-         (void) FormatMagickString(msg,MaxTextExtent,
+         (void) FormatLocaleString(msg,MaxTextExtent,
             "intent=%d (See Rendering intent)",
             (int) intent);
          (void) SetImageProperty(image,"PNG:sRGB                 ",msg);
@@ -3139,7 +3546,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
      if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
        {
-         (void) FormatMagickString(msg,MaxTextExtent,
+         (void) FormatLocaleString(msg,MaxTextExtent,
             "gamma=%.8g (See Gamma, above)",
             file_gamma);
          (void) SetImageProperty(image,"PNG:gAMA                 ",msg);
@@ -3148,7 +3555,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 #if defined(PNG_pHYs_SUPPORTED)
      if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
        {
-         (void) FormatMagickString(msg,MaxTextExtent,
+         (void) FormatLocaleString(msg,MaxTextExtent,
             "x_res=%.10g, y_res=%.10g, units=%d",
             (double) x_resolution,(double) y_resolution, unit_type);
          (void) SetImageProperty(image,"PNG:pHYs                 ",msg);
@@ -3158,7 +3565,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 #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",
+         (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
             (double) image->page.x,(double) image->page.y);
          (void) SetImageProperty(image,"PNG:oFFs                 ",msg);
        }
@@ -3167,7 +3574,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
      if ((image->page.width != 0 && image->page.width != image->columns) ||
          (image->page.height != 0 && image->page.height != image->rows))
        {
-         (void) FormatMagickString(msg,MaxTextExtent,
+         (void) FormatLocaleString(msg,MaxTextExtent,
             "width=%.20g, height=%.20g",
             (double) image->page.width,(double) image->page.height);
          (void) SetImageProperty(image,"PNG:vpAg                 ",msg);
@@ -3290,26 +3697,14 @@ 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);
-
-      if (image->matte != MagickFalse)
-        {
-          /* To do: Reduce to binary transparency */
-        }
-    }
-#endif
-
   if (LocaleCompare(image_info->magick,"PNG24") == 0)
     {
-      (void) SetImageType(image,TrueColorType);
+      (void) SetImageType(image,TrueColorType,exception);
       image->matte=MagickFalse;
     }
 
   if (LocaleCompare(image_info->magick,"PNG32") == 0)
-    (void) SetImageType(image,TrueColorMatteType);
+    (void) SetImageType(image,TrueColorMatteType,exception);
 
   if (logging != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -3394,14 +3789,14 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
     jng_alpha_filter_method,
     jng_alpha_interlace_method;
 
-  register const PixelPacket
+  register const Quantum
     *s;
 
   register ssize_t
     i,
     x;
 
-  register PixelPacket
+  register Quantum
     *q;
 
   register unsigned char
@@ -3430,7 +3825,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
 
   image=mng_info->image;
 
-  if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
+  if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
     {
       /*
         Allocate next image structure.
@@ -3892,7 +4287,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
        o close alpha_blob.
 
        o copy intensity of secondary image into
-         opacity samples of main image.
+         alpha samples of main image.
 
        o destroy the secondary image.
   */
@@ -3903,7 +4298,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "    Reading jng_image from color_blob.");
 
-  (void) FormatMagickString(color_image_info->filename,MaxTextExtent,"%s",
+  (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
     color_image->filename);
 
   color_image_info->ping=MagickFalse;   /* To do: avoid this */
@@ -3925,13 +4320,19 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
 
   image->rows=jng_height;
   image->columns=jng_width;
-  length=image->columns*sizeof(PixelPacket);
 
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     s=GetVirtualPixels(jng_image,0,y,image->columns,1,&image->exception);
     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
-    (void) CopyMagickMemory(q,s,length);
+    for (x=(ssize_t) image->columns; x != 0; x--)
+    {
+      SetPixelRed(image,GetPixelRed(jng_image,s),q);
+      SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
+      SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
+      q+=GetPixelChannels(image);
+      s+=GetPixelChannels(jng_image);
+    }
 
     if (SyncAuthenticPixels(image,exception) == MagickFalse)
       break;
@@ -3958,9 +4359,9 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
 
          if (logging != MagickFalse)
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-             "    Reading opacity from alpha_blob.");
+             "    Reading alpha from alpha_blob.");
 
-         (void) FormatMagickString(alpha_image_info->filename,MaxTextExtent,
+         (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
            "%s",alpha_image->filename);
 
          jng_image=ReadImage(alpha_image_info,exception);
@@ -3969,21 +4370,25 @@ static Image *ReadOneJNGImage(MngInfo *mng_info,
            for (y=0; y < (ssize_t) image->rows; y++)
            {
              s=GetVirtualPixels(jng_image,0,y,image->columns,1,
-                &image->exception);
+               &image->exception);
              q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
 
              if (image->matte != MagickFalse)
-               for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
-                  q->opacity=(Quantum) QuantumRange-
-                      GetRedPixelComponent(s);
+               for (x=(ssize_t) image->columns; x != 0; x--)
+               {
+                  SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
+                  q+=GetPixelChannels(image);
+                  s+=GetPixelChannels(jng_image);
+               }
 
              else
-               for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
+               for (x=(ssize_t) image->columns; x != 0; x--)
                {
-                  SetOpacityPixelComponent(q,(Quantum) QuantumRange-
-                      GetRedPixelComponent(s));
-                  if (GetOpacityPixelComponent(q) != OpaqueOpacity)
+                  SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
+                  if (GetPixelAlpha(image,q) != OpaqueAlpha)
                     image->matte=MagickTrue;
+                  q+=GetPixelChannels(image);
+                  s+=GetPixelChannels(jng_image);
                }
 
              if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -4468,7 +4873,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
             if (mng_type != 3)
               insert_layers=MagickTrue;
 #endif
-            if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
+            if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
               {
                 /* Allocate next image structure.  */
                 AcquireNextImage(image_info,image);
@@ -4484,7 +4889,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 (mng_info->mng_height > 65535L))
               ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
 
-            (void) FormatMagickString(page_geometry,MaxTextExtent,
+            (void) FormatLocaleString(page_geometry,MaxTextExtent,
               "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
               mng_info->mng_height);
 
@@ -4652,7 +5057,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 mng_background_color.blue=
                     ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
 
-                mng_background_color.opacity=OpaqueOpacity;
+                mng_background_color.alpha=OpaqueAlpha;
               }
 
 #ifdef MNG_OBJECT_BUFFERS
@@ -4920,7 +5325,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 (subframe_width) && (subframe_height))
               {
                 /* Allocate next image structure.  */
-                if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
+                if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
                   {
                     AcquireNextImage(image_info,image);
 
@@ -5471,7 +5876,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 (image_height < mng_info->mng_height) ||
                 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
               {
-                if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
+                if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
                   {
                     /*
                       Allocate next image structure.
@@ -5524,7 +5929,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 (subframe_width) && (subframe_height) && (simplicity == 0 ||
                 (simplicity & 0x08)))
           {
-            if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
+            if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
             {
               /*
                 Allocate next image structure.
@@ -5573,7 +5978,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 #endif /* MNG_INSERT_LAYERS */
         first_mng_object=MagickFalse;
 
-        if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
+        if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
           {
             /*
               Allocate next image structure.
@@ -5748,24 +6153,24 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 int
                   yy;
 
+                Quantum
+                  *next,
+                  *prev;
+
+                png_uint_16
+                  magn_methx,
+                  magn_methy;
+
                 ssize_t
                   m,
                   y;
 
-                register ssize_t
-                  x;
-
-                register PixelPacket
+                register Quantum
                   *n,
                   *q;
 
-                PixelPacket
-                  *next,
-                  *prev;
-
-                png_uint_16
-                  magn_methx,
-                  magn_methy;
+                register ssize_t
+                  x;
 
                 /* Allocate next image structure.  */
 
@@ -5805,15 +6210,15 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
                        for (x=(ssize_t) image->columns-1; x >= 0; x--)
                        {
-                          SetRedPixelComponent(q,ScaleQuantumToShort(
-                            GetRedPixelComponent(q));
-                          SetGreenPixelComponent(q,ScaleQuantumToShort(
-                            GetGreenPixelComponent(q));
-                          SetBluePixelComponent(q,ScaleQuantumToShort(
-                            GetBluePixelComponent(q));
-                          SetOpacityPixelComponent(q,ScaleQuantumToShort(
-                            GetOpacityPixelComponent(q));
-                          q++;
+                          SetPixelRed(image,ScaleQuantumToShort(
+                            GetPixelRed(image,q)),q);
+                          SetPixelGreen(image,ScaleQuantumToShort(
+                            GetPixelGreen(image,q)),q);
+                          SetPixelBlue(image,ScaleQuantumToShort(
+                            GetPixelBlue(image,q)),q);
+                          SetPixelAlpha(image,ScaleQuantumToShort(
+                            GetPixelAlpha(image,q)),q);
+                          q+=GetPixelChannels(image);
                        }
 
                        if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -5829,7 +6234,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
                 else
                   {
-                    large_image->background_color.opacity=OpaqueOpacity;
+                    large_image->background_color.alpha=OpaqueAlpha;
                     (void) SetImageBackgroundColor(large_image);
 
                     if (magn_methx == 4)
@@ -5853,11 +6258,11 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 m=(ssize_t) mng_info->magn_mt;
                 yy=0;
                 length=(size_t) image->columns;
-                next=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*next));
-                prev=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*prev));
+                next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
+                prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
 
-                if ((prev == (PixelPacket *) NULL) ||
-                    (next == (PixelPacket *) NULL))
+                if ((prev == (Quantum *) NULL) ||
+                    (next == (Quantum *) NULL))
                   {
                      image=DestroyImageList(image);
                      MngInfoFreeStruct(mng_info,&have_mng_structure);
@@ -5898,15 +6303,14 @@ 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
+                    register Quantum
                       *pixels;
 
                     assert(yy < (ssize_t) large_image->rows);
                     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--)
@@ -5920,41 +6324,66 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
                       if (magn_methy <= 1)
                         {
-                          *q=(*pixels); /* replicate previous */
+                          /* replicate previous */
+                          SetPixelRed(large_image,GetPixelRed(image,pixels),q);
+                          SetPixelGreen(large_image,GetPixelGreen(image,
+                             pixels),q);
+                          SetPixelBlue(large_image,GetPixelBlue(image,
+                             pixels),q);
+                          SetPixelAlpha(large_image,GetPixelAlpha(image,
+                             pixels),q);
                         }
 
                       else if (magn_methy == 2 || magn_methy == 4)
                         {
                           if (i == 0)
-                             *q=(*pixels);
+                            {
+                              SetPixelRed(large_image,GetPixelRed(image,
+                                 pixels),q);
+                              SetPixelGreen(large_image,GetPixelGreen(image,
+                                 pixels),q);
+                              SetPixelBlue(large_image,GetPixelBlue(image,
+                                 pixels),q);
+                              SetPixelAlpha(large_image,GetPixelAlpha(image,
+                                 pixels),q);
+                            }
 
                           else
                             {
                               /* Interpolate */
-                              (*q).red=(QM) (((ssize_t) (2*i*((*n).red
-                                 -(*pixels).red)+m))/((ssize_t) (m*2))
-                                 +(*pixels).red);
-                              (*q).green=(QM) (((ssize_t) (2*i*((*n).green
-                                 -(*pixels).green)+m))/((ssize_t) (m*2))
-                                 +(*pixels).green);
-                              (*q).blue=(QM) (((ssize_t) (2*i*((*n).blue
-                                 -(*pixels).blue)+m))/((ssize_t) (m*2))
-                                 +(*pixels).blue);
+                              SetPixelRed(large_image,((QM) (((ssize_t)
+                                 (2*i*(GetPixelRed(image,n)
+                                 -GetPixelRed(image,pixels)+m))/
+                                 ((ssize_t) (m*2))
+                                 +GetPixelRed(image,pixels)))),q);
+                              SetPixelGreen(large_image,((QM) (((ssize_t)
+                                 (2*i*(GetPixelGreen(image,n)
+                                 -GetPixelGreen(image,pixels)+m))/
+                                 ((ssize_t) (m*2))
+                                 +GetPixelGreen(image,pixels)))),q);
+                              SetPixelBlue(large_image,((QM) (((ssize_t)
+                                 (2*i*(GetPixelBlue(image,n)
+                                 -GetPixelBlue(image,pixels)+m))/
+                                 ((ssize_t) (m*2))
+                                 +GetPixelBlue(image,pixels)))),q);
 
                               if (image->matte != MagickFalse)
-                                 (*q).opacity=(QM) (((ssize_t)
-                                 (2*i*((*n).opacity
-                                 -(*pixels).opacity)+m))
-                                 /((ssize_t) (m*2))+(*pixels).opacity);
+                                 SetPixelAlpha(large_image, ((QM) (((ssize_t)
+                                    (2*i*(GetPixelAlpha(image,n)
+                                    -GetPixelAlpha(image,pixels)+m))
+                                    /((ssize_t) (m*2))+
+                                   GetPixelAlpha(image,pixels)))),q);
                             }
 
                           if (magn_methy == 4)
                             {
                               /* Replicate nearest */
                               if (i <= ((m+1) << 1))
-                                 (*q).opacity=(*pixels).opacity+0;
+                                 SetPixelAlpha(large_image,GetPixelAlpha(image,
+                                    pixels),q);
                               else
-                                 (*q).opacity=(*n).opacity+0;
+                                 SetPixelAlpha(large_image,GetPixelAlpha(image,
+                                    n),q);
                             }
                         }
 
@@ -5962,21 +6391,40 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                         {
                           /* Replicate nearest */
                           if (i <= ((m+1) << 1))
-                             *q=(*pixels);
+                          {
+                             SetPixelRed(large_image,GetPixelRed(image,
+                                    pixels),q);
+                             SetPixelGreen(large_image,GetPixelGreen(image,
+                                    pixels),q);
+                             SetPixelBlue(large_image,GetPixelBlue(image,
+                                    pixels),q);
+                             SetPixelAlpha(large_image,GetPixelAlpha(image,
+                                    pixels),q);
+                          }
 
                           else
-                             *q=(*n);
+                          {
+                             SetPixelRed(large_image,GetPixelRed(image,n),q);
+                             SetPixelGreen(large_image,GetPixelGreen(image,n),
+                                    q);
+                             SetPixelBlue(large_image,GetPixelBlue(image,n),
+                                    q);
+                             SetPixelAlpha(large_image,GetPixelAlpha(image,n),
+                                    q);
+                          }
 
                           if (magn_methy == 5)
                             {
-                              (*q).opacity=(QM) (((ssize_t) (2*i*((*n).opacity
-                                 -(*pixels).opacity)+m))/((ssize_t) (m*2))
-                                 +(*pixels).opacity);
+                              SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
+                                 (GetPixelAlpha(image,n)
+                                 -GetPixelAlpha(image,pixels))
+                                 +m))/((ssize_t) (m*2))
+                                 +GetPixelAlpha(image,pixels)),q);
                             }
                         }
-                      n++;
-                      q++;
-                      pixels++;
+                      n+=GetPixelChannels(image);
+                      q+=GetPixelChannels(large_image);
+                      pixels+=GetPixelChannels(image);
                     } /* x */
 
                     if (SyncAuthenticPixels(large_image,exception) == 0)
@@ -5985,8 +6433,8 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                   } /* i */
                 } /* y */
 
-                prev=(PixelPacket *) RelinquishMagickMemory(prev);
-                next=(PixelPacket *) RelinquishMagickMemory(next);
+                prev=(Quantum *) RelinquishMagickMemory(prev);
+                next=(Quantum *) RelinquishMagickMemory(next);
 
                 length=image->columns;
 
@@ -6007,17 +6455,17 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
                 for (y=0; y < (ssize_t) image->rows; y++)
                 {
-                  register PixelPacket
+                  register Quantum
                     *pixels;
 
                   q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
-                  pixels=q+(image->columns-length);
-                  n=pixels+1;
+                  pixels=q+(image->columns-length)*GetPixelChannels(image);
+                  n=pixels+GetPixelChannels(image);
 
                   for (x=(ssize_t) (image->columns-length);
                     x < (ssize_t) image->columns; x++)
                   {
-                    /* To do: Rewrite using Get/Set***PixelComponent() */
+                    /* To do: Rewrite using Get/Set***PixelChannel() */
 
                     if (x == (ssize_t) (image->columns-length))
                       m=(ssize_t) mng_info->magn_ml;
@@ -6039,39 +6487,64 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                       if (magn_methx <= 1)
                         {
                           /* replicate previous */
-                          *q=(*pixels);
+                          SetPixelRed(image,GetPixelRed(image,pixels),q);
+                          SetPixelGreen(image,GetPixelGreen(image,pixels),q);
+                          SetPixelBlue(image,GetPixelBlue(image,pixels),q);
+                          SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
                         }
 
                       else if (magn_methx == 2 || magn_methx == 4)
                         {
                           if (i == 0)
-                            *q=(*pixels);
-
+                          {
+                            SetPixelRed(image,GetPixelRed(image,pixels),q);
+                            SetPixelGreen(image,GetPixelGreen(image,pixels),q);
+                            SetPixelBlue(image,GetPixelBlue(image,pixels),q);
+                            SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
+                          }
+
+                          /* To do: Rewrite using Get/Set***PixelChannel() */
                           else
                             {
                               /* Interpolate */
-                              (*q).red=(QM) ((2*i*((*n).red
-                                 -(*pixels).red)+m)
-                                 /((ssize_t) (m*2))+(*pixels).red);
-                              (*q).green=(QM) ((2*i*((*n).green
-                                 -(*pixels).green)
-                                 +m)/((ssize_t) (m*2))+(*pixels).green);
-                              (*q).blue=(QM) ((2*i*((*n).blue
-                                 -(*pixels).blue)+m)
-                                 /((ssize_t) (m*2))+(*pixels).blue);
+                              SetPixelRed(image,(QM) ((2*i*(
+                                 GetPixelRed(image,n)
+                                 -GetPixelRed(image,pixels))+m)
+                                 /((ssize_t) (m*2))+
+                                 GetPixelRed(image,pixels)),q);
+
+                              SetPixelGreen(image,(QM) ((2*i*(
+                                 GetPixelGreen(image,n)
+                                 -GetPixelGreen(image,pixels))+m)
+                                 /((ssize_t) (m*2))+
+                                 GetPixelGreen(image,pixels)),q);
+
+                              SetPixelBlue(image,(QM) ((2*i*(
+                                 GetPixelBlue(image,n)
+                                 -GetPixelBlue(image,pixels))+m)
+                                 /((ssize_t) (m*2))+
+                                 GetPixelBlue(image,pixels)),q);
                               if (image->matte != MagickFalse)
-                                 (*q).opacity=(QM) ((2*i*((*n).opacity
-                                   -(*pixels).opacity)+m)/((ssize_t) (m*2))
-                                   +(*pixels).opacity);
+                                 SetPixelAlpha(image,(QM) ((2*i*(
+                                   GetPixelAlpha(image,n)
+                                   -GetPixelAlpha(image,pixels))+m)
+                                   /((ssize_t) (m*2))+
+                                   GetPixelAlpha(image,pixels)),q);
                             }
 
                           if (magn_methx == 4)
                             {
                               /* Replicate nearest */
                               if (i <= ((m+1) << 1))
-                                 (*q).opacity=(*pixels).opacity+0;
+                              {
+                                 SetPixelAlpha(image,
+                                   GetPixelAlpha(image,pixels)+0,q);
+                              }
                               else
-                                 (*q).opacity=(*n).opacity+0;
+                              {
+                                 SetPixelAlpha(image,
+                                   GetPixelAlpha(image,n)+0,q);
+                              }
                             }
                         }
 
@@ -6079,23 +6552,35 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
                         {
                           /* Replicate nearest */
                           if (i <= ((m+1) << 1))
-                             *q=(*pixels);
+                          {
+                             SetPixelRed(image,GetPixelRed(image,pixels),q);
+                             SetPixelGreen(image,GetPixelGreen(image,pixels),q);
+                             SetPixelBlue(image,GetPixelBlue(image,pixels),q);
+                             SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
+                          }
 
                           else
-                             *q=(*n);
+                          {
+                             SetPixelRed(image,GetPixelRed(image,n),q);
+                             SetPixelGreen(image,GetPixelGreen(image,n),q);
+                             SetPixelBlue(image,GetPixelBlue(image,n),q);
+                             SetPixelAlpha(image,GetPixelAlpha(image,n),q);
+                          }
 
                           if (magn_methx == 5)
                             {
                               /* Interpolate */
-                              (*q).opacity=(QM) ((2*i*((*n).opacity
-                                 -(*pixels).opacity)+m) /((ssize_t) (m*2))
-                                 +(*pixels).opacity);
+                              SetPixelAlpha(image,
+                                 (QM) ((2*i*( GetPixelAlpha(image,n)
+                                 -GetPixelAlpha(image,pixels))+m)/
+                                 ((ssize_t) (m*2))
+                                 +GetPixelAlpha(image,pixels)),q);
                             }
                         }
-                      q++;
+                      q+=GetPixelChannels(image);
                     }
-                    n++;
-                    p++;
+                    n+=GetPixelChannels(image);
+                    p+=GetPixelChannels(image);
                   }
 
                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -6113,15 +6598,15 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
                      for (x=(ssize_t) image->columns-1; x >= 0; x--)
                      {
-                        SetRedPixelComponent(q,ScaleShortToQuantum(
-                            GetRedPixelComponent(q));
-                        SetGreenPixelComponent(q,ScaleShortToQuantum(
-                            GetGreenPixelComponent(q));
-                        SetBluePixelComponent(q,ScaleShortToQuantum(
-                            GetBluePixelComponent(q));
-                        SetOpacityPixelComponent(q,ScaleShortToQuantum(
-                            GetOpacityPixelComponent(q));
-                        q++;
+                        SetPixelRed(image,ScaleShortToQuantum(
+                          GetPixelRed(image,q)),q);
+                        SetPixelGreen(image,ScaleShortToQuantum(
+                          GetPixelGreen(image,q)),q);
+                        SetPixelBlue(image,ScaleShortToQuantum(
+                          GetPixelBlue(image,q)),q);
+                        SetPixelAlpha(image,ScaleShortToQuantum(
+                          GetPixelAlpha(image,q)),q);
+                        q+=GetPixelChannels(image);
                      }
 
                      if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -6260,7 +6745,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "  No images found.  Inserting a background layer.");
 
-      if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
+      if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
         {
           /*
             Allocate next image structure.
@@ -6744,7 +7229,8 @@ ModuleExport void UnregisterPNGImage(void)
 %
 %  The format of the WriteMNGImage method is:
 %
-%      MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
+%      MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
+%        Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows.
 %
@@ -6752,6 +7238,7 @@ ModuleExport void UnregisterPNGImage(void)
 %
 %    o image:  The image.
 %
+%    o exception: return any errors or warnings in this structure.
 %
 %  To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
 %    "To do" under ReadPNGImage):
@@ -6850,7 +7337,7 @@ Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
      allocated_length);
    dp+=description_length;
    *dp++='\n';
-   (void) FormatMagickString(dp,allocated_length-
+   (void) FormatLocaleString(dp,allocated_length-
      (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
    dp+=8;
 
@@ -6931,7 +7418,7 @@ static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
 
 /* Write one PNG image */
 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
-   const ImageInfo *IMimage_info,Image *IMimage)
+  const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
 {
   Image
     *image;
@@ -7011,6 +7498,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     ping_need_colortype_warning,
 
     status,
+    tried_332,
     tried_333,
     tried_444;
 
@@ -7116,6 +7604,90 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   ping_preserve_colormap = mng_info->ping_preserve_colormap;
   ping_need_colortype_warning = MagickFalse;
 
+  /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
+   * i.e., eliminate the ICC profile and set image->rendering_intent.
+   * Note that this will not involve any changes to the actual pixels
+   * but merely passes information to applications that read the resulting
+   * PNG image.
+   */
+   if (ping_exclude_sRGB == MagickFalse)
+   {
+      char
+        *name;
+
+      const StringInfo
+        *profile;
+
+      ResetImageProfileIterator(image);
+      for (name=GetNextImageProfile(image); name != (const char *) NULL; )
+      {
+        profile=GetImageProfile(image,name);
+
+        if (profile != (StringInfo *) NULL)
+          {
+            if ((LocaleCompare(name,"ICC") == 0) ||
+               (LocaleCompare(name,"ICM") == 0))
+              {
+                 unsigned char
+                   *data;
+
+                 png_uint_32
+                   length;
+
+                 length=(png_uint_32) GetStringInfoLength(profile);
+
+                 if (length == 3144)
+                 {
+                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                       "    got a 3144-byte ICC profile (potentially sRGB)");
+
+                   data=GetStringInfoDatum(profile);
+
+                   if (data[52]=='s' && data[53]=='R' &&
+                       data[54]=='G' && data[55]=='B')
+                   {
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "    It is the HP-Microsoft sRGB)");
+                      if (image->rendering_intent==UndefinedIntent);
+                        image->rendering_intent=PerceptualIntent;
+                   }
+                   else
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "    It is not sRGB (%c%c%c%c)",data[52],
+                          data[53],data[54],data[55]);
+                   
+                 }
+                 else if (length == 3052)
+                 {
+                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                       "    got a 3052-byte ICC profile (potentially sRGB)");
+
+                   data=GetStringInfoDatum(profile);
+
+                   if (data[336]=='s' && data[337]=='R' &&
+                       data[338]=='G' && data[339]=='B')
+                   {
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "    It is the ICC no-black sRGB)");
+                      if (image->rendering_intent==UndefinedIntent);
+                        image->rendering_intent=PerceptualIntent;
+                   }
+                   else
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "    It is not sRGB (%c%c%c%c)",data[52],
+                          data[53],data[54],data[55]);
+                   
+                 }
+                 else
+                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                        "    got a %lu-byte ICC profile",
+                        (unsigned long) length);
+              }
+          }
+        name=GetNextImageProfile(image);
+      }
+  }
+
   number_opaque = 0;
   number_semitransparent = 0;
   number_transparent = 0;
@@ -7133,6 +7705,15 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           "    storage_class=PseudoClass");
     }
 
+  if (image->storage_class == PseudoClass && 
+     (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
+     (mng_info->write_png_colortype != 0 &&
+     mng_info->write_png_colortype != 4)))
+    {
+      (void) SyncImage(image);
+      image->storage_class = DirectClass;
+    }
+
   if (ping_preserve_colormap == MagickFalse)
     {
       if (image->storage_class != PseudoClass && image->colormap != NULL)
@@ -7145,8 +7726,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
            image->colormap=NULL;
         }
     }
-   
-  if (image->colorspace != RGBColorspace)
+
+  if (IsRGBColorspace(image->colorspace) == MagickFalse)
     (void) TransformImageColorspace(image,RGBColorspace);
 
   /*
@@ -7167,61 +7748,226 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     }
 #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 */
+  /* Respect the -depth option */
   if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
     {
-    }
-#endif
+       register Quantum
+         *r;
 
-  /* To do: set to next higher multiple of 8 */
-  if (image->depth < 8)
-     image->depth=8;
+       ExceptionInfo
+         *exception;
 
-#if (MAGICKCORE_QUANTUM_DEPTH > 16)
-  /* PNG does not handle depths greater than 16 so reduce it even
-   * if lossy
-   */
-  if (image->depth > 16)
-      image->depth=16;
-#endif
+       exception=(&image->exception);
 
-#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
+       if (image->depth > 8)
+         {
+#if MAGICKCORE_QUANTUM_DEPTH > 16
+           /* Scale to 16-bit */
+           LBR16PacketRGBO(image->background_color);
 
-  /* 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.
-   */
+           for (y=0; y < (ssize_t) image->rows; y++)
+           {
+             r=GetAuthenticPixels(image,0,y,image->columns,1,
+                 exception);
 
-  tried_333 = MagickFalse;
-  tried_444 = MagickFalse;
+             if (r == (Quantum *) NULL)
+               break;
 
-  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.
+             for (x=0; x < (ssize_t) image->columns; x++)
+             {
+                LBR16PixelRGBA(r);
+                r++;
+             }
+
+             if (SyncAuthenticPixels(image,exception) == MagickFalse)
+                break;
+           }
+
+           if (image->storage_class == PseudoClass && image->colormap != NULL)
+           {
+             for (i=0; i < (ssize_t) image->colors; i++)
+             {
+               LBR16PacketRGBO(image->colormap[i]);
+             }
+           }
+#endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
+         }
+
+       else if (image->depth > 4)
+         {
+#if MAGICKCORE_QUANTUM_DEPTH > 8
+           /* Scale to 8-bit */
+           LBR08PacketRGBO(image->background_color);
+
+           for (y=0; y < (ssize_t) image->rows; y++)
+           {
+             r=GetAuthenticPixels(image,0,y,image->columns,1,
+                 exception);
+
+             if (r == (Quantum *) NULL)
+               break;
+
+             for (x=0; x < (ssize_t) image->columns; x++)
+             {
+                LBR08PixelRGBA(r);
+                r++;
+             }
+
+             if (SyncAuthenticPixels(image,exception) == MagickFalse)
+                break;
+           }
+
+           if (image->storage_class == PseudoClass && image->colormap != NULL)
+           {
+             for (i=0; i < (ssize_t) image->colors; i++)
+             {
+               LBR08PacketRGBO(image->colormap[i]);
+             }
+           }
+#endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
+         }
+       else
+         if (image->depth > 2)
+         {
+           /* Scale to 4-bit */
+           LBR04PacketRGBO(image->background_color);
+
+           for (y=0; y < (ssize_t) image->rows; y++)
+           {
+             r=GetAuthenticPixels(image,0,y,image->columns,1,
+                 exception);
+
+             if (r == (Quantum *) NULL)
+               break;
+
+             for (x=0; x < (ssize_t) image->columns; x++)
+             {
+                LBR04PixelRGBA(r);
+                r++;
+             }
+
+             if (SyncAuthenticPixels(image,exception) == MagickFalse)
+                break;
+           }
+
+           if (image->storage_class == PseudoClass && image->colormap != NULL)
+           {
+             for (i=0; i < (ssize_t) image->colors; i++)
+             {
+               LBR04PacketRGBO(image->colormap[i]);
+             }
+           }
+         }
+
+       else if (image->depth > 1)
+         {
+           /* Scale to 2-bit */
+           LBR02PacketRGBO(image->background_color);
+
+           for (y=0; y < (ssize_t) image->rows; y++)
+           {
+             r=GetAuthenticPixels(image,0,y,image->columns,1,
+                 exception);
+
+             if (r == (Quantum *) NULL)
+               break;
+
+             for (x=0; x < (ssize_t) image->columns; x++)
+             {
+                LBR02PixelRGBA(r);
+                r++;
+             }
+
+             if (SyncAuthenticPixels(image,exception) == MagickFalse)
+                break;
+           }
+
+           if (image->storage_class == PseudoClass && image->colormap != NULL)
+           {
+             for (i=0; i < (ssize_t) image->colors; i++)
+             {
+               LBR02PacketRGBO(image->colormap[i]);
+             }
+           }
+         }
+       else
+         {
+           /* Scale to 1-bit */
+           LBR01PacketRGBO(image->background_color);
+
+           for (y=0; y < (ssize_t) image->rows; y++)
+           {
+             r=GetAuthenticPixels(image,0,y,image->columns,1,
+                 exception);
+
+             if (r == (Quantum *) NULL)
+               break;
+
+             for (x=0; x < (ssize_t) image->columns; x++)
+             {
+                LBR01PixelRGBA(r);
+                r++;
+             }
+
+             if (SyncAuthenticPixels(image,exception) == MagickFalse)
+                break;
+           }
+
+           if (image->storage_class == PseudoClass && image->colormap != NULL)
+           {
+             for (i=0; i < (ssize_t) image->colors; i++)
+             {
+               LBR01PacketRGBO(image->colormap[i]);
+             }
+           }
+         }
+    }
+
+  /* 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
+   */
+  if (image->depth > 8)
+      image->depth=16;
+#endif
+
+#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
+
+  /* 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 then to a simple 3-3-2-1 RGBA
+   * palette.  Then (To do) we take care of a final reduction that is only
+   * needed if there are still 256 colors present and one of them has both
+   * transparent and opaque instances.
+   */
+
+  tried_332 = MagickFalse;
+  tried_333 = MagickFalse;
+  tried_444 = MagickFalse;
+
+  for (j=0; j<6; 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
+     * If image->matte is MagickFalse, we ignore the alpha channel
      * even though it sometimes contains left-over non-opaque values.
      *
      * Also we gather some information (number of opaque, transparent,
@@ -7243,14 +7989,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
      semitransparent[260],
      transparent[260];
 
-   register IndexPacket
-     *indexes;
+   register const Quantum
+     *s;
 
-   register const PixelPacket
-     *s,
-     *q;
-
-   register PixelPacket
+   register Quantum
+     *q,
      *r;
 
    if (logging != MagickFalse)
@@ -7273,7 +8016,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
              "      Original colormap:");
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-             "        i    (red,green,blue,opacity)");
+             "        i    (red,green,blue,alpha)");
 
          for (i=0; i < 256; i++)
          {
@@ -7283,7 +8026,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                     (int) image->colormap[i].red,
                     (int) image->colormap[i].green,
                     (int) image->colormap[i].blue,
-                    (int) image->colormap[i].opacity);
+                    (int) image->colormap[i].alpha);
          }
 
          for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
@@ -7296,7 +8039,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                     (int) image->colormap[i].red,
                     (int) image->colormap[i].green,
                     (int) image->colormap[i].blue,
-                    (int) image->colormap[i].opacity);
+                    (int) image->colormap[i].alpha);
              }
          }
        }
@@ -7324,25 +8067,26 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
      {
        q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
 
-       if (q == (PixelPacket *) NULL)
+       if (q == (Quantum *) NULL)
          break;
 
        for (x=0; x < (ssize_t) image->columns; x++)
        {
-           if (image->matte == MagickFalse || q->opacity == OpaqueOpacity)
+           if (image->matte == MagickFalse ||
+              GetPixelAlpha(image,q) == OpaqueAlpha)
              {
                if (number_opaque < 259)
                  {
                    if (number_opaque == 0)
                      {
-                       GetRGBPixelComponents(q, opaque[0]);
-                       opaque[0].opacity=OpaqueOpacity;
+                       GetPixelPacket(image, q, opaque);
+                       opaque[0].alpha=OpaqueAlpha;
                        number_opaque=1;
                      }
 
                    for (i=0; i< (ssize_t) number_opaque; i++)
                      {
-                       if (IsColorEqual(q, opaque+i))
+                       if (IsPixelEquivalent(image,q, opaque+i))
                          break;
                      }
 
@@ -7350,32 +8094,32 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                        number_opaque < 259)
                      {
                        number_opaque++;
-                       GetRGBPixelComponents(q, opaque[i]);
-                       opaque[i].opacity=OpaqueOpacity;
+                       GetPixelPacket(image, q, opaque+i);
+                       opaque[i].alpha=OpaqueAlpha;
                      }
                  }
              }
-           else if (q->opacity == TransparentOpacity)
+           else if (GetPixelAlpha(image,q) == TransparentAlpha)
              {
                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);
+                       GetPixelPacket(image, q, transparent);
+                       ping_trans_color.red=(unsigned short)
+                         GetPixelRed(image,q);
+                       ping_trans_color.green=(unsigned short)
+                         GetPixelGreen(image,q);
+                       ping_trans_color.blue=(unsigned short)
+                         GetPixelBlue(image,q);
+                       ping_trans_color.gray=(unsigned short)
+                         GetPixelRed(image,q);
                        number_transparent = 1;
                      }
 
                    for (i=0; i< (ssize_t) number_transparent; i++)
                      {
-                       if (IsColorEqual(q, transparent+i))
+                       if (IsPixelEquivalent(image,q, transparent+i))
                          break;
                      }
 
@@ -7383,7 +8127,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                        number_transparent < 259)
                      {
                        number_transparent++;
-                       GetRGBOPixelComponents(q, transparent[i]);
+                       GetPixelPacket(image,q,transparent+i);
                      }
                  }
              }
@@ -7393,15 +8137,15 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                  {
                    if (number_semitransparent == 0)
                      {
-                       GetRGBOPixelComponents(q, semitransparent[0]);
+                       GetPixelPacket(image,q,semitransparent);
                        number_semitransparent = 1;
                      }
 
                    for (i=0; i< (ssize_t) number_semitransparent; i++)
                      {
-                       if (IsColorEqual(q, semitransparent+i)
-                           && GetOpacityPixelComponent(q) ==
-                           semitransparent[i].opacity)
+                       if (IsPixelEquivalent(image,q, semitransparent+i)
+                           && GetPixelAlpha(image,q) ==
+                           semitransparent[i].alpha)
                          break;
                      }
 
@@ -7409,15 +8153,16 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                        number_semitransparent < 259)
                      {
                        number_semitransparent++;
-                       GetRGBOPixelComponents(q, semitransparent[i]);
+                       GetPixelPacket(image, q, semitransparent+i);
                      }
                  }
              }
-           q++;
+           q+=GetPixelChannels(image);
         }
      }
 
-     if (ping_exclude_bKGD == MagickFalse)
+     if (mng_info->write_png8 == MagickFalse &&
+         ping_exclude_bKGD == MagickFalse)
        {
          /* Add the background color to the palette, if it
           * isn't already there.
@@ -7487,51 +8232,52 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
              {
                q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
 
-               if (q == (PixelPacket *) NULL)
+               if (q == (Quantum *) NULL)
+                 break;
+
+               s=q;
+               for (x=0; x < (ssize_t) image->columns; x++)
+               {
+                 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
+                     GetPixelRed(image,s) != GetPixelBlue(image,s))
+                   {
+                      ping_have_color=MagickTrue;
+                      ping_have_non_bw=MagickTrue;
+                      break;
+                   }
+                 s+=GetPixelChannels(image);
+               }
+
+               if (ping_have_color != MagickFalse)
                  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++;
-                   }
-                 }
-
                if (ping_have_non_bw == MagickFalse)
                  {
                    s=q;
                    for (x=0; x < (ssize_t) image->columns; x++)
                    {
-                     if (GetRedPixelComponent(s) != 0 &&
-                         GetRedPixelComponent(s) != QuantumRange)
+                     if (GetPixelRed(image,s) != 0 &&
+                         GetPixelRed(image,s) != QuantumRange)
                        {
                          ping_have_non_bw=MagickTrue;
+                         break;
                        }
-                     s++;
+                     s+=GetPixelChannels(image);
                    }
-                 }
+               }
              }
-           } 
-       } 
+           }
+       }
 
      if (image_colors < 257)
        {
          PixelPacket
            colormap[260];
-             
+
          /*
           * Initialize image colormap.
           */
@@ -7555,7 +8301,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
          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
           */
@@ -7598,7 +8344,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
             image->colors = image_colors;
 
-            if (AcquireImageColormap(image,image_colors) ==
+            if (AcquireImageColormap(image,image_colors,exception) ==
                 MagickFalse)
                ThrowWriterException(ResourceLimitError,
                    "MemoryAllocationFailed");
@@ -7611,7 +8357,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                       "      image->colors=%d (%d)",
                       (int) image->colors, image_colors);
+
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                       "      Update the pixel indexes");
               }
@@ -7623,30 +8369,25 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
               q=GetAuthenticPixels(image,0,y,image->columns,1,
                   exception);
 
-              if (q == (PixelPacket *) NULL)
+              if (q == (Quantum *) 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))
+                      image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
+                      image->colormap[i].red == GetPixelRed(image,q) &&
+                      image->colormap[i].green == GetPixelGreen(image,q) &&
+                      image->colormap[i].blue == GetPixelBlue(image,q))
                   {
-                    indexes[x]=(IndexPacket) i;
+                    SetPixelIndex(image,i,q);
                     break;
                   }
                 }
-                q++;
+                q+=GetPixelChannels(image);
               }
 
               if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -7663,7 +8404,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
          if (image->colormap != NULL)
            {
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                 "       i     (red,green,blue,opacity)");
+                 "       i     (red,green,blue,alpha)");
 
              for (i=0; i < (ssize_t) image->colors; i++)
              {
@@ -7675,7 +8416,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                         (int) image->colormap[i].red,
                         (int) image->colormap[i].green,
                         (int) image->colormap[i].blue,
-                        (int) image->colormap[i].opacity);
+                        (int) image->colormap[i].alpha);
                  }
              }
            }
@@ -7734,9 +8475,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
       break;
 
     /* PNG8 can't have semitransparent colors so we threshold the
-     * opacity to 0 or OpaqueOpacity
+     * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
+     * transparent color so if more than one is transparent we merge
+     * them into image->background_color.
      */
-    if (number_semitransparent != 0)
+    if (number_semitransparent != 0 || number_transparent > 1)
       {
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
             "    Thresholding the alpha channel to binary");
@@ -7746,26 +8489,30 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           r=GetAuthenticPixels(image,0,y,image->columns,1,
               exception);
 
-          if (r == (PixelPacket *) NULL)
+          if (r == (Quantum *) NULL)
             break;
 
           for (x=0; x < (ssize_t) image->columns; x++)
           {
-              SetOpacityPixelComponent(r,
-              (GetOpacityPixelComponent(r) > TransparentOpacity/2) ?
-                   TransparentOpacity : OpaqueOpacity);
-              r++;
+              if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
+                {
+                  SetPixelPacket(image,&image->background_color,r);
+                  SetPixelAlpha(image,TransparentAlpha,r);
+                }
+              else
+                  SetPixelAlpha(image,OpaqueAlpha,r);
+              r+=GetPixelChannels(image);
           }
-  
+
           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;
+                image->colormap[i].alpha =
+                    (image->colormap[i].alpha > TransparentAlpha/2 ?
+                    TransparentAlpha : OpaqueAlpha);
         }
       continue;
     }
@@ -7783,18 +8530,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
         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);
+        LBR04PacketRGB(image->background_color);
 
         if (logging != MagickFalse)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -7807,30 +8543,16 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
             r=GetAuthenticPixels(image,0,y,image->columns,1,
                 exception);
 
-            if (r == (PixelPacket *) NULL)
+            if (r == (Quantum *) NULL)
               break;
 
             for (x=0; x < (ssize_t) image->columns; x++)
             {
-              if (r->opacity == TransparentOpacity)
-                {
-                  SetRGBPixelComponents(r,image->background_color);
-                }
-              else
-                {
-                  r->red=ScaleCharToQuantum(
-                       (ScaleQuantumToChar(r->red) & 0xf0) |
-                       (ScaleQuantumToChar(r->red) & 0xf0) >> 4);
-                  r->green=ScaleCharToQuantum(
-                       (ScaleQuantumToChar(r->green) & 0xf0) |
-                       (ScaleQuantumToChar(r->green) & 0xf0) >> 4);
-                  r->blue=ScaleCharToQuantum(
-                       (ScaleQuantumToChar(r->blue) & 0xf0) |
-                       (ScaleQuantumToChar(r->blue) & 0xf0) >> 4);
-                }
+              if (GetPixelAlpha(image,r) == OpaqueAlpha)
+                  LBR04PixelRGB(r);
               r++;
             }
-    
+
             if (SyncAuthenticPixels(image,exception) == MagickFalse)
                break;
           }
@@ -7842,17 +8564,10 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           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));
+            LBR04PacketRGB(image->colormap[i]);
           }
         }
         continue;
@@ -7866,21 +8581,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
         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);
+        LBR03PacketRGB(image->background_color);
 
         if (logging != MagickFalse)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -7893,35 +8594,16 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
             r=GetAuthenticPixels(image,0,y,image->columns,1,
                 exception);
 
-            if (r == (PixelPacket *) NULL)
+            if (r == (Quantum *) NULL)
               break;
 
             for (x=0; x < (ssize_t) image->columns; x++)
             {
-              if (r->opacity == TransparentOpacity)
-                {
-                  r->red = image->background_color.red;
-                  r->green = image->background_color.green;
-                  r->blue = image->background_color.blue;
-                }
-              else
-                {
-                  r->red=ScaleCharToQuantum(
-                       (ScaleQuantumToChar(r->red) & 0xe0) |
-                       (ScaleQuantumToChar(r->red) & 0xe0) >> 3 |
-                       (ScaleQuantumToChar(r->red) & 0xc0) >> 6);
-                  r->green=ScaleCharToQuantum(
-                       (ScaleQuantumToChar(r->green) & 0xe0) |
-                       (ScaleQuantumToChar(r->green) & 0xe0) >> 3 |
-                       (ScaleQuantumToChar(r->green) & 0xc0) >> 6);
-                  r->blue=ScaleCharToQuantum(
-                       (ScaleQuantumToChar(r->blue) & 0xe0) |
-                       (ScaleQuantumToChar(r->blue) & 0xe0) >> 3 |
-                       (ScaleQuantumToChar(r->blue) & 0xc0) >> 6);
-                }
+              if (GetPixelAlpha(image,r) == OpaqueAlpha)
+                  LBR03RGB(r);
               r++;
             }
-    
+
             if (SyncAuthenticPixels(image,exception) == MagickFalse)
                break;
           }
@@ -7935,38 +8617,25 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
               "    Quantizing the colormap to 3-3-3-1");
           for (i=0; i<image_colors; i++)
           {
-              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);
+              LBR03PacketRGB(image->colormap[i]);
           }
         }
         continue;
       }
 
-    if (image_colors == 0 || image_colors > 256)
+    if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
       {
         if (logging != MagickFalse)
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                "    Quantizing the background color to 3-3-2");
 
+        tried_332 = MagickTrue;
+
         /* Red and green were already done so we only quantize the blue
          * channel
          */
 
-        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);
+        LBR02PacketBlue(image->background_color);
 
         if (logging != MagickFalse)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -7979,26 +8648,16 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
             r=GetAuthenticPixels(image,0,y,image->columns,1,
                 exception);
 
-            if (r == (PixelPacket *) NULL)
+            if (r == (Quantum *) NULL)
               break;
 
             for (x=0; x < (ssize_t) image->columns; x++)
             {
-              if (r->opacity == TransparentOpacity)
-                {
-                  SetRGBPixelComponents(r,image->background_color);
-                }
-              else
-                {
-                  r->blue=ScaleCharToQuantum(
-                      (ScaleQuantumToChar(r->blue) & 0xc0) |
-                      (ScaleQuantumToChar(r->blue) & 0xc0) >> 2 |
-                      (ScaleQuantumToChar(r->blue) & 0xc0) >> 4 |
-                      (ScaleQuantumToChar(r->blue) & 0xc0) >> 6);
-                }
+              if (GetPixelAlpha(image,r) == OpaqueAlpha)
+                  LBR02PixelBlue(r);
               r++;
             }
-    
+
             if (SyncAuthenticPixels(image,exception) == MagickFalse)
                break;
           }
@@ -8012,16 +8671,68 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
               "    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);
+              LBR02PacketBlue(image->colormap[i]);
           }
       }
       continue;
     }
     break;
+
+    if (image_colors == 0 || image_colors > 256)
+    {
+      /* Take care of special case with 256 colors + 1 transparent
+       * color.  We don't need to quantize to 2-3-2-1; we only need to
+       * eliminate one color, so we'll merge the two darkest red
+       * colors (0x49, 0, 0) -> (0x24, 0, 0).
+       */
+      if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
+          ScaleQuantumToChar(image->background_color.green) == 0x00 &&
+          ScaleQuantumToChar(image->background_color.blue) == 0x00)
+      {
+         image->background_color.red=ScaleCharToQuantum(0x24);
+      }
+
+      if (image->colormap == NULL)
+      {
+        for (y=0; y < (ssize_t) image->rows; y++)
+        {
+          r=GetAuthenticPixels(image,0,y,image->columns,1,
+              exception);
+
+          if (r == (Quantum *) NULL)
+            break;
+
+          for (x=0; x < (ssize_t) image->columns; x++)
+          {
+            if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
+                ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
+                ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
+                GetPixelAlpha(image,r) == OpaqueAlpha)
+              {
+                SetPixelRed(image,ScaleCharToQuantum(0x24),r);
+              }
+            r+=GetPixelChannels(image);
+          }
+
+          if (SyncAuthenticPixels(image,exception) == MagickFalse)
+             break;
+
+        }
+      }
+
+      else
+      {
+         for (i=0; i<image_colors; i++)
+         {
+            if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
+                ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
+                ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
+            {
+               image->colormap[i].red=ScaleCharToQuantum(0x24);
+            }
+         }
+      }
+    }
   }
   /* END OF BUILD_PALETTE */
 
@@ -8032,7 +8743,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   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;
@@ -8041,7 +8752,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
         mng_info->write_png_colortype = 7;
 
       if (colortype != 0 &&
-         mng_info->write_png_colortype != (ssize_t) colortype)
+         mng_info->write_png_colortype != colortype)
         ping_need_colortype_warning=MagickTrue;
 
     }
@@ -8067,7 +8778,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
            ExceptionInfo
              *exception;
 
-           register const PixelPacket
+           register const Quantum
              *q;
 
            exception=(&image->exception);
@@ -8076,26 +8787,26 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
            {
              q=GetVirtualPixels(image,0,y,image->columns,1, exception);
 
-             if (q == (PixelPacket *) NULL)
+             if (q == (Quantum *) 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)
+                 if (GetPixelAlpha(image,q) != TransparentAlpha &&
+                     (unsigned short) GetPixelRed(image,q) ==
+                                     ping_trans_color.red &&
+                     (unsigned short) GetPixelGreen(image,q) ==
+                                     ping_trans_color.green &&
+                     (unsigned short) GetPixelBlue(image,q) ==
+                                     ping_trans_color.blue)
                    {
                      ping_have_cheap_transparency = MagickFalse;
                      break;
                    }
 
-                 q++;
+                 q+=GetPixelChannels(image);
              }
-    
+
              if (ping_have_cheap_transparency == MagickFalse)
                 break;
            }
@@ -8115,7 +8826,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                      break;
                   }
          }
-       
+
        if (logging != MagickFalse)
          {
            if (ping_have_cheap_transparency == MagickFalse)
@@ -8434,13 +9145,13 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
       }
     } /* end of write_png8 */
 
-  else if (mng_info->write_png24)
+  else if (mng_info->write_png24 || mng_info->write_png_colortype == 3)
     {
       image_matte=MagickFalse;
       ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
     }
 
-  else if (mng_info->write_png32)
+  else if (mng_info->write_png32 || mng_info->write_png_colortype == 7)
     {
       image_matte=MagickTrue;
       ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
@@ -8628,7 +9339,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           else
             {
               unsigned int
-                mask; 
+                mask;
 
               mask=0xffff;
 
@@ -8654,7 +9365,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
 
               ping_trans_color.gray=(png_uint_16)
-                (ScaleQuantumToShort(PixelIntensityToQuantum(
+                (ScaleQuantumToShort(GetPixelPacketIntensity(
                    image->colormap)) & mask);
 
               ping_trans_color.index=(png_byte) 0;
@@ -8732,7 +9443,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           image_depth=MAGICKCORE_QUANTUM_DEPTH;
 
         if ((image_colors == 0) ||
-             ((ssize_t) (image_colors-1) > MaxColormapSize))
+             ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
           image_colors=(int) (one << image_depth);
 
         if (image_depth > 8)
@@ -8841,7 +9552,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) < (size_t) number_colors)
                   ping_bit_depth <<= 1;
               }
 
@@ -8871,8 +9582,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
                     for (i=0; i < ping_num_trans; i++)
                     {
-                       ping_trans_alpha[i]= (png_byte) (255-
-                          ScaleQuantumToChar(image->colormap[i].opacity));
+                       ping_trans_alpha[i]= (png_byte) 
+                         ScaleQuantumToChar(image->colormap[i].alpha);
                     }
                   }
               }
@@ -8933,7 +9644,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
          {
 
          ping_background.gray=(png_uint_16)
-           (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
+           ((maxval/255.)*((GetPixelPacketIntensity(&image->background_color)))
+                                    +.5);
 
          if (logging != MagickFalse)
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -8945,8 +9657,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
          ping_have_bKGD = MagickTrue;
          }
 
-         ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
-           ping_trans_color.gray));
+         if (logging != MagickFalse)
+           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             "  Scaling ping_trans_color.gray from %d",
+             (int)ping_trans_color.gray);
+
+         ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
+           ping_trans_color.gray)+.5);
+
+         if (logging != MagickFalse)
+           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             "      to %d", (int)ping_trans_color.gray);
       }
 
   if (ping_exclude_bKGD == MagickFalse)
@@ -9018,88 +9739,148 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
   png_set_compression_mem_level(ping, 9);
 
+  /* Untangle the "-quality" setting:
+
+     Undefined is 0; the default is used.
+     Default is 75
+
+     10's digit:
+
+        0: Use Z_HUFFMAN_ONLY strategy with the
+           zlib default compression level
+
+        1-9: the zlib compression level
+
+     1's digit:
+
+        0-4: the PNG filter method
+
+        5:   libpng adaptive filtering if compression level > 5
+             libpng filter type "none" if compression level <= 5
+                or if image is grayscale or palette
+             
+        6:   libpng adaptive filtering
+
+        7:   "LOCO" filtering (intrapixel differing) if writing
+             a MNG, othewise "none".  Did not work in IM-6.7.0-9
+             and earlier because of a missing "else".
+
+        8:   Z_RLE strategy, all filters
+             Unused prior to IM-6.7.0-10, was same as 6
+
+        9:   Z_RLE strategy, no PNG filters
+             Unused prior to IM-6.7.0-10, was same as 6
+
+    Note that using the -quality option, not all combinations of
+    PNG filter type, zlib compression level, and zlib compression
+    strategy are possible.  This will be addressed soon in a
+    release that accomodates "-define PNG:compression-strategy", etc.
+
+   */
+
   quality=image->quality == UndefinedCompressionQuality ? 75UL :
      image->quality;
 
-  if (quality > 9)
+  if (quality <= 9)
+    {
+      if (mng_info->write_png_compression_strategy == 0)
+        mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
+    }
+  
+  else if (mng_info->write_png_compression_level == 0)
     {
       int
         level;
 
       level=(int) MagickMin((ssize_t) quality/10,9);
 
-      if (logging != MagickFalse)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "    Compression level: %d",level);
-
-      png_set_compression_level(ping,level);
+      mng_info->write_png_compression_level = level+1;
     }
 
-  else
+  if (mng_info->write_png_compression_strategy == 0)
     {
-      if (logging != MagickFalse)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "    Compression strategy: Z_HUFFMAN_ONLY");
-
-      png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
+        if ((quality %10) == 8 || (quality %10) == 9)
+            mng_info->write_png_compression_strategy=Z_RLE;
     }
 
-  if (logging != MagickFalse)
-    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-      "  Setting up filtering");
+  if (mng_info->write_png_compression_filter == 0)
+        mng_info->write_png_compression_filter=((int) quality % 10) + 1;
 
-#if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
-  /* This became available in libpng-1.0.9.  Output must be a MNG. */
-  if (mng_info->write_mng && ((quality % 10) == 7))
+  if (logging != MagickFalse)
     {
-      if (logging != MagickFalse)
+     if (mng_info->write_png_compression_level)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "    Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
-
-      ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
-    }
+          "    Compression level:    %d",
+            (int) mng_info->write_png_compression_level-1);
 
-  else
-    if (logging != MagickFalse)
-      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-        "    Filter_type: 0");
-#endif
+     if (mng_info->write_png_compression_strategy)
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    Compression strategy: %d",
+            (int) mng_info->write_png_compression_strategy-1);
 
-  {
-    int
-      base_filter;
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "  Setting up filtering");
 
-    if ((quality % 10) > 5)
-      base_filter=PNG_ALL_FILTERS;
+        if (mng_info->write_png_compression_filter == 6)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    Base filter method: ADAPTIVE");
+        else if (mng_info->write_png_compression_filter == 0 ||
+                 mng_info->write_png_compression_filter == 1)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    Base filter method: NONE");
+        else
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    Base filter method: %d",
+            (int) mng_info->write_png_compression_filter-1);
+    }
 
-    else
-      if ((quality % 10) != 5)
-        base_filter=(int) quality % 10;
+  if (mng_info->write_png_compression_level != 0)
+    png_set_compression_level(ping,mng_info->write_png_compression_level-1);
 
+  if (mng_info->write_png_compression_filter == 6)
+    {
+      if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
+         ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
+         (quality < 50))
+        png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
       else
-        if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
-            ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
-            (quality < 50))
-          base_filter=PNG_NO_FILTERS;
-
-        else
-          base_filter=PNG_ALL_FILTERS;
+        png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
+     }
+  else if (mng_info->write_png_compression_filter == 7 ||
+      mng_info->write_png_compression_filter == 10)
+    png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
 
-    if (logging != MagickFalse)
+  else if (mng_info->write_png_compression_filter == 8)
+    {
+#if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
+      if (mng_info->write_mng)
       {
-        if (base_filter == PNG_ALL_FILTERS)
-          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-            "    Base filter method: ADAPTIVE");
-        else
-          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-            "    Base filter method: NONE");
+         if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
+             ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
+        ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
       }
+#endif
+      png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
+    }
 
-    png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
-  }
+  else if (mng_info->write_png_compression_filter == 9)
+    png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
 
-  if ((ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse) &&
-     (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
+  else if (mng_info->write_png_compression_filter != 0)
+    png_set_filter(ping,PNG_FILTER_TYPE_BASE,
+       mng_info->write_png_compression_filter-1);
+
+  if (mng_info->write_png_compression_strategy != 0)
+    png_set_compression_strategy(ping,
+       mng_info->write_png_compression_strategy-1);
+
+  /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
+  if (ping_exclude_sRGB != MagickFalse ||
+     (image->rendering_intent == UndefinedIntent))
+  {
+    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; )
@@ -9115,7 +9896,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
                if (ping_exclude_iCCP == MagickFalse)
                  {
-                       png_set_iCCP(ping,ping_info,(const png_charp) name,0,
+                       png_set_iCCP(ping,ping_info,(png_charp) name,0,
 #if (PNG_LIBPNG_VER < 10500)
                          (png_charp) GetStringInfoDatum(profile),
 #else
@@ -9142,6 +9923,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
         name=GetNextImageProfile(image);
       }
+    }
   }
 
 #if defined(PNG_WRITE_sRGB_SUPPORTED)
@@ -9161,9 +9943,6 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           (void) png_set_sRGB(ping,ping_info,(
             Magick_RenderingIntent_to_PNG_RenderingIntent(
               image->rendering_intent)));
-
-          if (ping_exclude_gAMA == MagickFalse)
-            png_set_gAMA(ping,ping_info,0.45455);
         }
     }
 
@@ -9558,7 +10337,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
        ping_have_non_bw == MagickFalse)
     {
       /* Palette, Bilevel, or Opaque Monochrome */
-      register const PixelPacket
+      register const Quantum
         *p;
 
       quantum_info->depth=8;
@@ -9575,12 +10354,12 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
 
-          if (p == (const PixelPacket *) NULL)
+          if (p == (const Quantum *) NULL)
             break;
 
           if (mng_info->IsPalette)
             {
-              (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+              (void) ExportQuantumPixels(image,(CacheView *) NULL,
                 quantum_info,GrayQuantum,ping_pixels,&image->exception);
               if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
                   mng_info->write_png_depth &&
@@ -9595,7 +10374,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
           else
             {
-              (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+              (void) ExportQuantumPixels(image,(CacheView *) NULL,
                 quantum_info,RedQuantum,ping_pixels,&image->exception);
             }
 
@@ -9627,7 +10406,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
          (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
          (mng_info->IsPalette) && ping_have_color == MagickFalse)
         {
-          register const PixelPacket
+          register const Quantum
             *p;
 
           for (pass=0; pass < num_passes; pass++)
@@ -9637,17 +10416,17 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
           {
             p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
 
-            if (p == (const PixelPacket *) NULL)
+            if (p == (const Quantum *) NULL)
               break;
 
             if (ping_color_type == PNG_COLOR_TYPE_GRAY)
               {
                 if (mng_info->IsPalette)
-                  (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                  (void) ExportQuantumPixels(image,(CacheView *) NULL,
                     quantum_info,GrayQuantum,ping_pixels,&image->exception);
 
                 else
-                  (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                  (void) ExportQuantumPixels(image,(CacheView *) NULL,
                     quantum_info,RedQuantum,ping_pixels,&image->exception);
 
                 if (logging != MagickFalse && y == 0)
@@ -9661,7 +10440,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                          "    Writing GRAY_ALPHA PNG pixels (2)");
 
-                (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                (void) ExportQuantumPixels(image,(CacheView *) NULL,
                   quantum_info,GrayAlphaQuantum,ping_pixels,&image->exception);
               }
 
@@ -9683,7 +10462,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
       else
         {
-          register const PixelPacket
+          register const Quantum
             *p;
 
           for (pass=0; pass < num_passes; pass++)
@@ -9697,23 +10476,23 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                 p=GetVirtualPixels(image,0,y,image->columns,1,
                    &image->exception);
 
-                if (p == (const PixelPacket *) NULL)
+                if (p == (const Quantum *) NULL)
                   break;
 
                 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
                   {
                     if (image->storage_class == DirectClass)
-                      (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                      (void) ExportQuantumPixels(image,(CacheView *) NULL,
                         quantum_info,RedQuantum,ping_pixels,&image->exception);
 
                     else
-                      (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                      (void) ExportQuantumPixels(image,(CacheView *) NULL,
                         quantum_info,GrayQuantum,ping_pixels,&image->exception);
                   }
 
                 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
                   {
-                    (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                    (void) ExportQuantumPixels(image,(CacheView *) NULL,
                       quantum_info,GrayAlphaQuantum,ping_pixels,
                       &image->exception);
 
@@ -9723,11 +10502,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                   }
 
                 else if (image_matte != MagickFalse)
-                  (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                  (void) ExportQuantumPixels(image,(CacheView *) NULL,
                     quantum_info,RGBAQuantum,ping_pixels,&image->exception);
 
                 else
-                  (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                  (void) ExportQuantumPixels(image,(CacheView *) NULL,
                     quantum_info,RGBQuantum,ping_pixels,&image->exception);
 
                 if (logging != MagickFalse && y == 0)
@@ -9763,14 +10542,14 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                 p=GetVirtualPixels(image,0,y,image->columns,1,
                    &image->exception);
 
-                if (p == (const PixelPacket *) NULL)
+                if (p == (const Quantum *) NULL)
                   break;
 
                 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
                   {
                     quantum_info->depth=image->depth;
 
-                    (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                    (void) ExportQuantumPixels(image,(CacheView *) NULL,
                        quantum_info,GrayQuantum,ping_pixels,&image->exception);
                   }
 
@@ -9780,14 +10559,14 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                            "  Writing GRAY_ALPHA PNG pixels (4)");
 
-                    (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                    (void) ExportQuantumPixels(image,(CacheView *) NULL,
                          quantum_info,GrayAlphaQuantum,ping_pixels,
                          &image->exception);
                   }
 
                 else
                   {
-                    (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+                    (void) ExportQuantumPixels(image,(CacheView *) NULL,
                       quantum_info,IndexQuantum,ping_pixels,&image->exception);
 
                     if (logging != MagickFalse && y <= 2)
@@ -10016,7 +10795,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %
 %  The format of the WritePNGImage method is:
 %
-%      MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
+%      MagickBooleanType WritePNGImage(const ImageInfo *image_info,
+%        Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -10024,6 +10804,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %
 %    o image:  The image.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 %  Returns MagickTrue on success, MagickFalse on failure.
 %
 %  Communicating with the PNG encoder:
@@ -10039,7 +10821,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %               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.
+%               3-3-3-1, or 3-3-2-1 palette.  The underlying RGB color
+%               of any resulting fully-transparent pixels is changed to
+%               the image's background color.
 %
 %               If you want better quantization or dithering of the colors
 %               or alpha than that, you need to do it before calling the
@@ -10096,9 +10880,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %  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 with depth, color,
-%   or transparency limitations.
-%
-%  To do: Enforce the previous paragraph.
+%  or transparency limitations.
 %
 %  Note that another definition, "png:bit-depth-written" exists, but it
 %  is not intended for external use.  It is only used internally by the
@@ -10142,7 +10924,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 */
 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
-  Image *image)
+  Image *image,ExceptionInfo *exception)
 {
   MagickBooleanType
     excluding,
@@ -10206,10 +10988,10 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       image->depth = 8;
 
       if (image->matte == MagickTrue)
-        (void) SetImageType(image,TrueColorMatteType);
+        (void) SetImageType(image,TrueColorMatteType,exception);
 
       else
-        (void) SetImageType(image,TrueColorType);
+        (void) SetImageType(image,TrueColorType,exception);
 
       (void) SyncImage(image);
     }
@@ -10221,10 +11003,10 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       image->depth = 8;
 
       if (image->matte == MagickTrue)
-        (void) SetImageType(image,TrueColorMatteType);
+        (void) SetImageType(image,TrueColorMatteType,exception);
 
       else
-        (void) SetImageType(image,TrueColorType);
+        (void) SetImageType(image,TrueColorType,exception);
 
       (void) SyncImage(image);
     }
@@ -10323,7 +11105,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
    * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
    *
    * The -strip option causes StripImage() to set the png:include-chunk
-   * artifact to "none,gama".
+   * artifact to "none,trns,gama".
    */
 
   mng_info->ping_exclude_bKGD=MagickFalse;
@@ -10350,6 +11132,128 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
   if (value != NULL)
      mng_info->ping_preserve_colormap=MagickTrue;
 
+  /* Thes compression-level, compression-strategy, and compression-filter
+   * defines take precedence over values from the -quality option.
+   */
+  value=GetImageArtifact(image,"png:compression-level");
+  if (value == NULL)
+     value=GetImageOption(image_info,"png:compression-level");
+  if (value != NULL)
+  {
+      /* We have to add 1 to everything because 0 is a valid input,
+       * and we want to use 0 (the default) to mean undefined.
+       */
+      if (LocaleCompare(value,"0") == 0)
+        mng_info->write_png_compression_level = 1;
+
+      if (LocaleCompare(value,"1") == 0)
+        mng_info->write_png_compression_level = 2;
+
+      else if (LocaleCompare(value,"2") == 0)
+        mng_info->write_png_compression_level = 3;
+
+      else if (LocaleCompare(value,"3") == 0)
+        mng_info->write_png_compression_level = 4;
+
+      else if (LocaleCompare(value,"4") == 0)
+        mng_info->write_png_compression_level = 5;
+
+      else if (LocaleCompare(value,"5") == 0)
+        mng_info->write_png_compression_level = 6;
+
+      else if (LocaleCompare(value,"6") == 0)
+        mng_info->write_png_compression_level = 7;
+
+      else if (LocaleCompare(value,"7") == 0)
+        mng_info->write_png_compression_level = 8;
+
+      else if (LocaleCompare(value,"8") == 0)
+        mng_info->write_png_compression_level = 9;
+
+      else if (LocaleCompare(value,"9") == 0)
+        mng_info->write_png_compression_level = 10;
+
+      else
+        (void) ThrowMagickException(&image->exception,
+             GetMagickModule(),CoderWarning,
+             "ignoring invalid defined png:compression-level",
+             "=%s",value);
+    }
+
+  value=GetImageArtifact(image,"png:compression-strategy");
+  if (value == NULL)
+     value=GetImageOption(image_info,"png:compression-strategy");
+  if (value != NULL)
+  {
+
+      if (LocaleCompare(value,"0") == 0)
+        mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
+
+      else if (LocaleCompare(value,"1") == 0)
+        mng_info->write_png_compression_strategy = Z_FILTERED+1;
+
+      else if (LocaleCompare(value,"2") == 0)
+        mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
+
+      else if (LocaleCompare(value,"3") == 0)
+#ifdef Z_RLE  /* Z_RLE was added to zlib-1.2.0 */
+        mng_info->write_png_compression_strategy = Z_RLE+1;
+#else
+        mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
+#endif
+
+      else if (LocaleCompare(value,"4") == 0)
+#ifdef Z_FIXED  /* Z_FIXED was added to zlib-1.2.2.2 */
+        mng_info->write_png_compression_strategy = Z_FIXED+1;
+#else
+        mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
+#endif
+
+      else
+        (void) ThrowMagickException(&image->exception,
+             GetMagickModule(),CoderWarning,
+             "ignoring invalid defined png:compression-strategy",
+             "=%s",value);
+    }
+
+  value=GetImageArtifact(image,"png:compression-filter");
+  if (value == NULL)
+     value=GetImageOption(image_info,"png:compression-filter");
+  if (value != NULL)
+  {
+
+      /* To do: combinations of filters allowed by libpng
+       * masks 0x08 through 0xf8
+       *
+       * Implement this as a comma-separated list of 0,1,2,3,4,5
+       * where 5 is a special case meaning PNG_ALL_FILTERS.
+       */
+
+      if (LocaleCompare(value,"0") == 0)
+        mng_info->write_png_compression_filter = 1;
+
+      if (LocaleCompare(value,"1") == 0)
+        mng_info->write_png_compression_filter = 2;
+
+      else if (LocaleCompare(value,"2") == 0)
+        mng_info->write_png_compression_filter = 3;
+
+      else if (LocaleCompare(value,"3") == 0)
+        mng_info->write_png_compression_filter = 4;
+
+      else if (LocaleCompare(value,"4") == 0)
+        mng_info->write_png_compression_filter = 5;
+
+      else if (LocaleCompare(value,"5") == 0)
+        mng_info->write_png_compression_filter = 6;
+
+      else
+        (void) ThrowMagickException(&image->exception,
+             GetMagickModule(),CoderWarning,
+             "ignoring invalid defined png:compression-filter",
+             "=%s",value);
+    }
+
   excluding=MagickFalse;
 
   for (source=0; source<1; source++)
@@ -10671,7 +11575,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
 
   mng_info->need_blob = MagickTrue;
 
-  status=WriteOnePNGImage(mng_info,image_info,image);
+  status=WriteOnePNGImage(mng_info,image_info,image,exception);
 
   MngInfoFreeStruct(mng_info,&have_mng_structure);
 
@@ -10685,7 +11589,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
 
 /* Write one JNG image */
 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
-   const ImageInfo *image_info,Image *image)
+   const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
 {
   Image
     *jpeg_image;
@@ -10739,12 +11643,15 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
 
   if (transparent)
     {
+      ChannelType
+        channel_mask;
+
       jng_color_type=14;
 
       /* Create JPEG blob, image, and image_info */
       if (logging != MagickFalse)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "  Creating jpeg_image_info for opacity.");
+          "  Creating jpeg_image_info for alpha.");
 
       jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
 
@@ -10761,8 +11668,9 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
 
       (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
-      status=SeparateImageChannel(jpeg_image,OpacityChannel);
-      status=NegateImage(jpeg_image,MagickFalse);
+      channel_mask=SetPixelChannelMask(jpeg_image,AlphaChannel);
+      status=SeparateImage(jpeg_image);
+      (void) SetPixelChannelMap(jpeg_image,channel_mask);
       jpeg_image->matte=MagickFalse;
 
       if (jng_quality >= 1000)
@@ -10772,9 +11680,9 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
         jpeg_image_info->quality=jng_quality;
 
       jpeg_image_info->type=GrayscaleType;
-      (void) SetImageType(jpeg_image,GrayscaleType);
+      (void) SetImageType(jpeg_image,GrayscaleType,exception);
       (void) AcquireUniqueFilename(jpeg_image->filename);
-      (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
+      (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
         "%s",jpeg_image->filename);
     }
 
@@ -10792,7 +11700,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
           const char
             *value;
 
-          /* Encode opacity as a grayscale PNG blob */
+          /* Encode alpha as a grayscale PNG blob */
           status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
             &image->exception);
           if (logging != MagickFalse)
@@ -10814,7 +11722,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
         }
       else
         {
-          /* Encode opacity as a grayscale JPEG blob */
+          /* Encode alpha as a grayscale JPEG blob */
 
           status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
             &image->exception);
@@ -11147,7 +12055,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
   (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
 
   (void) AcquireUniqueFilename(jpeg_image->filename);
-  (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
+  (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
     jpeg_image->filename);
 
   status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
@@ -11229,7 +12137,8 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
 %
 %  The format of the WriteJNGImage method is:
 %
-%      MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
+%      MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
+%        Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -11237,9 +12146,12 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
 %
 %    o image:  The image.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 */
-static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
+static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
+  ExceptionInfo *exception)
 {
   MagickBooleanType
     have_mng_structure,
@@ -11278,7 +12190,7 @@ static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
 
   (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
 
-  status=WriteOneJNGImage(mng_info,image_info,image);
+  status=WriteOneJNGImage(mng_info,image_info,image,exception);
   (void) CloseBlob(image);
 
   (void) CatchImageException(image);
@@ -11289,9 +12201,8 @@ static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
 }
 #endif
 
-
-
-static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
+static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
+  ExceptionInfo *exception)
 {
   const char
     *option;
@@ -12094,7 +13005,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
        /* To do: specify the desired alpha compression method. */
        write_info=CloneImageInfo(image_info);
        write_info->compression=UndefinedCompression;
-       status=WriteOneJNGImage(mng_info,write_info,image);
+       status=WriteOneJNGImage(mng_info,write_info,image,exception);
        write_info=DestroyImageInfo(write_info);
      }
    else
@@ -12124,7 +13035,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
        mng_info->ping_exclude_zCCP=MagickTrue;
        mng_info->ping_exclude_zTXt=MagickTrue;
 
-       status=WriteOnePNGImage(mng_info,image_info,image);
+       status=WriteOnePNGImage(mng_info,image_info,image,exception);
      }
 
     if (status == MagickFalse)