]> granicus.if.org Git - imagemagick/blobdiff - coders/png.c
(no commit message)
[imagemagick] / coders / png.c
index e775dd7ad402dc73f1df3c670c23e79759490a84..8ab45502459b2cfba3433e37f4e5e782d8260421 100644 (file)
@@ -1953,6 +1953,9 @@ static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
      Note that libpng has already taken care of the CRC handling.
   */
 
+  LogMagickEvent(CoderEvent,GetMagickModule(),
+     " read_vpag_chunk: found %c%c%c%c chunk",
+       chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]);
 
   if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
       chunk->name[2] != 65 ||chunk-> name[3] != 103)
@@ -2025,6 +2028,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   Image
     *image;
 
+  char
+    im_vers[32],
+    libpng_runv[32],
+    libpng_vers[32],
+    zlib_runv[32],
+    zlib_vers[32];
+
   int
     intent, /* "PNG Rendering intent", which is ICC intent + 1 */
     num_raw_profiles,
@@ -2051,6 +2061,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
     ping_found_gAMA,
     ping_found_iCCP,
     ping_found_sRGB,
+    ping_found_sRGB_cHRM,
     status;
 
   PixelInfo
@@ -2130,6 +2141,49 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
     "  Enter ReadOnePNGImage()");
 
+  /* Define these outside of the following "if logging()" block so they will
+   * show in debuggers.
+   */
+  *im_vers='\0';
+  (void) ConcatenateMagickString(im_vers,
+         MagickLibVersionText,32);
+  (void) ConcatenateMagickString(im_vers,
+         MagickLibAddendum,32);
+
+  *libpng_vers='\0';
+  (void) ConcatenateMagickString(libpng_vers,
+         PNG_LIBPNG_VER_STRING,32);
+  *libpng_runv='\0';
+  (void) ConcatenateMagickString(libpng_runv,
+         png_get_libpng_ver(NULL),32);
+
+  *zlib_vers='\0';
+  (void) ConcatenateMagickString(zlib_vers,
+         ZLIB_VERSION,32);
+  *zlib_runv='\0';
+  (void) ConcatenateMagickString(zlib_runv,
+         zlib_version,32);
+
+  if (logging)
+    {
+       LogMagickEvent(CoderEvent,GetMagickModule(),"    IM version     = %s",
+           im_vers);
+       LogMagickEvent(CoderEvent,GetMagickModule(),"    Libpng version = %s",
+           libpng_vers);
+       if (LocaleCompare(libpng_vers,libpng_runv) != 0)
+       {
+       LogMagickEvent(CoderEvent,GetMagickModule(),"      running with   %s",
+           libpng_runv);
+       }
+       LogMagickEvent(CoderEvent,GetMagickModule(),"    Zlib version   = %s",
+           zlib_vers);
+       if (LocaleCompare(zlib_vers,zlib_runv) != 0)
+       {
+       LogMagickEvent(CoderEvent,GetMagickModule(),"      running with   %s",
+           zlib_runv);
+       }
+    }
+
 #if (PNG_LIBPNG_VER < 10200)
   if (image_info->verbose)
     printf("Your PNG library (libpng-%s) is rather old.\n",
@@ -2154,13 +2208,19 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   if (logging != MagickFalse)
   {
     (void)LogMagickEvent(CoderEvent,GetMagickModule(),
-      "  image->alpha_trait=%d",(int) image->alpha_trait);
+      "    Before reading:");
 
     (void)LogMagickEvent(CoderEvent,GetMagickModule(),
-      "  image->rendering_intent=%d",(int) image->rendering_intent);
+      "      image->alpha_trait=%d",(int) image->alpha_trait);
 
     (void)LogMagickEvent(CoderEvent,GetMagickModule(),
-      "  image->colorspace=%d",(int) image->colorspace);
+      "      image->rendering_intent=%d",(int) image->rendering_intent);
+
+    (void)LogMagickEvent(CoderEvent,GetMagickModule(),
+      "      image->colorspace=%d",(int) image->colorspace);
+
+    (void)LogMagickEvent(CoderEvent,GetMagickModule(),
+      "      image->gamma=%f", image->gamma);
   }
   intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
 
@@ -2281,7 +2341,11 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   /* Ignore unused chunks and all unknown chunks except for vpAg */
+#if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */
+  png_set_keep_unknown_chunks(ping, 2, NULL, 0);
+#else
   png_set_keep_unknown_chunks(ping, 1, NULL, 0);
+#endif
   png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
   png_set_keep_unknown_chunks(ping, 1, unused_chunks,
      (int)sizeof(unused_chunks)/5);
@@ -2331,6 +2395,18 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
   ping_file_depth = ping_bit_depth;
 
+  /* Save bit-depth and color-type in case we later want to write a PNG00 */
+  {
+      char
+        msg[MaxTextExtent];
+
+      (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
+      (void) SetImageProperty(image,"png:IHDR.color-type-orig ",msg,exception);
+
+      (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
+      (void) SetImageProperty(image,"png:IHDR.bit-depth-orig  ",msg,exception);
+  }
+
   (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
                       &ping_trans_color);
 
@@ -2513,20 +2589,45 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         &image->chromaticity.blue_primary.x,
         &image->chromaticity.blue_primary.y);
 
+       if (image->chromaticity.red_primary.x>0.6399f &&
+           image->chromaticity.red_primary.x<0.6401f &&
+           image->chromaticity.red_primary.y>0.3299f &&
+           image->chromaticity.red_primary.y<0.3301f &&
+           image->chromaticity.green_primary.x>0.2999f &&
+           image->chromaticity.green_primary.x<0.3001f &&
+           image->chromaticity.green_primary.y>0.5999f &&
+           image->chromaticity.green_primary.y<0.6001f &&
+           image->chromaticity.blue_primary.x>0.1499f &&
+           image->chromaticity.blue_primary.x<0.1501f &&
+           image->chromaticity.blue_primary.y>0.0599f &&
+           image->chromaticity.blue_primary.y<0.0601f &&
+           image->chromaticity.white_point.x>0.3126f &&
+           image->chromaticity.white_point.x<0.3128f &&
+           image->chromaticity.white_point.y>0.3289f &&
+           image->chromaticity.white_point.y<0.3291f)
+          ping_found_sRGB_cHRM=MagickTrue;
+
       ping_found_cHRM=MagickTrue;
     }
 
   if (image->rendering_intent != UndefinedIntent)
     {
-      if (ping_found_sRGB != MagickTrue)
+      if (ping_found_sRGB != MagickTrue &&
+          (ping_found_gAMA != MagickTrue ||
+          (image->gamma > .45 && image->gamma < .46)) &&
+          (ping_found_cHRM != MagickTrue ||
+          ping_found_sRGB_cHRM == MagickTrue) &&
+          ping_found_iCCP != MagickTrue)
       {
          png_set_sRGB(ping,ping_info,
             Magick_RenderingIntent_to_PNG_RenderingIntent
             (image->rendering_intent));
-         png_set_gAMA(ping,ping_info,1.000f/2.200f);
+         if (ping_found_gAMA != MagickTrue)
+            png_set_gAMA(ping,ping_info,1.000f/2.200f);
          file_gamma=1.000f/2.200f;
          ping_found_sRGB=MagickTrue;
-         ping_found_cHRM=MagickTrue;
+         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+           "    Setting sRGB and gAMA as if in input");
       }
     }
 
@@ -2819,8 +2920,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
       ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
     {
       if ((!png_get_valid(ping,ping_info,PNG_INFO_gAMA) ||
-          image->gamma == 1.0) &&
-          ping_found_cHRM != MagickTrue && ping_found_sRGB != MagickTrue)
+          image->gamma == 1.0) && ping_found_sRGB != MagickTrue)
         {
           /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
            * image->colorspace to GRAY, and reset image->chromaticity.
@@ -3163,6 +3263,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 
       for (y=0; y < (ssize_t) image->rows; y++)
       {
+        Quantum
+           alpha;
+
         if (num_passes > 1)
           row_offset=ping_rowbytes*y;
 
@@ -3174,7 +3277,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         if (pass < num_passes-1)
           continue;
 
-        q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+        q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
 
         if (q == (Quantum *) NULL)
           break;
@@ -3186,13 +3289,19 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         {
           case 8:
           {
+
             if (ping_color_type == 4)
               for (x=(ssize_t) image->columns-1; x >= 0; x--)
               {
                 *r++=*p++;
-                SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *p++),q);
-                if (GetPixelAlpha(image,q) != OpaqueAlpha)
+
+                alpha=ScaleCharToQuantum((unsigned char)*p++);
+
+                SetPixelAlpha(image,alpha,q);
+
+                if (alpha != OpaqueAlpha)
                   found_transparent_pixel = MagickTrue;
+
                 q+=GetPixelChannels(image);
               }
 
@@ -3229,9 +3338,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                     quantum=0;
 
                   quantum|=(*p++);
-                  SetPixelAlpha(image,ScaleShortToQuantum(quantum),q);
-                  if (GetPixelAlpha(image,q) != OpaqueAlpha)
+
+                  alpha=ScaleShortToQuantum(quantum);
+                  SetPixelAlpha(image,alpha,q);
+
+                  if (alpha != OpaqueAlpha)
                     found_transparent_pixel = MagickTrue;
+
                   q+=GetPixelChannels(image);
                 }
 
@@ -3242,8 +3355,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
               if (ping_color_type == 4)
                 {
                   SetPixelAlpha(image,*p++,q);
+
                   if (GetPixelAlpha(image,q) != OpaqueAlpha)
                     found_transparent_pixel = MagickTrue;
+
                   p++;
                   q+=GetPixelChannels(image);
                 }
@@ -3588,6 +3703,32 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
         BlendPixelTrait : UndefinedPixelTrait;
 
+#if 0  /* I'm not sure what's wrong here but it does not work. */
+    if (image->alpha_trait == BlendPixelTrait)
+    {
+      if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+        (void) SetImageType(image,GrayscaleMatteType,exception);
+
+      else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
+        (void) SetImageType(image,PaletteMatteType,exception);
+
+      else
+        (void) SetImageType(image,TrueColorMatteType,exception);
+    }
+
+    else
+    {
+      if (ping_color_type == PNG_COLOR_TYPE_GRAY)
+        (void) SetImageType(image,GrayscaleType,exception);
+
+      else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
+        (void) SetImageType(image,PaletteType,exception);
+
+      else
+        (void) SetImageType(image,TrueColorType,exception);
+    }
+#endif
+
    /* Set more properties for identify to retrieve */
    {
      char
@@ -3814,20 +3955,25 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
     }
 
   if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
-      ((image->gamma < .45) || (image->gamma > .46)))
+      ((image->gamma < .45) || (image->gamma > .46)) &&
+           !(image->chromaticity.red_primary.x>0.6399f &&
+           image->chromaticity.red_primary.x<0.6401f &&
+           image->chromaticity.red_primary.y>0.3299f &&
+           image->chromaticity.red_primary.y<0.3301f &&
+           image->chromaticity.green_primary.x>0.2999f &&
+           image->chromaticity.green_primary.x<0.3001f &&
+           image->chromaticity.green_primary.y>0.5999f &&
+           image->chromaticity.green_primary.y<0.6001f &&
+           image->chromaticity.blue_primary.x>0.1499f &&
+           image->chromaticity.blue_primary.x<0.1501f &&
+           image->chromaticity.blue_primary.y>0.0599f &&
+           image->chromaticity.blue_primary.y<0.0601f &&
+           image->chromaticity.white_point.x>0.3126f &&
+           image->chromaticity.white_point.x<0.3128f &&
+           image->chromaticity.white_point.y>0.3289f &&
+           image->chromaticity.white_point.y<0.3291f))
     SetImageColorspace(image,RGBColorspace,exception);
 
-  if ((LocaleCompare(image_info->magick,"PNG24") == 0) ||
-      (LocaleCompare(image_info->magick,"PNG48") == 0))
-    {
-      (void) SetImageType(image,TrueColorType,exception);
-      image->alpha_trait=UndefinedPixelTrait;
-    }
-
-  if ((LocaleCompare(image_info->magick,"PNG32") == 0) ||
-      (LocaleCompare(image_info->magick,"PNG64") == 0))
-    (void) SetImageType(image,TrueColorMatteType,exception);
-
   if (logging != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
         "  page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
@@ -7305,6 +7451,20 @@ ModuleExport size_t RegisterPNGImage(void)
   entry->module=ConstantString("PNG");
   (void) RegisterMagickInfo(entry);
 
+  entry=SetMagickInfo("PNG00");
+
+#if defined(MAGICKCORE_PNG_DELEGATE)
+  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
+  entry->encoder=(EncodeImageHandler *) WritePNGImage;
+#endif
+
+  entry->magick=(IsImageFormatHandler *) IsPNG;
+  entry->adjoin=MagickFalse;
+  entry->description=ConstantString(
+    "PNG inheriting bit-depth and color-type from original");
+  entry->module=ConstantString("PNG");
+  (void) RegisterMagickInfo(entry);
+
   entry=SetMagickInfo("JNG");
 
 #if defined(JNG_SUPPORTED)
@@ -7356,6 +7516,7 @@ ModuleExport void UnregisterPNGImage(void)
   (void) UnregisterMagickInfo("PNG32");
   (void) UnregisterMagickInfo("PNG48");
   (void) UnregisterMagickInfo("PNG64");
+  (void) UnregisterMagickInfo("PNG00");
   (void) UnregisterMagickInfo("JNG");
 
 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
@@ -7680,6 +7841,13 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   unsigned char
     *volatile ping_pixels;
 
+  char
+    im_vers[32],
+    libpng_runv[32],
+    libpng_vers[32],
+    zlib_runv[32],
+    zlib_vers[32];
+
   volatile int
     image_colors,
     ping_bit_depth,
@@ -7718,6 +7886,49 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   if (image_info == (ImageInfo *) NULL)
      ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
 
+  /* Define these outside of the following "if logging()" block so they will
+   * show in debuggers.
+   */
+  *im_vers='\0';
+  (void) ConcatenateMagickString(im_vers,
+         MagickLibVersionText,MaxTextExtent);
+  (void) ConcatenateMagickString(im_vers,
+         MagickLibAddendum,MaxTextExtent);
+
+  *libpng_vers='\0';
+  (void) ConcatenateMagickString(libpng_vers,
+         PNG_LIBPNG_VER_STRING,32);
+  *libpng_runv='\0';
+  (void) ConcatenateMagickString(libpng_runv,
+         png_get_libpng_ver(NULL),32);
+
+  *zlib_vers='\0';
+  (void) ConcatenateMagickString(zlib_vers,
+         ZLIB_VERSION,32);
+  *zlib_runv='\0';
+  (void) ConcatenateMagickString(zlib_runv,
+         zlib_version,32);
+
+  if (logging)
+    {
+       LogMagickEvent(CoderEvent,GetMagickModule(),"    IM version     = %s",
+           im_vers);
+       LogMagickEvent(CoderEvent,GetMagickModule(),"    Libpng version = %s",
+           libpng_vers);
+       if (LocaleCompare(libpng_vers,libpng_runv) != 0)
+       {
+       LogMagickEvent(CoderEvent,GetMagickModule(),"      running with   %s",
+           libpng_runv);
+       }
+       LogMagickEvent(CoderEvent,GetMagickModule(),"    Zlib version   = %s",
+           zlib_vers);
+       if (LocaleCompare(zlib_vers,zlib_runv) != 0)
+       {
+       LogMagickEvent(CoderEvent,GetMagickModule(),"      running with   %s",
+           zlib_runv);
+       }
+    }
+
   /* Initialize some stuff */
   ping_bit_depth=0,
   ping_color_type=0,
@@ -9732,16 +9943,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
             */
             ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
 
-            if (mng_info->have_write_global_plte && matte == MagickFalse)
-              {
-                png_set_PLTE(ping,ping_info,NULL,0);
-
-                if (logging != MagickFalse)
-                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "  Setting up empty PLTE chunk");
-              }
-
-            else
+            if (!(mng_info->have_write_global_plte && matte == MagickFalse))
               {
                 for (i=0; i < (ssize_t) number_colors; i++)
                 {
@@ -10094,9 +10296,128 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     png_set_compression_strategy(ping,
        mng_info->write_png_compression_strategy-1);
 
+  ping_interlace_method=image_info->interlace != NoInterlace;
+
+  if (mng_info->write_mng)
+    png_set_sig_bytes(ping,8);
+
+  /* Bail out if cannot meet defined png:bit-depth or png:color-type */
+
+  if (mng_info->write_png_colortype != 0)
+    {
+     if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
+       if (ping_have_color != MagickFalse)
+         {
+           ping_color_type = PNG_COLOR_TYPE_RGB;
+
+           if (ping_bit_depth < 8)
+             ping_bit_depth=8;
+         }
+
+     if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
+       if (ping_have_color != MagickFalse)
+         ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+    }
+
+  if (ping_need_colortype_warning != MagickFalse ||
+     ((mng_info->write_png_depth &&
+     (int) mng_info->write_png_depth != ping_bit_depth) ||
+     (mng_info->write_png_colortype &&
+     ((int) mng_info->write_png_colortype-1 != ping_color_type &&
+      mng_info->write_png_colortype != 7 &&
+      !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
+    {
+      if (logging != MagickFalse)
+        {
+          if (ping_need_colortype_warning != MagickFalse)
+            {
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                 "  Image has transparency but tRNS chunk was excluded");
+            }
+
+          if (mng_info->write_png_depth)
+            {
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "  Defined png:bit-depth=%u, Computed depth=%u",
+                  mng_info->write_png_depth,
+                  ping_bit_depth);
+            }
+
+          if (mng_info->write_png_colortype)
+            {
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "  Defined png:color-type=%u, Computed color type=%u",
+                  mng_info->write_png_colortype-1,
+                  ping_color_type);
+            }
+        }
+
+      png_warning(ping,
+        "Cannot write image with defined png:bit-depth or png:color-type.");
+    }
+
+  if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
+    {
+      /* Add an opaque matte channel */
+      image->alpha_trait = BlendPixelTrait;
+      (void) SetImageAlpha(image,OpaqueAlpha,exception);
+
+      if (logging != MagickFalse)
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "  Added an opaque matte channel");
+    }
+
+  if (number_transparent != 0 || number_semitransparent != 0)
+    {
+      if (ping_color_type < 4)
+        {
+           ping_have_tRNS=MagickTrue;
+           if (logging != MagickFalse)
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+               "  Setting ping_have_tRNS=MagickTrue.");
+        }
+    }
+
+  if (logging != MagickFalse)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+      "  Writing PNG header chunks");
+
+  png_set_IHDR(ping,ping_info,ping_width,ping_height,
+               ping_bit_depth,ping_color_type,
+               ping_interlace_method,ping_compression_method,
+               ping_filter_method);
+
+  if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
+    {
+      png_set_PLTE(ping,ping_info,palette,number_colors);
+
+      if (logging != MagickFalse)
+        {
+          for (i=0; i< (ssize_t) number_colors; i++)
+          {
+            if (i < ping_num_trans)
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                "     PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
+                      (int) i,
+                      (int) palette[i].red,
+                      (int) palette[i].green,
+                      (int) palette[i].blue,
+                      (int) i,
+                      (int) ping_trans_alpha[i]);
+             else
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                "     PLTE[%d] = (%d,%d,%d)",
+                      (int) i,
+                      (int) palette[i].red,
+                      (int) palette[i].green,
+                      (int) palette[i].blue);
+           }
+         }
+    }
+
   /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
   if (ping_exclude_sRGB != MagickFalse ||
-     (image->rendering_intent == UndefinedIntent))
+     (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
   {
     if ((ping_exclude_tEXt == MagickFalse ||
        ping_exclude_zTXt == MagickFalse) &&
@@ -10148,7 +10469,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
 #if defined(PNG_WRITE_sRGB_SUPPORTED)
   if ((mng_info->have_write_global_srgb == 0) &&
-      (image->rendering_intent != UndefinedIntent))
+      (png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
     {
       if (ping_exclude_sRGB == MagickFalse)
         {
@@ -10216,125 +10537,6 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
         }
     }
 
-  ping_interlace_method=image_info->interlace != NoInterlace;
-
-  if (mng_info->write_mng)
-    png_set_sig_bytes(ping,8);
-
-  /* Bail out if cannot meet defined png:bit-depth or png:color-type */
-
-  if (mng_info->write_png_colortype != 0)
-    {
-     if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
-       if (ping_have_color != MagickFalse)
-         {
-           ping_color_type = PNG_COLOR_TYPE_RGB;
-
-           if (ping_bit_depth < 8)
-             ping_bit_depth=8;
-         }
-
-     if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
-       if (ping_have_color != MagickFalse)
-         ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
-    }
-
-  if (ping_need_colortype_warning != MagickFalse ||
-     ((mng_info->write_png_depth &&
-     (int) mng_info->write_png_depth != ping_bit_depth) ||
-     (mng_info->write_png_colortype &&
-     ((int) mng_info->write_png_colortype-1 != ping_color_type &&
-      mng_info->write_png_colortype != 7 &&
-      !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
-    {
-      if (logging != MagickFalse)
-        {
-          if (ping_need_colortype_warning != MagickFalse)
-            {
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                 "  Image has transparency but tRNS chunk was excluded");
-            }
-
-          if (mng_info->write_png_depth)
-            {
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                  "  Defined png:bit-depth=%u, Computed depth=%u",
-                  mng_info->write_png_depth,
-                  ping_bit_depth);
-            }
-
-          if (mng_info->write_png_colortype)
-            {
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                  "  Defined png:color-type=%u, Computed color type=%u",
-                  mng_info->write_png_colortype-1,
-                  ping_color_type);
-            }
-        }
-
-      png_warning(ping,
-        "Cannot write image with defined png:bit-depth or png:color-type.");
-    }
-
-  if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
-    {
-      /* Add an opaque matte channel */
-      image->alpha_trait = BlendPixelTrait;
-      (void) SetImageAlpha(image,OpaqueAlpha,exception);
-
-      if (logging != MagickFalse)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "  Added an opaque matte channel");
-    }
-
-  if (number_transparent != 0 || number_semitransparent != 0)
-    {
-      if (ping_color_type < 4)
-        {
-           ping_have_tRNS=MagickTrue;
-           if (logging != MagickFalse)
-             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "  Setting ping_have_tRNS=MagickTrue.");
-        }
-    }
-
-  if (logging != MagickFalse)
-    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-      "  Writing PNG header chunks");
-
-  png_set_IHDR(ping,ping_info,ping_width,ping_height,
-               ping_bit_depth,ping_color_type,
-               ping_interlace_method,ping_compression_method,
-               ping_filter_method);
-
-  if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
-    {
-      png_set_PLTE(ping,ping_info,palette,number_colors);
-
-      if (logging != MagickFalse)
-        {
-          for (i=0; i< (ssize_t) number_colors; i++)
-          {
-            if (i < ping_num_trans)
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "     PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
-                      (int) i,
-                      (int) palette[i].red,
-                      (int) palette[i].green,
-                      (int) palette[i].blue,
-                      (int) i,
-                      (int) ping_trans_alpha[i]);
-             else
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "     PLTE[%d] = (%d,%d,%d)",
-                      (int) i,
-                      (int) palette[i].red,
-                      (int) palette[i].green,
-                      (int) palette[i].blue);
-           }
-         }
-    }
-
   if (ping_exclude_bKGD == MagickFalse)
     {
       if (ping_have_bKGD != MagickFalse)
@@ -10888,7 +11090,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
                   "  Setting up text chunk");
 
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                  "    keyword: %s",text[0].key);
+                  "    keyword: '%s'",text[0].key);
               }
 
             png_set_text(ping,ping_info,text,1);
@@ -11071,6 +11273,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %               each pixel can have any value from 0 to 65535. The alpha
 %               channel is present even if the image is fully opaque.
 %
+%    o PNG00:   A PNG that inherits its colortype and bit-depth from the input
+%               image, if the input was a PNG, is written.  If these values
+%               cannot be found, then "PNG00" falls back to the regular "PNG"
+%               format.
+%
 %    o -define: For more precise control of the PNG output, you can use the
 %               Image options "png:bit-depth" and "png:color-type".  These
 %               can be set from the commandline with "-define" and also
@@ -11224,6 +11431,63 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       else if (LocaleCompare(value,"png64") == 0)
         mng_info->write_png64 = MagickTrue;
     }
+
+  if (LocaleCompare(value,"png00") == 0)
+    {
+      /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig
+         Note that whitespace at the end of the property names must match
+         that in the corresponding SetImageProperty() calls.
+       */
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+         "  Format=%s",value);
+
+      value=GetImageProperty(image,"png:IHDR.bit-depth-orig  ",exception);
+
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+         "  png00 inherited bit depth=%s",value);
+
+      if (value != (char *) NULL)
+        {
+          if (LocaleCompare(value,"1") == 0)
+            mng_info->write_png_depth = 1;
+
+          else if (LocaleCompare(value,"1") == 0)
+            mng_info->write_png_depth = 2;
+
+          else if (LocaleCompare(value,"2") == 0)
+            mng_info->write_png_depth = 4;
+
+          else if (LocaleCompare(value,"8") == 0)
+            mng_info->write_png_depth = 8;
+
+          else if (LocaleCompare(value,"16") == 0)
+            mng_info->write_png_depth = 16;
+        }
+
+      value=GetImageProperty(image,"png:IHDR.color-type-orig ",exception);
+
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+         "  png00 inherited color type=%s",value);
+
+      if (value != (char *) NULL)
+        {
+          if (LocaleCompare(value,"0") == 0)
+            mng_info->write_png_colortype = 1;
+
+          else if (LocaleCompare(value,"2") == 0)
+            mng_info->write_png_colortype = 3;
+
+          else if (LocaleCompare(value,"3") == 0)
+            mng_info->write_png_colortype = 4;
+
+          else if (LocaleCompare(value,"4") == 0)
+            mng_info->write_png_colortype = 5;
+
+          else if (LocaleCompare(value,"6") == 0)
+            mng_info->write_png_colortype = 7;
+        }
+    }
+
   if (mng_info->write_png8)
     {
       mng_info->write_png_colortype = /* 3 */ 4;
@@ -11267,13 +11531,13 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       mng_info->write_png_depth = 16;
       image->depth = 16;
 
-      if (image->matte == MagickTrue)
-        (void) SetImageType(image,TrueColorMatteType);
+      if (image->alpha_trait == BlendPixelTrait)
+        (void) SetImageType(image,TrueColorMatteType,exception);
 
       else
-        (void) SetImageType(image,TrueColorType);
+        (void) SetImageType(image,TrueColorType,exception);
 
-      (void) SyncImage(image);
+      (void) SyncImage(image,exception);
     }
 
   if (mng_info->write_png64)
@@ -11282,13 +11546,13 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       mng_info->write_png_depth = 16;
       image->depth = 16;
 
-      if (image->matte == MagickTrue)
-        (void) SetImageType(image,TrueColorMatteType);
+      if (image->alpha_trait == BlendPixelTrait)
+        (void) SetImageType(image,TrueColorMatteType,exception);
 
       else
-        (void) SetImageType(image,TrueColorType);
+        (void) SetImageType(image,TrueColorType,exception);
 
-      (void) SyncImage(image);
+      (void) SyncImage(image,exception);
     }
 
   value=GetImageOption(image_info,"png:bit-depth");
@@ -12628,7 +12892,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "      Image depth: %.20g",(double) p->depth);
 
-        if (p->alpha_trait)
+        if (p->alpha_trait == BlendPixelTrait)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
             "      Matte: True");
 
@@ -12722,11 +12986,12 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
         if (next_image->page.x || next_image->page.y)
           need_defi=MagickTrue;
 
-        if (next_image->alpha_trait)
+        if (next_image->alpha_trait == BlendPixelTrait)
           need_matte=MagickTrue;
 
         if ((int) next_image->dispose >= BackgroundDispose)
-          if (next_image->alpha_trait || next_image->page.x || next_image->page.y ||
+          if ((next_image->alpha_trait == BlendPixelTrait) ||
+               next_image->page.x || next_image->page.y ||
               ((next_image->columns < mng_info->page.width) &&
                (next_image->rows < mng_info->page.height)))
             mng_info->need_fram=MagickTrue;
@@ -13098,8 +13363,8 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
        Write MNG BACK chunk and global bKGD chunk, if the image is transparent
        or does not cover the entire frame.
      */
-     if (write_mng && (image->alpha_trait || image->page.x > 0 ||
-         image->page.y > 0 || (image->page.width &&
+     if (write_mng && ((image->alpha_trait == BlendPixelTrait) ||
+         image->page.x > 0 || image->page.y > 0 || (image->page.width &&
          (image->page.width+image->page.x < mng_info->page.width))
          || (image->page.height && (image->page.height+image->page.y
          < mng_info->page.height))))