]> granicus.if.org Git - imagemagick/blobdiff - coders/png.c
(no commit message)
[imagemagick] / coders / png.c
index 24b1c40af7837309e6d62e2d20712a282e7c653d..8ab45502459b2cfba3433e37f4e5e782d8260421 100644 (file)
@@ -880,7 +880,9 @@ typedef struct _MngInfo
     write_png_compression_filter,
     write_png8,
     write_png24,
-    write_png32;
+    write_png32,
+    write_png48,
+    write_png64;
 
 #ifdef MNG_BASI_SUPPORTED
   size_t
@@ -1951,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)
@@ -2023,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,
@@ -2049,6 +2061,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
     ping_found_gAMA,
     ping_found_iCCP,
     ping_found_sRGB,
+    ping_found_sRGB_cHRM,
     status;
 
   PixelInfo
@@ -2128,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",
@@ -2152,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);
 
@@ -2279,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);
@@ -2287,6 +2353,15 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
   png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
 #endif
 
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+#  if (PNG_LIBPNG_VER >= 10400)
+    /* Limit the size of the chunk storage cache used for sPLT, text,
+     * and unknown chunks.
+     */
+    png_set_chunk_cache_max(ping, 32767);
+#  endif
+#endif
+
 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
     /* Disable new libpng-1.5.10 feature */
     png_set_check_for_invalid_index (ping, 0);
@@ -2320,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);
 
@@ -2502,18 +2589,48 @@ 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)
     {
-      png_set_sRGB(ping,ping_info,
-         Magick_RenderingIntent_to_PNG_RenderingIntent
-         (image->rendering_intent));
-      png_set_gAMA(ping,ping_info,1.000f/2.200f);
-      png_set_cHRM(ping,ping_info,
-                  0.6400f, 0.3300f, 0.3000f, 0.6000f,
-                  0.1500f, 0.0600f, 0.3127f, 0.3290f);
+      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));
+         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;
+         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+           "    Setting sRGB and gAMA as if in input");
+      }
     }
+
 #if defined(PNG_oFFs_SUPPORTED)
   if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
     {
@@ -2803,9 +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) &&
-          !png_get_valid(ping,ping_info,PNG_INFO_cHRM) &&
-          !png_get_valid(ping,ping_info,PNG_INFO_sRGB))
+          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.
@@ -3148,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;
 
@@ -3159,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;
@@ -3171,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);
               }
 
@@ -3214,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);
                 }
 
@@ -3227,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);
                 }
@@ -3573,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
@@ -3799,18 +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)
-    {
-      (void) SetImageType(image,TrueColorType,exception);
-      image->alpha_trait=UndefinedPixelTrait;
-    }
-
-  if (LocaleCompare(image_info->magick,"PNG32") == 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.",
@@ -7245,7 +7408,7 @@ ModuleExport size_t RegisterPNGImage(void)
 
   entry->magick=(IsImageFormatHandler *) IsPNG;
   entry->adjoin=MagickFalse;
-  entry->description=ConstantString("opaque 24-bit RGB");
+  entry->description=ConstantString("opaque or binary transparent 24-bit RGB");
   entry->module=ConstantString("PNG");
   (void) RegisterMagickInfo(entry);
 
@@ -7262,6 +7425,46 @@ ModuleExport size_t RegisterPNGImage(void)
   entry->module=ConstantString("PNG");
   (void) RegisterMagickInfo(entry);
 
+  entry=SetMagickInfo("PNG48");
+
+#if defined(MAGICKCORE_PNG_DELEGATE)
+  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
+  entry->encoder=(EncodeImageHandler *) WritePNGImage;
+#endif
+
+  entry->magick=(IsImageFormatHandler *) IsPNG;
+  entry->adjoin=MagickFalse;
+  entry->description=ConstantString("opaque or binary transparent 48-bit RGB");
+  entry->module=ConstantString("PNG");
+  (void) RegisterMagickInfo(entry);
+
+  entry=SetMagickInfo("PNG64");
+
+#if defined(MAGICKCORE_PNG_DELEGATE)
+  entry->decoder=(DecodeImageHandler *) ReadPNGImage;
+  entry->encoder=(EncodeImageHandler *) WritePNGImage;
+#endif
+
+  entry->magick=(IsImageFormatHandler *) IsPNG;
+  entry->adjoin=MagickFalse;
+  entry->description=ConstantString("opaque or transparent 64-bit RGBA");
+  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)
@@ -7311,6 +7514,9 @@ ModuleExport void UnregisterPNGImage(void)
   (void) UnregisterMagickInfo("PNG8");
   (void) UnregisterMagickInfo("PNG24");
   (void) UnregisterMagickInfo("PNG32");
+  (void) UnregisterMagickInfo("PNG48");
+  (void) UnregisterMagickInfo("PNG64");
+  (void) UnregisterMagickInfo("PNG00");
   (void) UnregisterMagickInfo("JNG");
 
 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
@@ -7635,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,
@@ -7673,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,
@@ -7821,8 +8077,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
   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)))
+     mng_info->write_png48 || mng_info->write_png64 ||
+     (mng_info->write_png_colortype != 1 &&
+     mng_info->write_png_colortype != 5)))
     {
       (void) SyncImage(image,exception);
       image->storage_class = DirectClass;
@@ -8059,8 +8316,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
      /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
       * are not going to need the result.
       */
-     image_colors=image->colors;
-     number_opaque = image->colors;
+     image_colors = (int) image->colors;
+     number_opaque = (int) image->colors;
      if (mng_info->write_png_colortype == 1 ||
         mng_info->write_png_colortype == 5)
        ping_have_color=MagickFalse;
@@ -9093,6 +9350,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
      image_depth=8;
 
+  if (mng_info->write_png48 || mng_info->write_png64)
+     image_depth=16;
+
   if (mng_info->write_png_depth != 0)
      image_depth=mng_info->write_png_depth;
 
@@ -9303,13 +9563,21 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
       }
     } /* end of write_png8 */
 
-  else if (mng_info->write_png24 || mng_info->write_png_colortype == 3)
+  else if (mng_info->write_png_colortype == 1)
+    {
+      image_matte=MagickFalse;
+      ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
+    }
+
+  else if (mng_info->write_png24 || mng_info->write_png48 ||
+      mng_info->write_png_colortype == 3)
     {
       image_matte=MagickFalse;
       ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
     }
 
-  else if (mng_info->write_png32 || mng_info->write_png_colortype == 7)
+  else if (mng_info->write_png32 || mng_info->write_png64 ||
+      mng_info->write_png_colortype == 7)
     {
       image_matte=MagickTrue;
       ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
@@ -9675,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++)
                 {
@@ -10037,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) &&
@@ -10091,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)
         {
@@ -10159,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)
@@ -10470,6 +10729,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   num_passes=png_set_interlace_handling(ping);
 
   if ((!mng_info->write_png8 && !mng_info->write_png24 &&
+       !mng_info->write_png48 && !mng_info->write_png64 &&
        !mng_info->write_png32) &&
        (mng_info->IsPalette ||
        (image_info->type == BilevelType)) &&
@@ -10541,10 +10801,10 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   else   /* Not Palette, Bilevel, or Opaque Monochrome */
     {
       if ((!mng_info->write_png8 && !mng_info->write_png24 &&
-         !mng_info->write_png32) &&
-         (image_matte != MagickFalse ||
-         (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
-         (mng_info->IsPalette) && ping_have_color == MagickFalse)
+          !mng_info->write_png48 && !mng_info->write_png64 &&
+          !mng_info->write_png32) && (image_matte != MagickFalse ||
+          (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
+          (mng_info->IsPalette) && ping_have_color == MagickFalse)
         {
           register const Quantum
             *p;
@@ -10607,9 +10867,12 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
           for (pass=0; pass < num_passes; pass++)
           {
-            if ((image_depth > 8) || (mng_info->write_png24 ||
+            if ((image_depth > 8) ||
+                mng_info->write_png24 ||
                 mng_info->write_png32 ||
-                (!mng_info->write_png8 && !mng_info->IsPalette)))
+                mng_info->write_png48 ||
+                mng_info->write_png64 ||
+                (!mng_info->write_png8 && !mng_info->IsPalette))
             {
               for (y=0; y < (ssize_t) image->rows; y++)
               {
@@ -10657,9 +10920,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
             }
 
           else
-            /* not ((image_depth > 8) || (mng_info->write_png24 ||
-                mng_info->write_png32 ||
-                (!mng_info->write_png8 && !mng_info->IsPalette))) */
+            /* not ((image_depth > 8) ||
+                mng_info->write_png24 || mng_info->write_png32 ||
+                mng_info->write_png48 || mng_info->write_png64 ||
+                (!mng_info->write_png8 && !mng_info->IsPalette))
+             */
             {
               if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
                   (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
@@ -10825,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);
@@ -10996,6 +11261,23 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %               The only loss in data is the reduction of the sample depth
 %               to 8.
 %
+%    o PNG48:   A 16-bit per sample RGB PNG datastream is written.  The tRNS
+%               chunk can be present to convey binary transparency by naming
+%               one of the colors as transparent.  If the image has more
+%               than one transparent color, has semitransparent pixels, or
+%               has an opaque pixel with the same RGB components as the
+%               transparent color, an image is not written.
+%
+%    o PNG64:   A 16-bit per sample RGBA PNG is written.  Partial
+%               transparency is permitted, i.e., the alpha sample for
+%               each pixel can have any value from 0 to 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
@@ -11019,9 +11301,10 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 %               When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
 %               png:bit-depth can be 8 or 16.
 %
-%  If the image cannot be written without loss with the requested bit-depth
-%  and color-type, a PNG file will not be written, and the encoder will
-%  return MagickFalse.
+%               If the image cannot be written without loss with the
+%               requested bit-depth and color-type, a PNG file will not
+%               be written, a warning will be issued, and the encoder will
+%               return MagickFalse.
 %
 %  Since image encoders should not be responsible for the "heavy lifting",
 %  the user should make sure that ImageMagick has already reduced the
@@ -11120,32 +11403,91 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
   mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
   mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
   mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
+  mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
+  mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
 
   value=GetImageOption(image_info,"png:format");
 
   if (value != (char *) NULL)
     {
+      mng_info->write_png8 = MagickFalse;
+      mng_info->write_png24 = MagickFalse;
+      mng_info->write_png32 = MagickFalse;
+      mng_info->write_png48 = MagickFalse;
+      mng_info->write_png64 = MagickFalse;
+
       if (LocaleCompare(value,"png8") == 0)
-        {
         mng_info->write_png8 = MagickTrue;
-        mng_info->write_png24 = MagickFalse;
-        mng_info->write_png32 = MagickFalse;
-        }
 
       else if (LocaleCompare(value,"png24") == 0)
-        {
-        mng_info->write_png8 = MagickFalse;
         mng_info->write_png24 = MagickTrue;
-        mng_info->write_png32 = MagickFalse;
-        }
 
       else if (LocaleCompare(value,"png32") == 0)
-        {
-        mng_info->write_png8 = MagickFalse;
-        mng_info->write_png24 = MagickFalse;
         mng_info->write_png32 = MagickTrue;
+
+      else if (LocaleCompare(value,"png48") == 0)
+        mng_info->write_png48 = MagickTrue;
+
+      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;
@@ -11183,6 +11525,36 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       (void) SyncImage(image,exception);
     }
 
+  if (mng_info->write_png48)
+    {
+      mng_info->write_png_colortype = /* 2 */ 3;
+      mng_info->write_png_depth = 16;
+      image->depth = 16;
+
+      if (image->alpha_trait == BlendPixelTrait)
+        (void) SetImageType(image,TrueColorMatteType,exception);
+
+      else
+        (void) SetImageType(image,TrueColorType,exception);
+
+      (void) SyncImage(image,exception);
+    }
+
+  if (mng_info->write_png64)
+    {
+      mng_info->write_png_colortype = /* 6 */  7;
+      mng_info->write_png_depth = 16;
+      image->depth = 16;
+
+      if (image->alpha_trait == BlendPixelTrait)
+        (void) SetImageType(image,TrueColorMatteType,exception);
+
+      else
+        (void) SetImageType(image,TrueColorType,exception);
+
+      (void) SyncImage(image,exception);
+    }
+
   value=GetImageOption(image_info,"png:bit-depth");
 
   if (value != (char *) NULL)
@@ -12520,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");
 
@@ -12614,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;
@@ -12990,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))))