File GraphicsMagick-png.c-update.patch of Package GraphicsMagick.7782

--- a/coders/png.c	2018-01-09 12:22:08.952526412 +0100
+++ b/coders/png.c	2018-01-10 12:57:36.027306949 +0100
@@ -1,5 +1,5 @@
 /*
-% Copyright (C) 2003-2015 GraphicsMagick Group
+% Copyright (C) 2003-2017 GraphicsMagick Group
 % Copyright (C) 2002 ImageMagick Studio
 % Copyright 1991-1999 E. I. du Pont de Nemours and Company
 %
@@ -76,6 +76,7 @@
 #include "magick/tempfile.h"
 #include "magick/transform.h"
 #include "magick/utility.h"
+#include "magick/version.h"
 #if defined(HasPNG)
 
 /* Suppress libpng pedantic warnings */
@@ -87,12 +88,22 @@
 
 #include "png.h"
 #include "zlib.h"
+#if defined(HasLCMS)
+#  if defined(HAVE_LCMS2_LCMS2_H)
+#    include <lcms2/lcms2.h>
+#  elif defined(HAVE_LCMS2_H)
+#    include <lcms2.h>
+#  else
+#    error "LCMS 2 header missing!"
+#  endif
+#endif
 
 
 #if PNG_LIBPNG_VER > 10011
 /*
   Optional declarations. Define or undefine them as you like.
 */
+
 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
 
 /*
@@ -194,10 +205,13 @@ static png_byte const mng_SEEK[5]={ 83,
 static png_byte const mng_SHOW[5]={ 83,  72,  79,  87, '\0'};
 static png_byte const mng_TERM[5]={ 84,  69,  82,  77, '\0'};
 static png_byte const mng_bKGD[5]={ 98,  75,  71,  68, '\0'};
+static png_byte const mng_caNv[5]={ 99,  97,  78, 118, '\0'};
 static png_byte const mng_cHRM[5]={ 99,  72,  82,  77, '\0'};
+static png_byte const mng_eXIf[5]={101,  88,  73, 102, '\0'};
 static png_byte const mng_gAMA[5]={103,  65,  77,  65, '\0'};
 static png_byte const mng_iCCP[5]={105,  67,  67,  80, '\0'};
 static png_byte const mng_nEED[5]={110,  69,  69,  68, '\0'};
+static png_byte const mng_orNT[5]={111, 114,  78,  84, '\0'};
 static png_byte const mng_pHYg[5]={112,  72,  89, 103, '\0'};
 static png_byte const mng_pHYs[5]={112,  72,  89, 115, '\0'};
 static png_byte const mng_sBIT[5]={115,  66,  73,  84, '\0'};
@@ -652,12 +666,12 @@ static void PNGType(png_bytep p,png_byte
   (void) memcpy(p,type,4*sizeof(png_byte));
 }
 
-static void LogPNGChunk(int logging, png_byte const * type, unsigned long length)
+static void LogPNGChunk(int logging, png_byte const * type, size_t length)
 {
   if (logging)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-        "  Writing %c%c%c%c chunk, length: %lu",
-        type[0],type[1],type[2],type[3],length);
+        "  Writing %c%c%c%c chunk, length: %" MAGICK_SIZE_T_F "u",
+        type[0],type[1],type[2],type[3],(MAGICK_SIZE_T) length);
 }
 #endif /* PNG_LIBPNG_VER > 10011 */
 
@@ -776,7 +790,7 @@ static void png_get_data(png_structp png
     {
       png_size_t
         check;
-    
+
       if (length > 0x7fffffff)
         png_warning(png_ptr, "chunk length > 2G");
       check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
@@ -784,7 +798,7 @@ static void png_get_data(png_structp png
         {
           char
             msg[MaxTextExtent];
-        
+
             (void) sprintf(msg,"Expected %lu bytes; found %lu bytes",
                            (unsigned long) length,(unsigned long) check);
           png_warning(png_ptr,msg);
@@ -887,7 +901,7 @@ static void png_put_data(png_structp png
     {
       png_size_t
         check;
-    
+
       check=(png_size_t) WriteBlob(image,(unsigned long) length,(char *) data);
       if (check != length)
         png_error(png_ptr,"WriteBlob Failed");
@@ -944,7 +958,10 @@ static void MngInfoDiscardObject(MngInfo
           if (mng_info->ob[i]->reference_count == 0)
             {
               if (mng_info->ob[i]->image != (Image *) NULL)
-                DestroyImage(mng_info->ob[i]->image);
+                {
+                  DestroyImage(mng_info->ob[i]->image);
+                  mng_info->ob[i]->image=(Image *) NULL;
+                }
               MagickFreeMemory(mng_info->ob[i]);
             }
         }
@@ -969,9 +986,10 @@ static void MngInfoFreeStruct(MngInfo *m
     {
       register long
         i;
-    
+
       for (i=1; i < MNG_MAX_OBJECTS; i++)
         MngInfoDiscardObject(mng_info,i);
+      mng_info->image=(Image *)NULL;
       MagickFreeMemory(mng_info->global_plte);
       MagickFreeMemory(mng_info);
       *have_mng_structure=MagickFalse;
@@ -995,6 +1013,14 @@ static MngBox mng_minimum_box(MngBox box
   return box;
 }
 
+static long mng_get_long(unsigned char *p)
+{
+  return ((long) (((magick_uint32_t) p[0] << 24) |
+                  ((magick_uint32_t) p[1] << 16) |
+                  ((magick_uint32_t) p[2] <<  8) |
+                  (magick_uint32_t)  p[3]));
+}
+
 static MngBox mng_read_box(MngBox previous_box,char delta_type,
                            unsigned char *p)
 {
@@ -1004,10 +1030,10 @@ static MngBox mng_read_box(MngBox previo
   /*
     Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
   */
-  box.left=(long) ((p[0]  << 24) | (p[1]  << 16) | (p[2]  << 8) | p[3]);
-  box.right=(long) ((p[4]  << 24) | (p[5]  << 16) | (p[6]  << 8) | p[7]);
-  box.top=(long) ((p[8]  << 24) | (p[9]  << 16) | (p[10] << 8) | p[11]);
-  box.bottom=(long) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
+  box.left  = mng_get_long(p);
+  box.right = mng_get_long(&p[4]);
+  box.top   = mng_get_long(&p[8]);
+  box.bottom= mng_get_long(&p[12]);
   if (delta_type != 0)
     {
       box.left+=previous_box.left;
@@ -1026,8 +1052,9 @@ static MngPair mng_read_pair(MngPair pre
   /*
     Read two longs from CLON, MOVE or PAST chunk
   */
-  pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
-  pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
+  pair.a= mng_get_long(p);
+  pair.b= mng_get_long(&p[4]);
+
   if (delta_type != 0)
     {
       pair.a+=previous_pair.a;
@@ -1036,11 +1063,6 @@ static MngPair mng_read_pair(MngPair pre
   return(pair);
 }
 
-static long mng_get_long(unsigned char *p)
-{
-  return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
-}
-
 static void PNGErrorHandler(png_struct *ping,png_const_charp message) MAGICK_FUNC_NORETURN;
 
 static void PNGErrorHandler(png_struct *ping,png_const_charp message)
@@ -1147,15 +1169,15 @@ png_read_raw_profile(Image *image, const
   /* allocate space */
   if (length == 0)
     {
-      (void) ThrowException2(&image->exception,CoderWarning,
-                             "invalid profile length",(char *) NULL);
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "invalid profile length");
       return (MagickFail);
     }
   info=MagickAllocateMemory(unsigned char *,length);
   if (info == (unsigned char *) NULL)
     {
-      (void) ThrowException2(&image->exception,CoderWarning,
-                             "unable to copy profile",(char *) NULL);
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "Unable to copy profile");
       return (MagickFail);
     }
   /* copy profile, skipping white space and column 1 "=" signs */
@@ -1168,8 +1190,8 @@ png_read_raw_profile(Image *image, const
           if (*sp == '\0')
             {
               MagickFreeMemory(info);
-              (void) ThrowException2(&image->exception,CoderWarning,
-                                     "ran out of profile data",(char *) NULL);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "ran out of profile data");
               return (MagickFail);
             }
           sp++;
@@ -1205,13 +1227,145 @@ png_read_raw_profile(Image *image, const
   if(SetImageProfile(image,profile_name,info,length) == MagickFail)
     {
       MagickFreeMemory(info);
-      (void) ThrowException(&image->exception,ResourceLimitError,
-                            MemoryAllocationFailed,"unable to copy profile");
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+           "unable to copy profile");
+      return MagickFail;
     }
   MagickFreeMemory(info);
   return MagickTrue;
 }
 
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+
+static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
+{
+  Image
+    *image;
+
+
+  /* The unknown chunk structure contains the chunk data:
+     png_byte name[5];
+     png_byte *data;
+     png_size_t size;
+
+     Note that libpng has already taken care of the CRC handling.
+
+     Returns one of the following:
+         return(-n);  chunk had an error
+         return(0);  did not recognize
+         return(n);  success
+  */
+
+  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+     "    read_user_chunk: found %c%c%c%c chunk",
+       chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]);
+
+  if (chunk->name[0]  == 101 &&
+      (chunk->name[1] ==  88 || chunk->name[1] == 120 ) &&
+      chunk->name[2]  ==  73 &&
+      chunk->name[3]  == 102)
+    {
+      /* process eXIf or exIf chunk */
+
+      unsigned char
+        *profile;
+
+      unsigned char
+        *p;
+
+      png_byte
+        *s;
+
+      size_t
+        i;
+
+(void) LogMagickEvent(CoderEvent,GetMagickModule(),
+        " recognized eXIf chunk");
+
+      image=(Image *) png_get_user_chunk_ptr(ping);
+
+#if PNG_LIBPNG_VER >= 14000
+      profile=(unsigned char *) png_malloc(ping,
+        (png_alloc_size_t) chunk->size+6);
+#else
+      profile=(unsigned char *) png_malloc(ping,
+         (png_size_t) chunk->size+6);
+#endif
+      p=profile;
+
+      if (*p != 'E' || *(p+1) != 'x' || *(p+2) != 'i' ||
+          *(p+3) != 'f' || *(p+4) != '\0' || *(p+5) != '\0')
+        {
+          /* Initialize profile with "Exif\0\0" if it
+             doesn't already begin with it by accident
+          */
+          *p++ ='E';
+          *p++ ='x';
+          *p++ ='i';
+          *p++ ='f';
+          *p++ ='\0';
+          *p++ ='\0';
+        }
+
+      /* copy chunk->data to profile */
+      s=chunk->data;
+      for (i=0; i<chunk->size; i++)
+        *p++ = *s++;
+
+      (void) SetImageProfile(image,"exif",
+         (const unsigned char *)profile, chunk->size+6);
+      return(1);
+    }
+
+  /* orNT */
+  if (chunk->name[0] == 111 &&
+      chunk->name[1] == 114 &&
+      chunk->name[2] ==  78 &&
+      chunk->name[3] ==  84)
+    {
+     /* recognized orNT */
+     if (chunk->size != 1)
+       return(-1); /* Error return */
+
+     image=(Image *) png_get_user_chunk_ptr(ping);
+     if (chunk->data[0] < 9)
+       image->orientation = chunk->data[0];
+     else
+       image->orientation = 0;
+     return(1);
+    }
+
+  /* caNv */
+  if (chunk->name[0] ==  99 &&
+      chunk->name[1] ==  97 &&
+      chunk->name[2] ==  78 &&
+      chunk->name[3] == 118)
+    {
+     /* recognized caNv */
+
+     if (chunk->size != 16)
+       return(-1); /* Error return */
+
+     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+             " recognized caNv chunk");
+
+     image=(Image *) png_get_user_chunk_ptr(ping);
+
+     image->page.width=(size_t) mng_get_long(chunk->data);
+     image->page.height=(size_t) mng_get_long(&chunk->data[4]);
+     image->page.x=(size_t) mng_get_long(&chunk->data[8]);
+     image->page.y=(size_t) mng_get_long(&chunk->data[12]);
+
+     return(1);
+    }
+
+  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+         " unrecognized user chunk");
+
+  return(0); /* Did not recognize */
+}
+#endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */
+
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -1369,6 +1523,8 @@ static Image *ReadOnePNGImage(MngInfo *m
       ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
     }
 
+  png_set_crc_action(ping, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
+
   mng_info->png_pixels=(unsigned char *) NULL;
   mng_info->quantum_scanline=(Quantum *) NULL;
 
@@ -1416,12 +1572,15 @@ static Image *ReadOnePNGImage(MngInfo *m
   png_set_benign_errors(ping, 1);
 #endif
 
+  /* Just use libpng's limit (PNG_USER_CHUNK_MALLOC_MAX == 8000000) on
+     chunk size */
 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
   /* Reject images with too many rows or columns */
   png_set_user_limits(ping,
     (png_uint_32) Min(0x7fffffffL, GetMagickResourceLimit(WidthResource)),
     (png_uint_32) Min(0x7fffffffL, GetMagickResourceLimit(HeightResource)));
 #endif /* PNG_SET_USER_LIMITS_SUPPORTED */
+
   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                             "    PNG width limit: %lu, height limit: %lu",
     (unsigned long) Min(0x7fffffffL, GetMagickResourceLimit(WidthResource)),
@@ -1441,16 +1600,16 @@ static Image *ReadOnePNGImage(MngInfo *m
       (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
       png_set_read_fn(ping,image,png_get_data);
 #else
-#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
+# if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
       png_permit_empty_plte(ping,MagickTrue);
       png_set_read_fn(ping,image,png_get_data);
-#else
+# else
       mng_info->image=image;
       mng_info->bytes_in_read_buffer=0;
       mng_info->found_empty_plte=MagickFalse;
       mng_info->have_saved_bkgd_index=MagickFalse;
       png_set_read_fn(ping,mng_info,mng_get_data);
-#endif
+# endif
 #endif
     }
   else
@@ -1458,14 +1617,17 @@ static Image *ReadOnePNGImage(MngInfo *m
 
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   /* Ignore unknown chunks */
-#if PNG_LIBPNG_VER < 10700 /* Avoid a libpng16 warning */
+# if PNG_LIBPNG_VER < 10700 /* Avoid a libpng16 warning */
   png_set_keep_unknown_chunks(ping, 2, NULL, 0);
-#else
+# else
   png_set_keep_unknown_chunks(ping, 1, NULL, 0);
-#endif
-  /* Ignore unused chunks */
+# endif
+  /* Ignore unused chunks and all unknown chunks except for caNv */
+  png_set_keep_unknown_chunks(ping, 2, (png_bytep) mng_caNv, 1);
   png_set_keep_unknown_chunks(ping, 1, unused_chunks,
                               (int)sizeof(unused_chunks)/5);
+  /* Callback for other unknown chunks */
+  png_set_read_user_chunk_fn(ping, image, read_user_chunk_callback);
 #endif
 
 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
@@ -1562,7 +1724,7 @@ static Image *ReadOnePNGImage(MngInfo *m
 
   /* Too big? */
   if (ping_width >
-     (magick_uint64_t) GetMagickResourceLimit(PixelsResource)/ping_height)
+    (magick_uint64_t) GetMagickResourceLimit(PixelsResource)/ping_height)
   {
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "Number of pixels exceeds resource limit");
@@ -1808,7 +1970,7 @@ static Image *ReadOnePNGImage(MngInfo *m
     }
 
 #if defined(PNG_READ_bKGD_SUPPORTED)
-  if (mng_info->have_global_bkgd && 
+  if (mng_info->have_global_bkgd &&
               !(png_get_valid(ping,ping_info, PNG_INFO_bKGD)))
     image->background_color=mng_info->mng_global_bkgd;
   if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
@@ -1886,7 +2048,7 @@ static Image *ReadOnePNGImage(MngInfo *m
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "    Reading PNG tRNS chunk.");
 
-      bit_mask = (1 << ping_file_depth) - 1;
+      bit_mask = (1U << ping_file_depth) - 1;
 
       /*
         Image has a transparent background.
@@ -1966,7 +2128,7 @@ static Image *ReadOnePNGImage(MngInfo *m
       (ping_colortype == PNG_COLOR_TYPE_GRAY))
     {
       image->storage_class=PseudoClass;
-      image->colors=1 << ping_file_depth;
+      image->colors=1U << ping_file_depth;
 #if (QuantumDepth == 8)
       if (image->colors > 256)
         image->colors=256;
@@ -2019,7 +2181,7 @@ static Image *ReadOnePNGImage(MngInfo *m
           unsigned long
             scale;
 
-          scale=(MaxRGB/((1 << ping_file_depth)-1));
+          scale=(MaxRGB/((1U << ping_file_depth)-1));
           if (scale < 1)
             scale=1;
           for (i=0; i < (long) image->colors; i++)
@@ -2064,12 +2226,24 @@ static Image *ReadOnePNGImage(MngInfo *m
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                           "    Reading PNG IDAT chunk(s)");
   if (num_passes > 1)
-    mng_info->png_pixels=MagickAllocateMemory(unsigned char *,
-                                    ping_rowbytes*image->rows);
+  {
+    if (ping_rowbytes < GetMagickResourceLimit(MemoryResource)/image->rows)
+      mng_info->png_pixels=MagickAllocateMemory(unsigned char *,
+               ping_rowbytes*image->rows);
+    else
+      png_error(ping, "png_pixels array exceeds MemoryResource");
+  }
   else
-    mng_info->png_pixels=MagickAllocateMemory(unsigned char *, ping_rowbytes);
+  {
+    if ((magick_int64_t)ping_rowbytes < GetMagickResourceLimit(MemoryResource))
+      mng_info->png_pixels=MagickAllocateMemory(unsigned char *, ping_rowbytes);
+    else
+      png_error(ping, "png_rowbytes array exceeds MemoryResource");
+  }
   if (mng_info->png_pixels == (unsigned char *) NULL)
+  {
     png_error(ping, "Could not allocate png_pixels array");
+  }
 
   if (logging)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -2103,7 +2277,7 @@ static Image *ReadOnePNGImage(MngInfo *m
 
             png_read_row(ping,mng_info->png_pixels+row_offset,NULL);
 
-	    if (!SetImagePixels(image,0,y,image->columns,1))
+            if (!SetImagePixels(image,0,y,image->columns,1))
               break;
 
             if (pass < num_passes-1)
@@ -2125,7 +2299,8 @@ static Image *ReadOnePNGImage(MngInfo *m
                         *r++=*p++;
                         p++;
                         if ((png_get_valid(ping, ping_info, PNG_INFO_tRNS)) &&
-                            ((unsigned long) ((*(p-2) << 8)|*(p-1))
+                            ((unsigned long) (((magick_uint32_t) *(p-2) << 8)|
+                                              (magick_uint32_t) *(p-1))
                             == transparent_color.opacity))
                           {
                             /* Cheap transparency */
@@ -2146,11 +2321,11 @@ static Image *ReadOnePNGImage(MngInfo *m
                           p++;
                           *r++=*p++;
                           p++;
-                          if (((unsigned long) ((*(p-6) << 8)|*(p-5)) ==
+                          if (((unsigned long) (((magick_uint32_t) *(p-6) << 8)|*(p-5)) ==
                               transparent_color.red) &&
-                              ((unsigned long) ((*(p-4) << 8)|*(p-3)) ==
+                              ((unsigned long) (((magick_uint32_t) *(p-4) << 8)|*(p-3)) ==
                               transparent_color.green) &&
-                              ((unsigned long) ((*(p-2) << 8)|*(p-1)) ==
+                              ((unsigned long) (((magick_uint32_t) *(p-2) << 8)|*(p-1)) ==
                               transparent_color.blue))
                             {
                               /* Cheap transparency */
@@ -2263,146 +2438,152 @@ static Image *ReadOnePNGImage(MngInfo *m
           if (QuantumTick(pass, num_passes))
             if (!MagickMonitorFormatted(pass,num_passes,exception,
                                         LoadImageTag,image->filename,
-				        image->columns,image->rows))
+                                        image->columns,image->rows))
                break;
       }
 
   else /* image->storage_class != DirectClass */
-  {
-   image->matte=ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA;
-   mng_info->quantum_scanline=MagickAllocateMemory(Quantum *,
-      (image->matte ?  2 : 1) * image->columns*sizeof(Quantum));
-   if (mng_info->quantum_scanline == (Quantum *) NULL)
-     png_error(ping, "Could not allocate quantum_scanline");
-   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                         "      Allocated quantum_scanline");
+    {
+      image->matte=ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA;
+      mng_info->quantum_scanline=
+        MagickAllocateMemory(Quantum *,
+                             (image->matte ?  2 : 1) *
+                             image->columns*sizeof(Quantum));
+      if (mng_info->quantum_scanline == (Quantum *) NULL)
+        png_error(ping, "Could not allocate quantum_scanline");
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                            "      Allocated quantum_scanline");
 
-    for (pass=0; pass < num_passes; pass++)
-      {
-        register Quantum
-          *r;
+      for (pass=0; pass < num_passes; pass++)
+        {
+          register Quantum
+            *r;
 
-        /*
-          Convert grayscale image to PseudoClass pixel packets.
-        */
-        for (y=0; y < (long) image->rows; y++)
-          {
-            register unsigned char
-              *p;
+          /*
+            Convert grayscale image to PseudoClass pixel packets.
+          */
+          for (y=0; y < (long) image->rows; y++)
+            {
+              register unsigned char
+                *p;
 
-            if (num_passes > 1)
-              row_offset=ping_rowbytes*y;
+              if (num_passes > 1)
+                row_offset=ping_rowbytes*y;
 
-            else
-              row_offset=0;
+              else
+                row_offset=0;
 
-            png_read_row(ping,mng_info->png_pixels+row_offset,NULL);
-            q=SetImagePixels(image,0,y,image->columns,1);
-            if (q == (PixelPacket *) NULL)
-              break;
+              png_read_row(ping,mng_info->png_pixels+row_offset,NULL);
+              q=SetImagePixels(image,0,y,image->columns,1);
+              if (q == (PixelPacket *) NULL)
+                break;
 
-            if (pass < num_passes-1)
-              continue;
+              if (pass < num_passes-1)
+                continue;
 
-            indexes=AccessMutableIndexes(image);
-            p=mng_info->png_pixels+row_offset;
-            r=mng_info->quantum_scanline;
-            switch (ping_bit_depth)
-              {
-              case 8:
-                {
-                  if (ping_colortype == 4)
-                    for (x=(long) image->columns; x > 0; x--)
-                      {
-                        *r++=*p++;
-                        /* In image.h, OpaqueOpacity is 0
-                         * TransparentOpacity is MaxRGB
-                         * In a PNG datastream, Opaque is MaxRGB
-                         * and Transparent is 0.
-                         */
-                        q->opacity=ScaleCharToQuantum(255-(*p++));
-                        q++;
-                      }
-                  else
-                    for (x=(long) image->columns; x > 0; x--)
-                      *r++=*p++;
-                  break;
-                }
-              case 16:
+              indexes=AccessMutableIndexes(image);
+              p=mng_info->png_pixels+row_offset;
+              r=mng_info->quantum_scanline;
+              switch (ping_bit_depth)
                 {
-                  for (x=(long) image->columns; x > 0; x--)
-                    {
-#if (QuantumDepth == 16)
-                      if (image->colors > 256)
-                        *r=((*p++) << 8);
-                      else
-                        *r=0;
-                      *r|=(*p++);
-                      r++;
-                      if (ping_colortype == 4)
+                case 8:
+                  {
+                    if (ping_colortype == 4)
+                      for (x=(long) image->columns; x > 0; x--)
                         {
-                          q->opacity=((*p++) << 8);
-                          q->opacity|=(*p++);
-                          q->opacity=(Quantum) (MaxRGB-q->opacity);
+                          *r++=*p++;
+                          /* In image.h, OpaqueOpacity is 0
+                           * TransparentOpacity is MaxRGB
+                           * In a PNG datastream, Opaque is MaxRGB
+                           * and Transparent is 0.
+                           */
+                          q->opacity=ScaleCharToQuantum(255-(*p++));
                           q++;
                         }
+                    else
+                      for (x=(long) image->columns; x > 0; x--)
+                        *r++=*p++;
+                    break;
+                  }
+                case 16:
+                  {
+                    for (x=(long) image->columns; x > 0; x--)
+                      {
+#if (QuantumDepth == 16)
+                        if (image->colors > 256)
+                          *r=(((magick_uint32_t) *p++) << 8);
+                        else
+                          *r=0;
+                        *r|=(*p++);
+                        r++;
+                        if (ping_colortype == 4)
+                          {
+                            q->opacity=(((magick_uint32_t) *p++) << 8);
+                            q->opacity|=((magick_uint32_t) *p++);
+                            q->opacity=(Quantum) (MaxRGB-q->opacity);
+                            q++;
+                          }
 #else
 #if (QuantumDepth == 32)
-                      if (image->colors > 256)
-                        *r=((*p++) << 8);
-                      else
-                        *r=0;
-                      *r|=(*p++);
-                      r++;
-                      if (ping_colortype == 4)
-                        {
-                          q->opacity=((*p++) << 8);
-                          q->opacity|=(*p++);
-                          q->opacity*=65537L;
-                          q->opacity=(Quantum) (MaxRGB-q->opacity);
-                          q++;
-                        }
+                        if (image->colors > 256)
+                          *r=(((magick_uint32_t) *p++) << 8);
+                        else
+                          *r=0;
+                        *r|=(*p++);
+                        r++;
+                        if (ping_colortype == 4)
+                          {
+                            q->opacity=(((magick_uint32_t) *p++) << 8);
+                            q->opacity|=((magick_uint32_t) *p++);
+                            q->opacity*=65537U;
+                            q->opacity=(Quantum) (MaxRGB-q->opacity);
+                            q++;
+                          }
 #else /* QuantumDepth == 8 */
-                      *r++=(*p++);
-                      p++; /* strip low byte */
-                      if (ping_colortype == 4)
-                        {
-                          q->opacity=(Quantum) (MaxRGB-(*p++));
-                          p++;
-                          q++;
-                        }
+                        *r++=(*p++);
+                        p++; /* strip low byte */
+                        if (ping_colortype == 4)
+                          {
+                            q->opacity=(Quantum) (MaxRGB-(*p++));
+                            p++;
+                            q++;
+                          }
 #endif
 #endif
-                    }
+                      }
+                    break;
+                  }
+                default:
                   break;
                 }
-              default:
-                break;
-              }
-            /*
-              Transfer image scanline.
-            */
-            r=mng_info->quantum_scanline;
+              /*
+                Transfer image scanline.
+              */
+              r=mng_info->quantum_scanline;
 
-            for (x=0; x < (long) image->columns; x++)
-              indexes[x]=(*r++);
+              for (x=0; x < (long) image->columns; x++)
+                indexes[x]=(*r++);
 
-            if (!SyncImagePixels(image))
-              break;
+              if (!SyncImagePixels(image))
+                break;
             }
 
-        if (image->previous == (Image *) NULL)
-          if (QuantumTick(pass, num_passes))
-            if (!MagickMonitorFormatted(pass,num_passes,exception,LoadImageTag,
-                                        image->filename,
-            			        image->columns,image->rows))
+          /* Quit 'passes' loop if we encountered an error */
+          if (y < (long) image->rows)
+            break;
+
+          if (image->previous == (Image *) NULL)
+            if (QuantumTick(pass, num_passes))
+              if (!MagickMonitorFormatted(pass,num_passes,exception,LoadImageTag,
+                                          image->filename,
+                                          image->columns,image->rows))
               break;
       }
 
       MagickFreeMemory(mng_info->quantum_scanline);
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "      Free'ed quantum_scanline after last pass");
-  }
+                            "      Free'ed quantum_scanline after last pass");
+    }
 
   if (image->storage_class == PseudoClass)
     (void) SyncImage(image);
@@ -2436,7 +2617,6 @@ static Image *ReadOnePNGImage(MngInfo *m
       image->matte=MagickTrue;
       for (y=0; y < (long) image->rows; y++)
         {
-          image->storage_class=storage_class;
           q=SetImagePixels(image,0,y,image->columns,1);
           if (q == (PixelPacket *) NULL)
             break;
@@ -2454,8 +2634,8 @@ static Image *ReadOnePNGImage(MngInfo *m
                     if (index < (unsigned int) ping_num_trans)
                       q->opacity=
                         ScaleCharToQuantum(255-ping_trans_alpha[index]);
-		    else
-		      q->opacity=OpaqueOpacity;
+                    else
+                      q->opacity=OpaqueOpacity;
                     q++;
                   }
               else if (ping_colortype == PNG_COLOR_TYPE_GRAY)
@@ -2468,8 +2648,8 @@ static Image *ReadOnePNGImage(MngInfo *m
                     if ((unsigned long) ScaleQuantumToShort(q->red) ==
                         transparent_color.opacity)
                       q->opacity=TransparentOpacity;
-		    else
-		      q->opacity=OpaqueOpacity;
+                    else
+                      q->opacity=OpaqueOpacity;
                     q++;
                   }
             }
@@ -2483,8 +2663,8 @@ static Image *ReadOnePNGImage(MngInfo *m
                     (unsigned long) ScaleQuantumToShort(q->blue) ==
                     transparent_color.blue)
                   q->opacity=TransparentOpacity;
-		else
-		  q->opacity=OpaqueOpacity;
+                else
+                  q->opacity=OpaqueOpacity;
                 q++;
               }
           if (!SyncImagePixels(image))
@@ -2573,7 +2753,10 @@ static Image *ReadOnePNGImage(MngInfo *m
             filter_method;
 
           if (mng_info->ob[object_id]->image != (Image *) NULL)
-            DestroyImage(mng_info->ob[object_id]->image);
+            {
+              DestroyImage(mng_info->ob[object_id]->image);
+              mng_info->ob[object_id]->image=(Image *) NULL;
+            }
           mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
                                                     &image->exception);
           if (mng_info->ob[object_id]->image != (Image *) NULL)
@@ -2675,6 +2858,16 @@ static Image *ReadPNGImage(const ImageIn
   {
     ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
   }
+
+  /*
+     Verify that file size large enough to contain a PNG datastream
+     if using a seekable blob
+  */
+  if (BlobIsSeekable(image) && GetBlobSize(image) < 61)
+  {
+    ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image);
+  }
+
   /*
     Allocate a MngInfo structure.
   */
@@ -2706,6 +2899,7 @@ static Image *ReadPNGImage(const ImageIn
       if (image->exception.severity > exception->severity)
         CopyException(exception,&image->exception);
       DestroyImageList(image);
+      image=(Image *) NULL;
       if (logging)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                               "exit ReadPNGImage() with error.");
@@ -2735,18 +2929,32 @@ static Image *ReadPNGImage(const ImageIn
 
 #if defined(JNG_SUPPORTED)
 
-
-void
-DestroyJNGInfo(ImageInfo *color_image_info, ImageInfo *alpha_image_info)
+static void
+DestroyJNG(unsigned char *chunk,Image **color_image,
+   ImageInfo **color_image_info,
+   Image **alpha_image,ImageInfo **alpha_image_info)
 {
-          if (color_image_info != (ImageInfo *)NULL)
-            {
-              DestroyImageInfo(color_image_info);
-            }
-          if (alpha_image_info != (ImageInfo *)NULL)
-            {
-              DestroyImageInfo(alpha_image_info);
-            }
+  MagickFreeMemory(chunk);
+  if (*color_image_info)
+  {
+    DestroyImageInfo(*color_image_info);
+    *color_image_info = (ImageInfo *)NULL;
+  }
+  if (*alpha_image_info)
+  {
+    DestroyImageInfo(*alpha_image_info);
+    *alpha_image_info = (ImageInfo *)NULL;
+  }
+  if (*color_image)
+  {
+    DestroyImage(*color_image);
+    *color_image = (Image *)NULL;
+  }
+  if (*alpha_image)
+  {
+    DestroyImage(*alpha_image);
+    *alpha_image = (Image *)NULL;
+  }
 }
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2801,14 +3009,14 @@ static Image *ReadOneJNGImage(MngInfo *m
   long
     y;
 
-  unsigned long
-    jng_height,
-    jng_width;
-
   magick_int64_t
     height_resource,
     width_resource;
 
+  unsigned long
+    jng_height,
+    jng_width;
+
   png_byte
     jng_color_type,
     jng_image_sample_depth,
@@ -2907,17 +3115,25 @@ static Image *ReadOneJNGImage(MngInfo *m
       if (logging)
         {
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                " Reading JNG chunk type %c%c%c%c, length: %lu",
-                                type[0],type[1],type[2],type[3],length);
-      
+                                " Reading JNG chunk type %c%c%c%c, "
+                                "length: %" MAGICK_SIZE_T_F "u",
+                                type[0],type[1],type[2],type[3],
+                                (MAGICK_SIZE_T) length);
+
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                "   count=%u\n",count);
+                                "   count=%u",count);
         }
 
       if (length > PNG_MAX_UINT || count == 0)
         {
-          DestroyJNGInfo(color_image_info,alpha_image_info);
-          ThrowReaderException(CorruptImageError,CorruptImage,image);
+          DestroyJNG(NULL,&color_image,&color_image_info,
+            &alpha_image,&alpha_image_info);
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "chunk length (%" MAGICK_SIZE_T_F "u) > PNG_MAX_UINT",
+                                (MAGICK_SIZE_T) length);
+          ThrowException(exception,CorruptImageError,
+                         ImproperImageHeader,image->filename);
+          return ((Image*)NULL);
         }
 
       chunk=(unsigned char *) NULL;
@@ -2927,14 +3143,23 @@ static Image *ReadOneJNGImage(MngInfo *m
           chunk=MagickAllocateMemory(unsigned char *,length);
           if (chunk == (unsigned char *) NULL)
             {
-              DestroyJNGInfo(color_image_info,alpha_image_info);
-              ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
-                                   image);
+              DestroyJNG(chunk,&color_image,&color_image_info,
+                &alpha_image,&alpha_image_info);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "    Could not allocate chunk memory");
+              ThrowException(exception,ResourceLimitError,
+                             MemoryAllocationFailed,image->filename);
+              return ((Image*)NULL);
             }
           if (ReadBlob(image,length,chunk) < length)
             {
-              DestroyJNGInfo(color_image_info,alpha_image_info);
-              ThrowReaderException(CorruptImageError,CorruptImage,image);
+              DestroyJNG(chunk,&color_image,&color_image_info,
+                &alpha_image,&alpha_image_info);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "    chunk reading was incomplete");
+              ThrowException(exception,CorruptImageError,
+                             InsufficientImageDataInFile,image->filename);
+              return ((Image*)NULL);
             }
           p=chunk;
         }
@@ -2942,63 +3167,54 @@ static Image *ReadOneJNGImage(MngInfo *m
 
       if (!memcmp(type,mng_JHDR,4))
         {
-          if (length != 16)
+          if (length == 16)
             {
-              DestroyJNGInfo(color_image_info,alpha_image_info);
-              MagickFreeMemory(chunk);
-              (void) ThrowException2(&image->exception,CoderWarning,
-                             "Invalid JHDR chunk length",(char *) NULL);
-              return (MagickFail);
-            }
-
-          jng_width=(unsigned long) ((p[0] << 24) | (p[1] << 16) |
-                                     (p[2] << 8) | p[3]);
-          jng_height=(unsigned long) ((p[4] << 24) | (p[5] << 16) |
-                                      (p[6] << 8) | p[7]);
-          jng_color_type=p[8];
-          jng_image_sample_depth=p[9];
-          jng_image_compression_method=p[10];
-          jng_image_interlace_method=p[11];
-          jng_alpha_sample_depth=p[12];
-          jng_alpha_compression_method=p[13];
-          jng_alpha_filter_method=p[14];
-          jng_alpha_interlace_method=p[15];
-          if (logging)
-            {
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_width:      %16lu",
-                                    jng_width);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_height:     %16lu",
-                                    jng_height);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_color_type: %16d",
-                                    jng_color_type);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_image_sample_depth:      %3d",
-                                    jng_image_sample_depth);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_image_compression_method:%3d",
-                                    jng_image_compression_method);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_image_interlace_method:  %3d",
-                                    jng_image_interlace_method);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_alpha_sample_depth:      %3d",
-                                jng_alpha_sample_depth);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_alpha_compression_method:%3d",
-                                    jng_alpha_compression_method);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_alpha_filter_method:     %3d",
-                                    jng_alpha_filter_method);
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                    "    jng_alpha_interlace_method:  %3d",
-                                    jng_alpha_interlace_method);
+              jng_width=(unsigned long) mng_get_long(p);
+              jng_height=(unsigned long) mng_get_long(&p[4]);
+              jng_color_type=p[8];
+              jng_image_sample_depth=p[9];
+              jng_image_compression_method=p[10];
+              jng_image_interlace_method=p[11];
+              jng_alpha_sample_depth=p[12];
+              jng_alpha_compression_method=p[13];
+              jng_alpha_filter_method=p[14];
+              jng_alpha_interlace_method=p[15];
+              if (logging)
+                {
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_width:      %16lu",
+                      jng_width);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_height:     %16lu",
+                      jng_height);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_color_type: %16d",
+                      jng_color_type);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_image_sample_depth:      %3d",
+                      jng_image_sample_depth);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_image_compression_method:%3d",
+                      jng_image_compression_method);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_image_interlace_method:  %3d",
+                      jng_image_interlace_method);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_alpha_sample_depth:      %3d",
+                      jng_alpha_sample_depth);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_alpha_compression_method:%3d",
+                      jng_alpha_compression_method);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_alpha_filter_method:     %3d",
+                      jng_alpha_filter_method);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    jng_alpha_interlace_method:  %3d",
+                      jng_alpha_interlace_method);
+                }
             }
 
-          if (length)
-            MagickFreeMemory(chunk);
+          MagickFreeMemory(chunk);
 
           if (jng_width > 65535 || jng_height > 65535 ||
                (long) jng_width > GetMagickResourceLimit(WidthResource) ||
@@ -3007,9 +3223,11 @@ static Image *ReadOneJNGImage(MngInfo *m
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                  "    JNG width or height too large: (%lu x %lu)",
                   jng_width, jng_height);
-              MagickFreeMemory(chunk);
-              DestroyJNGInfo(color_image_info,alpha_image_info);
-              ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
+              ThrowException(exception,CorruptImageError,
+                             ImproperImageHeader,image->filename);
+              DestroyJNG(chunk,&color_image,&color_image_info,
+                &alpha_image,&alpha_image_info);
+              return ((Image *)NULL);
             }
 
           /* Rationalize dimensions with blob size if it is available */
@@ -3030,20 +3248,22 @@ static Image *ReadOneJNGImage(MngInfo *m
 
                   ThrowException(exception,CorruptImageError,
                                  InsufficientImageDataInFile,image->filename);
-                  MagickFreeMemory(chunk);
-                  DestroyJNGInfo(color_image_info,alpha_image_info);
+                  DestroyJNG(chunk,&color_image,&color_image_info,
+                             &alpha_image,&alpha_image_info);
                   return ((Image *)NULL);
                 }
             }
 
+          /* Temporarily set width and height resources to match JHDR */
+          SetMagickResourceLimit(WidthResource,jng_width);
+          SetMagickResourceLimit(HeightResource,jng_height);
+
           continue;
         }
 
-
-      if (!reading_idat && !read_JSEP && (!memcmp(type,mng_JDAT,4) ||
-                                          !memcmp(type,mng_JdAA,4) ||
-                                          !memcmp(type,mng_IDAT,4) ||
-                                          !memcmp(type,mng_JDAA,4)))
+      if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
+         ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
+         (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
         {
           /*
             o create color_image
@@ -3055,17 +3275,25 @@ static Image *ReadOneJNGImage(MngInfo *m
           color_image_info=MagickAllocateMemory(ImageInfo *,sizeof(ImageInfo));
           if (color_image_info == (ImageInfo *) NULL)
             {
-              DestroyJNGInfo(color_image_info,alpha_image_info);
-              ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
-                                   image);
+              DestroyJNG(chunk,&color_image,&color_image_info,
+                &alpha_image,&alpha_image_info);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "    could not allocate color_image_info");
+              ThrowException(exception,ResourceLimitError,
+                             MemoryAllocationFailed,image->filename);
+              return ((Image *)NULL);
             }
           GetImageInfo(color_image_info);
           color_image=AllocateImage(color_image_info);
           if (color_image == (Image *) NULL)
             {
-              DestroyJNGInfo(color_image_info,alpha_image_info);
-              ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
-                                   image);
+              DestroyJNG(chunk,&color_image,&color_image_info,
+                &alpha_image,&alpha_image_info);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "    could not allocate color_image");
+              ThrowException(exception,ResourceLimitError,
+                             MemoryAllocationFailed,image->filename);
+              return ((Image *)NULL);
             }
           if (logging)
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -3075,8 +3303,11 @@ static Image *ReadOneJNGImage(MngInfo *m
                           exception);
           if (status == MagickFalse)
             {
-              DestroyJNGInfo(color_image_info,alpha_image_info);
-              ThrowReaderException(CoderError,UnableToOpenBlob,color_image);
+              DestroyJNG(chunk,&color_image,&color_image_info,
+                &alpha_image,&alpha_image_info);
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                  "    could not open color_image blob");
+              return ((Image *)NULL);
             }
 
           if (!image_info->ping && jng_color_type >= 12)
@@ -3085,18 +3316,25 @@ static Image *ReadOneJNGImage(MngInfo *m
                                                     sizeof(ImageInfo));
               if (alpha_image_info == (ImageInfo *) NULL)
                 {
-                  DestroyJNGInfo(color_image_info,alpha_image_info);
-                  ThrowReaderException(ResourceLimitError,
-                                       MemoryAllocationFailed, image);
+                  DestroyJNG(chunk,&color_image,&color_image_info,
+                    &alpha_image,&alpha_image_info);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    could not allocate alpha_image_info");
+                  ThrowException(exception,ResourceLimitError,
+                                 MemoryAllocationFailed,image->filename);
+                  return ((Image *)NULL);
                 }
               GetImageInfo(alpha_image_info);
               alpha_image=AllocateImage(alpha_image_info);
               if (alpha_image == (Image *) NULL)
                 {
-                  DestroyJNGInfo(color_image_info,alpha_image_info);
-                  ThrowReaderException(ResourceLimitError,
-                                       MemoryAllocationFailed,
-                                       alpha_image);
+                  DestroyJNG(chunk,&color_image,&color_image_info,
+                    &alpha_image,&alpha_image_info);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    could not allocate alpha_image");
+                  ThrowException(exception,ResourceLimitError,
+                                 MemoryAllocationFailed,image->filename);
+                  return ((Image *)NULL);
                 }
               if (logging)
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -3106,9 +3344,11 @@ static Image *ReadOneJNGImage(MngInfo *m
                               exception);
               if (status == MagickFalse)
                 {
-                  DestroyJNGInfo(color_image_info,alpha_image_info);
-                  DestroyImage(alpha_image);
-                  ThrowReaderException(CoderError,UnableToOpenBlob,image);
+                  DestroyJNG(chunk,&color_image,&color_image_info,
+                    &alpha_image,&alpha_image_info);
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "    could not open alpha_image blob");
+                  return ((Image *)NULL);
                 }
               if (jng_alpha_compression_method == 0)
                 {
@@ -3145,11 +3385,13 @@ static Image *ReadOneJNGImage(MngInfo *m
 
           if (logging)
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                  "    Copying JDAT chunk data"
-                                  " to color_blob.");
-          if (length) {
-            if (color_image != (Image *)NULL)
-              (void) WriteBlob(color_image,length,(char *) chunk);
+                                  "    Copying %" MAGICK_SIZE_T_F
+                                  "u bytes of JDAT chunk data"
+                                  " to color_blob.",
+                                  (MAGICK_SIZE_T) length);
+          if (length && color_image != (Image *)NULL)
+          {
+            (void) WriteBlob(color_image,length,(char *) chunk);
             MagickFreeMemory(chunk);
           }
           continue;
@@ -3167,25 +3409,28 @@ static Image *ReadOneJNGImage(MngInfo *m
           if (alpha_image != NULL && image_info->ping == MagickFalse)
             {
               if (logging)
+              {
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                      "    Copying IDAT chunk data"
-                                      " to alpha_blob.");
-
+                    "    Copying IDAT chunk data"
+                    " to alpha_blob.");
+              }
+              if (length == 0)
+              {
+                if (logging)
+                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                    "    IDAT chunk has length 0");
+                MagickFreeMemory(chunk);
+                continue;
+              }
               (void) WriteBlobMSBULong(alpha_image,(unsigned long) length);
               PNGType(data,mng_IDAT);
               LogPNGChunk(logging,mng_IDAT,length);
               (void) WriteBlob(alpha_image,4,(char *) data);
               (void) WriteBlob(alpha_image,length,(char *) chunk);
               (void) WriteBlobMSBULong(alpha_image,
-                                       crc32(crc32(0,data,4),chunk,length));
+                                       crc32(crc32(0,data,4),chunk,(uInt) length));
             }
-          if (length)
-            MagickFreeMemory(chunk);
-
-
-          SetMagickResourceLimit(WidthResource,jng_width);
-          SetMagickResourceLimit(HeightResource,jng_height);
-
+          MagickFreeMemory(chunk);
           continue;
         }
 
@@ -3204,16 +3449,14 @@ static Image *ReadOneJNGImage(MngInfo *m
 
               (void) WriteBlob(alpha_image,length,(char *) chunk);
             }
-          if (length)
-            MagickFreeMemory(chunk);
+          MagickFreeMemory(chunk);
           continue;
         }
 
       if (!memcmp(type,mng_JSEP,4))
         {
           read_JSEP=MagickTrue;
-          if (length)
-            MagickFreeMemory(chunk);
+          MagickFreeMemory(chunk);
           continue;
         }
 
@@ -3285,14 +3528,13 @@ static Image *ReadOneJNGImage(MngInfo *m
             {
               image->page.x=mng_get_long(p);
               image->page.y=mng_get_long(&p[4]);
-              if ((int) p[9] != 0)
+              if ((int) p[8] != 0)
                 {
                   image->page.x/=10000;
                   image->page.y/=10000;
                 }
             }
-          if (length)
-            MagickFreeMemory(chunk);
+          MagickFreeMemory(chunk);
           continue;
         }
 
@@ -3317,14 +3559,12 @@ static Image *ReadOneJNGImage(MngInfo *m
       if (!memcmp(type,mng_iCCP,4))
         {
           /* To do. */
-          if (length)
-            MagickFreeMemory(chunk);
+          MagickFreeMemory(chunk);
           continue;
         }
 #endif
 
-      if (length)
-        MagickFreeMemory(chunk);
+      MagickFreeMemory(chunk);
 
       if (memcmp(type,mng_IEND,4))
         continue;
@@ -3332,7 +3572,7 @@ static Image *ReadOneJNGImage(MngInfo *m
     }
 
 
-  /* IEND found */
+  /* IEND found or loop ended */
 
   /*
     Finish up reading image data:
@@ -3355,12 +3595,19 @@ static Image *ReadOneJNGImage(MngInfo *m
     o destroy the secondary image.
   */
 
-  if (color_image != (Image *)NULL)
+  if (color_image_info == (ImageInfo *) NULL || color_image == (Image *) NULL)
+    {
+      DestroyImage(color_image);
+      color_image=(Image *) NULL;
+      return (Image *) NULL;
+    }
+
+  else
     {
       CloseBlob(color_image);
       if (logging)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                              "    Reading jng_image from color_blob.");
+            "    Reading jng_image from color_blob.");
 
       FormatString(color_image_info->filename,"%.1024s",color_image->filename);
 
@@ -3378,13 +3625,14 @@ static Image *ReadOneJNGImage(MngInfo *m
             Don't throw exception here since ReadImage() will already
             have thrown it.
           */
-          DestroyImage(image);
+          DestroyJNG(/*chunk*/ NULL,&color_image,&color_image_info,
+                     &alpha_image,&alpha_image_info);
           return (Image *) NULL;
         }
 
       if (logging)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                              "    Copying jng_image pixels to main image.");
+            "    Copying jng_image pixels to main image.");
       image->rows=jng_height;
       image->columns=jng_width;
       length=MagickArraySize(image->columns,sizeof(PixelPacket));
@@ -3394,15 +3642,20 @@ static Image *ReadOneJNGImage(MngInfo *m
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "    jng_width=%lu jng_height=%lu",
               (unsigned long)jng_width,(unsigned long)jng_height);
-          DestroyJNGInfo(color_image_info, &alpha_image_info);
+          DestroyJNG(NULL,&color_image,&color_image_info,
+            &alpha_image,&alpha_image_info);
           DestroyImage(jng_image);
+          ThrowException(exception,CorruptImageError,
+                         ImproperImageHeader,image->filename);
           return ((Image *)NULL);
-        }      
+        }
       for (y=0; y < (long) image->rows; y++)
         {
-          s=AcquireImagePixels(jng_image,0,y,image->columns,1,&image->exception);
-          q=SetImagePixels(image,0,y,image->columns,1);
-          if ((s == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+          s=AcquireImagePixels(jng_image,0,y,image->columns,1,
+             exception);
+          q=SetImagePixelsEx(image,0,y,image->columns,1,exception);
+          if ((s == (const PixelPacket *) NULL) ||
+              (q == (PixelPacket *) NULL))
             break;
           (void) memcpy(q,s,length);
           if (!SyncImagePixels(image))
@@ -3415,7 +3668,8 @@ static Image *ReadOneJNGImage(MngInfo *m
           if (logging)
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                                   "Failed to transfer JPEG scanlines");
-          DestroyJNGInfo(&color_image_info, &alpha_image_info);
+          DestroyJNG(NULL,&color_image,&color_image_info,
+                     &alpha_image,&alpha_image_info);
           return ((Image *)NULL);
         }
       if (alpha_image != (Image *)NULL && !image_info->ping)
@@ -3435,47 +3689,73 @@ static Image *ReadOneJNGImage(MngInfo *m
               CloseBlob(alpha_image);
               if (logging)
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                                      "    Reading opacity from alpha_blob.");
+                     "    Reading opacity from alpha_blob.");
 
               FormatString(alpha_image_info->filename,"%.1024s",
                            alpha_image->filename);
 
               jng_image=ReadImage(alpha_image_info,exception);
 
-              for (y=0; y < (long) image->rows; y++)
+              if (jng_image == (Image *)NULL)
                 {
-                  s=AcquireImagePixels(jng_image,0,y,image->columns,1,
-                                       &image->exception);
-                  if (image->matte)
-                    {
-                      q=SetImagePixels(image,0,y,image->columns,1);
-                      if (q == (PixelPacket *) NULL)
-                        break;
-                      for (x=(long) image->columns; x > 0; x--,q++,s++)
-                        q->opacity=(Quantum) MaxRGB-s->red;
-                    }
-                  else
-                    {
-                      q=SetImagePixels(image,0,y,image->columns,1);
-                      if (q == (PixelPacket *) NULL)
-                        break;
-                      for (x=(long) image->columns; x > 0; x--,q++,s++)
-                        {
-                          q->opacity=(Quantum) MaxRGB-s->red;
-                          if (q->opacity != OpaqueOpacity)
-                            image->matte=MagickTrue;
-                        }
-                    }
-                  if (!SyncImagePixels(image))
-                    break;
-                }
-              (void) LiberateUniqueFileResource(alpha_image->filename);
-              DestroyImage(alpha_image);
-              alpha_image = (Image *)NULL;
-              DestroyImageInfo(alpha_image_info);
-              alpha_image_info = (ImageInfo *)NULL;
-              DestroyImage(jng_image);
-              jng_image = (Image *)NULL;
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                       "    jng_image is NULL.");
+                  DestroyJNG(NULL,&color_image,&color_image_info,
+                    &alpha_image,&alpha_image_info);
+                }
+             else
+                {
+
+                 if (logging)
+                   {
+                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "    Read jng_image.");
+                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "      jng_image->width=%lu, jng_image->height=%lu",
+                          (unsigned long)jng_width,(unsigned long)jng_height);
+                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "      image->rows=%lu, image->columns=%lu",
+                         (unsigned long)image->rows,
+                         (unsigned long)image->columns);
+                   }
+
+                 for (y=0; y < (long) image->rows; y++)
+                   {
+                     s=AcquireImagePixels(jng_image,0,y,image->columns,1,
+                                          &image->exception);
+                     if (s == (PixelPacket *) NULL)
+                       break;
+                     if (image->matte)
+                       {
+                         q=SetImagePixels(image,0,y,image->columns,1);
+                         if (q == (PixelPacket *) NULL)
+                           break;
+                         for (x=(long) image->columns; x > 0; x--,q++,s++)
+                           q->opacity=(Quantum) MaxRGB-s->red;
+                       }
+                     else
+                       {
+                         q=SetImagePixels(image,0,y,image->columns,1);
+                         if (q == (PixelPacket *) NULL)
+                           break;
+                         for (x=(long) image->columns; x > 0; x--,q++,s++)
+                           {
+                             q->opacity=(Quantum) MaxRGB-s->red;
+                             if (q->opacity != OpaqueOpacity)
+                               image->matte=MagickTrue;
+                           }
+                       }
+                     if (!SyncImagePixels(image))
+                       break;
+                   }
+                 (void) LiberateUniqueFileResource(alpha_image->filename);
+                 DestroyJNG(NULL,&color_image,&color_image_info,
+                   &alpha_image,&alpha_image_info);
+                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                     " Destroy the JNG image");
+                 DestroyImage(jng_image);
+                 jng_image = (Image *)NULL;
+               }
             }
         }
 
@@ -3496,13 +3776,8 @@ static Image *ReadOneJNGImage(MngInfo *m
 
   /* Clean up in case we didn't earlier */
 
-  DestroyJNGInfo(color_image_info,alpha_image_info);
-
-  if (alpha_image != (Image *)NULL)
-    {
-      (void) LiberateUniqueFileResource(alpha_image->filename);
-      DestroyImage(alpha_image);
-    }
+  DestroyJNG(NULL,&color_image,&color_image_info,
+    &alpha_image,&alpha_image_info);
 
   if (logging)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -3580,22 +3855,58 @@ static Image *ReadJNGImage(const ImageIn
   mng_info=(MngInfo *) NULL;
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   if (status == MagickFalse)
-    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
+  {
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Unable to open file");
+    ThrowException(exception,FileOpenError,UnableToOpenFile,image->filename);
+    DestroyImageList(image);
+    image=(Image *) NULL;
+    return ((Image *)NULL);
+  }
   if (LocaleCompare(image_info->magick,"JNG") != 0)
-    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
+  {
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Improper Image Header");
+    ThrowException(exception,CorruptImageError,ImproperImageHeader,image->filename);
+    DestroyImageList(image);
+    image=(Image *) NULL;
+    return((Image *)NULL);
+  }
   /*
     Verify JNG signature.
   */
   if ((ReadBlob(image,8,magic_number) != 8) ||
       (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0))
-    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
+  {
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Improper Image Header");
+    ThrowException(exception,CorruptImageError,ImproperImageHeader,image->filename);
+    DestroyImageList(image);
+    image=(Image *) NULL;
+    return((Image *)NULL);
+  }
+
+  if (BlobIsSeekable(image) && GetBlobSize(image) < 147)
+  {
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+        "Insufficient Image Data");
+    ThrowException(exception,CorruptImageError,InsufficientImageDataInFile,image->filename);
+    DestroyImageList(image);
+    image=(Image *) NULL;
+    return((Image *)NULL);
+  }
+
   /*
     Allocate a MngInfo structure.
   */
   have_mng_structure=MagickFalse;
   mng_info=MagickAllocateMemory(MngInfo *,sizeof(MngInfo));
   if (mng_info == (MngInfo *) NULL)
-    ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
+  {
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+        "Memory Allocation Failed");
+    ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image->filename);
+    DestroyImageList(image);
+    image=(Image *) NULL;
+    return((Image *)NULL);
+  }
   /*
     Initialize members of the MngInfo structure.
   */
@@ -3604,23 +3915,28 @@ static Image *ReadJNGImage(const ImageIn
 
   mng_info->image=image;
   image=ReadOneJNGImage(mng_info,image_info,exception);
-  MngInfoFreeStruct(mng_info,&have_mng_structure);
-  if (image == (Image *) NULL)
+  if (image == (Image *) NULL || image->columns == 0 || image->rows == 0)
     {
       if (logging)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                              "exit ReadJNGImage() with error");
-      return((Image *) NULL);
+            "exit ReadJNGImage() with error");
+      if (image != (Image *) NULL)
+        {
+          DestroyImageList(image);
+          image=(Image *) NULL;
+        }
+      if (mng_info->image != (Image *) NULL)
+        {
+          DestroyImageList(mng_info->image);
+          mng_info->image=(Image *) NULL;
+        }
+      MngInfoFreeStruct(mng_info,&have_mng_structure);
+      return((Image *)NULL);
     }
+
   CloseBlob(image);
-  if (image->columns == 0 || image->rows == 0)
-    {
-      DestroyImageList(image);
-      if (logging)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                              "exit ReadJNGImage() with error");
-      return((Image *) NULL);
-    }
+  MngInfoFreeStruct(mng_info,&have_mng_structure);
+
   if (logging)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
   return (image);
@@ -3799,7 +4115,7 @@ static Image *ReadMNGImage(const ImageIn
       if (LocaleCompare(image_info->magick,"MNG") == 0)
         {
           register unsigned char
-            *p;
+            *p = 0;
 
           unsigned char
             *chunk;
@@ -3809,7 +4125,7 @@ static Image *ReadMNGImage(const ImageIn
           */
           type[0]='\0';
           (void) strcat(type,"errr");
-          length=ReadBlobMSBLong(image);
+          length=(size_t) ReadBlobMSBLong(image);
           count=ReadBlob(image,4,type);
           if (count < 4)
             {
@@ -3829,9 +4145,10 @@ static Image *ReadMNGImage(const ImageIn
                                   type[0],type[1],type[2],type[3],length);
 
           if (length > PNG_MAX_UINT)
-            status=MagickFalse;
-          p=NULL;
-          chunk=(unsigned char *) NULL;
+            {
+              MngInfoFreeStruct(mng_info,&have_mng_structure);
+              ThrowReaderException(CorruptImageError,CorruptImage,image);
+            }
           if (length)
             {
               chunk=MagickAllocateMemory(unsigned char *,length);
@@ -3840,6 +4157,7 @@ static Image *ReadMNGImage(const ImageIn
                                      image);
               if (ReadBlob(image,length,chunk) < length)
                 {
+                  MagickFree(chunk);
                   MngInfoFreeStruct(mng_info,&have_mng_structure);
                   ThrowReaderException(CorruptImageError,CorruptImage,image);
                 }
@@ -3867,13 +4185,15 @@ static Image *ReadMNGImage(const ImageIn
               mng_info->dhdr_warning++;
             }
           if (!memcmp(type,mng_MEND,4))
-            break;
+            {
+              MagickFreeMemory(chunk);
+              break;
+            }
           if (skip_to_iend)
             {
               if (!memcmp(type,mng_IEND,4))
                 skip_to_iend=MagickFalse;
-              if (length)
-                MagickFreeMemory(chunk);
+              MagickFreeMemory(chunk);
               if (logging)
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                                       "  Skip to IEND.");
@@ -3889,12 +4209,8 @@ static Image *ReadMNGImage(const ImageIn
               /* To quiet a Coverity complaint */
               LockSemaphoreInfo(png_semaphore);
 #endif
-              mng_info->mng_width=(unsigned long) ((p[0] << 24) |
-                                                   (p[1] << 16) |
-                                                   (p[2] << 8) | p[3]);
-              mng_info->mng_height=(unsigned long) ((p[4] << 24) |
-                                                    (p[5] << 16) |
-                                                    (p[6] << 8) | p[7]);
+              mng_info->mng_width=(unsigned long) mng_get_long(p);
+              mng_info->mng_height=(unsigned long) mng_get_long(&p[4]);
               if (logging)
                 {
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -3958,11 +4274,18 @@ static Image *ReadMNGImage(const ImageIn
                   mng_info->image=image;
                 }
 
-              if ((mng_info->mng_width > 65535L) || (mng_info->mng_height
-                                                     > 65535L))
-                (void) ThrowException(&image->exception,ImageError,
-                                      WidthOrHeightExceedsLimit,
-                                      image->filename);
+              if ((mng_info->mng_width > 65535L) ||
+                  (mng_info->mng_height > 65535L))
+                {
+                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                      "  MNG width or height is too large: %lu, %lu",
+                      mng_info->mng_width,mng_info->mng_height);
+                  MagickFreeMemory(chunk);
+                  MngInfoFreeStruct(mng_info,&have_mng_structure);
+                  ThrowReaderException(CorruptImageError,
+                     ImproperImageHeader,image);
+                }
+
               FormatString(page_geometry,"%lux%lu+0+0",mng_info->mng_width,
                            mng_info->mng_height);
               mng_info->frame.left=0;
@@ -4015,11 +4338,25 @@ static Image *ReadMNGImage(const ImageIn
           if (!memcmp(type,mng_DEFI,4))
             {
               if (mng_type == 3)
-                (void) ThrowException2(&image->exception,CoderError,
-                                       "DEFI chunk found in MNG-VLC"
-                                       " datastream",
-                                       (char *) NULL);
-              object_id=(p[0] << 8) | p[1];
+                {
+                  if (logging)
+                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                                          "DEFI chunk found in MNG-VLC"
+                                          " datastream");
+                  MagickFreeMemory(chunk);
+                  continue;
+                }
+              if (length < 2)
+                {
+                  if (logging)
+                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                                          "  DEFI chunk must be at least"
+                                          " 2 bytes long");
+                  MagickFreeMemory(chunk);
+                  MngInfoFreeStruct(mng_info,&have_mng_structure);
+                  ThrowReaderException(CorruptImageError,CorruptImage,image);
+                }
+              object_id=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1];
               if (mng_type == 2 && object_id != 0)
                 (void) ThrowException2(&image->exception,CoderError,
                                        "Nonzero object_id in MNG-LC"
@@ -4031,18 +4368,19 @@ static Image *ReadMNGImage(const ImageIn
                     Instead of issuing a warning we should allocate a larger
                     MngInfo structure and continue.
                   */
-                  (void) ThrowException2(&image->exception,CoderError,
-                                         "object id too large",(char *) NULL);
+                  if (logging)
+                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                                          "object id too large");
                   object_id=MNG_MAX_OBJECTS;
                 }
               if (mng_info->exists[object_id])
                 if (mng_info->frozen[object_id])
                   {
+                    if (logging)
+                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                                            "DEFI cannot redefine a frozen"
+                                           " MNG object");
                     MagickFreeMemory(chunk);
-                    (void) ThrowException2(&image->exception,CoderError,
-                                           "DEFI cannot redefine a frozen"
-                                           " MNG object",
-                                           (char *) NULL);
                     continue;
                   }
               mng_info->exists[object_id]=MagickTrue;
@@ -4053,12 +4391,8 @@ static Image *ReadMNGImage(const ImageIn
               */
               if (length > 11)
                 {
-                  mng_info->x_off[object_id]=(long) ((p[4] << 24) |
-                                                     (p[5] << 16) |
-                                                     (p[6] << 8) | p[7]);
-                  mng_info->y_off[object_id]=(long) ((p[8] << 24) |
-                                                     (p[9] << 16) |
-                                                     (p[10] << 8) | p[11]);
+                  mng_info->x_off[object_id]= mng_get_long(&p[4]);
+                  mng_info->y_off[object_id]= mng_get_long(&p[8]);
                   if (logging)
                     {
                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -4084,11 +4418,14 @@ static Image *ReadMNGImage(const ImageIn
               if (length > 5)
                 {
                   mng_info->mng_global_bkgd.red
-                    =ScaleShortToQuantum(((p[0] << 8) | p[1]));
+                    =ScaleShortToQuantum((((magick_uint32_t) p[0] << 8) |
+                                          (magick_uint32_t) p[1]));
                   mng_info->mng_global_bkgd.green
-                    =ScaleShortToQuantum(((p[2] << 8) | p[3]));
+                    =ScaleShortToQuantum((((magick_uint32_t) p[2] << 8) |
+                                          (magick_uint32_t) p[3]));
                   mng_info->mng_global_bkgd.blue
-                    =ScaleShortToQuantum(((p[4] << 8) | p[5]));
+                    =ScaleShortToQuantum((((magick_uint32_t) p[4] << 8) |
+                                          (magick_uint32_t) p[5]));
                   mng_info->have_global_bkgd=MagickTrue;
                 }
               MagickFreeMemory(chunk);
@@ -4104,16 +4441,20 @@ static Image *ReadMNGImage(const ImageIn
               if (mandatory_back && length > 5)
                 {
                   mng_background_color.red=
-                    ScaleShortToQuantum(((p[0] << 8) | p[1]));
+                    ScaleShortToQuantum((((magick_uint32_t) p[0] << 8) |
+                                         (magick_uint32_t) p[1]));
                   mng_background_color.green=
-                    ScaleShortToQuantum(((p[2] << 8) | p[3]));
+                    ScaleShortToQuantum((((magick_uint32_t) p[2] << 8) |
+                                         (magick_uint32_t) p[3]));
                   mng_background_color.blue=
-                    ScaleShortToQuantum(((p[4] << 8) | p[5]));
+                    ScaleShortToQuantum((((magick_uint32_t) p[4] << 8) |
+                                         (magick_uint32_t) p[5]));
                   mng_background_color.opacity=OpaqueOpacity;
                 }
 #ifdef MNG_OBJECT_BUFFERS
               if (length > 8)
-                mng_background_object=(p[7] << 8) | p[8];
+                mng_background_object=((magick_uint32_t) p[7] << 8) |
+                  (magick_uint32_t) p[8];
 #endif
 #endif
               MagickFreeMemory(chunk);
@@ -4237,8 +4578,7 @@ static Image *ReadMNGImage(const ImageIn
               /*
                 Read global iCCP.
               */
-              if (length)
-                MagickFreeMemory(chunk);
+              MagickFreeMemory(chunk);
               continue;
             }
           if (!memcmp(type,mng_FRAM,4))
@@ -4267,7 +4607,7 @@ static Image *ReadMNGImage(const ImageIn
                     Note the delay and frame clipping boundaries.
                   */
                   p++; /* framing mode */
-                  while (*p && ((p-chunk) < (long) length))
+                  while (((p-chunk) < (long) length) && *p)
                     p++;  /* frame name */
                   p++;  /* frame name terminator */
                   if ((p-chunk) < (long) (length-4))
@@ -4305,10 +4645,10 @@ static Image *ReadMNGImage(const ImageIn
                                                   "    Framing_timeout=%ld",
                                                   frame_timeout);
                         }
-                      if (change_clipping && (p-chunk) < (ssize_t) (length-17))
+                      if (change_clipping && (p-chunk) < (ssize_t) (length-16))
                         {
                           fb=mng_read_box(previous_fb,p[0],&p[1]);
-                          p+=17;
+                          p+=16;
                           previous_fb=fb;
                           if (logging)
                             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -4402,8 +4742,8 @@ static Image *ReadMNGImage(const ImageIn
               */
               if (length > 3)
                 {
-                  first_object=(p[0] << 8) | p[1];
-                  last_object=(p[2] << 8) | p[3];
+                  first_object=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1];
+                  last_object=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3];
                   p+=4;
 
                   for (i=(int) first_object; i <= (int) last_object; i++)
@@ -4436,8 +4776,7 @@ static Image *ReadMNGImage(const ImageIn
                       mng_info->ob[i]->frozen=MagickTrue;
 #endif
                   }
-              if (length)
-                MagickFreeMemory(chunk);
+              MagickFreeMemory(chunk);
               continue;
             }
 
@@ -4458,12 +4797,11 @@ static Image *ReadMNGImage(const ImageIn
 
                   for (j=0; j < (long) length; j+=2)
                     {
-                      i=p[j] << 8 | p[j+1];
+                      i=(magick_uint32_t) p[j] << 8 | (magick_uint32_t) p[j+1];
                       MngInfoDiscardObject(mng_info,i);
                     }
                 }
-              if (length)
-                MagickFreeMemory(chunk);
+              MagickFreeMemory(chunk);
               continue;
             }
           if (!memcmp(type,mng_MOVE,4))
@@ -4478,8 +4816,8 @@ static Image *ReadMNGImage(const ImageIn
 
               if (length > 3)
                 {
-                  first_object=(p[0] << 8) | p[1];
-                  last_object=(p[2] << 8) | p[3];
+                  first_object=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1];
+                  last_object=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3];
                   p+=4;
 
                   for (i=(long) first_object; i <= (long) last_object; i++)
@@ -4600,11 +4938,11 @@ static Image *ReadMNGImage(const ImageIn
                 magn_methy;
 
               if (length > 1)
-                magn_first=(p[0] << 8) | p[1];
+                magn_first=((magick_uint32_t) p[0] << 8) | (magick_uint32_t) p[1];
               else
                 magn_first=0;
               if (length > 3)
-                magn_last=(p[2] << 8) | p[3];
+                magn_last=((magick_uint32_t) p[2] << 8) | (magick_uint32_t) p[3];
               else
                 magn_last=magn_first;
 #ifndef MNG_OBJECT_BUFFERS
@@ -4624,42 +4962,42 @@ static Image *ReadMNGImage(const ImageIn
                 magn_methx=0;
 
               if (length > 6)
-                magn_mx=(p[5] << 8) | p[6];
+                magn_mx=((magick_uint32_t) p[5] << 8) | (magick_uint32_t) p[6];
               else
                 magn_mx=1;
               if (magn_mx == 0)
                 magn_mx=1;
 
               if (length > 8)
-                magn_my=(p[7] << 8) | p[8];
+                magn_my=((magick_uint32_t) p[7] << 8) | (magick_uint32_t) p[8];
               else
                 magn_my=magn_mx;
               if (magn_my == 0)
                 magn_my=1;
 
               if (length > 10)
-                magn_ml=(p[9] << 8) | p[10];
+                magn_ml=((magick_uint32_t) p[9] << 8) | (magick_uint32_t) p[10];
               else
                 magn_ml=magn_mx;
               if (magn_ml == 0)
                 magn_ml=1;
 
               if (length > 12)
-                magn_mr=(p[11] << 8) | p[12];
+                magn_mr=((magick_uint32_t) p[11] << 8) | (magick_uint32_t) p[12];
               else
                 magn_mr=magn_mx;
               if (magn_mr == 0)
                 magn_mr=1;
 
               if (length > 14)
-                magn_mt=(p[13] << 8) | p[14];
+                magn_mt=((magick_uint32_t) p[13] << 8) | (magick_uint32_t) p[14];
               else
                 magn_mt=magn_my;
               if (magn_mt == 0)
                 magn_mt=1;
 
               if (length > 16)
-                magn_mb=(p[15] << 8) | p[16];
+                magn_mb=((magick_uint32_t) p[15] << 8) | (magick_uint32_t) p[16];
               else
                 magn_mb=magn_my;
               if (magn_mb == 0)
@@ -4755,28 +5093,29 @@ static Image *ReadMNGImage(const ImageIn
                                        image->filename);
               mng_info->basi_warning++;
 #ifdef MNG_BASI_SUPPORTED
-              basi_width=(unsigned long) ((p[0] << 24) | (p[1] << 16) |
-                                          (p[2] << 8) | p[3]);
-              basi_height=(unsigned long) ((p[4] << 24) | (p[5] << 16) |
-                                           (p[6] << 8) | p[7]);
+              basi_width=(unsigned long) mng_get_long(p);
+                                          ((magick_uint32_t) p[1] << 16) |
+                                          ((magick_uint32_t) p[2] << 8) |
+                                          (magick_uint32_t) p[3]);
+              basi_height=(unsigned long) mng_get_long(&p[4]);
               basi_color_type=p[8];
               basi_compression_method=p[9];
               basi_filter_type=p[10];
               basi_interlace_method=p[11];
               if (length > 11)
-                basi_red=(p[12] << 8) & p[13];
+                basi_red=((magick_uint32_t) p[12] << 8) & (magick_uint32_t) p[13];
               else
                 basi_red=0;
               if (length > 13)
-                basi_green=(p[14] << 8) & p[15];
+                basi_green=((magick_uint32_t) p[14] << 8) & (magick_uint32_t) p[15];
               else
                 basi_green=0;
               if (length > 15)
-                basi_blue=(p[16] << 8) & p[17];
+                basi_blue=((magick_uint32_t) p[16] << 8) & (magick_uint32_t) p[17];
               else
                 basi_blue=0;
               if (length > 17)
-                basi_alpha=(p[18] << 8) & p[19];
+                basi_alpha=((magick_uint32_t) p[18] << 8) & (magick_uint32_t) p[19];
               else
                 {
                   if (basi_sample_depth == 16)
@@ -4799,8 +5138,7 @@ static Image *ReadMNGImage(const ImageIn
               )
             {
               /* Not an IHDR or JHDR chunk */
-              if (length)
-                MagickFreeMemory(chunk);
+              MagickFreeMemory(chunk);
               continue;
             }
           /* Process IHDR */
@@ -5132,6 +5470,8 @@ static Image *ReadMNGImage(const ImageIn
                       for (y=0; y < (long) image->rows; y++)
                         {
                           q=GetImagePixels(image,0,y,image->columns,1);
+                          if(q == (PixelPacket *) NULL)
+                            break;
                           for (x=(long) image->columns; x > 0; x--)
                             {
                               q->red=ScaleQuantumToShort(q->red);
@@ -5172,18 +5512,22 @@ static Image *ReadMNGImage(const ImageIn
                                           large_image->rows);
                   m=mng_info->magn_mt;
                   yy=0;
-                  row_length=(size_t) (image->columns*sizeof(PixelPacket));
+                  row_length=MagickArraySize(image->columns,sizeof(PixelPacket));
                   next=MagickAllocateMemory(PixelPacket *,row_length);
                   prev=MagickAllocateMemory(PixelPacket *,row_length);
                   if ((prev == (PixelPacket *) NULL) ||
                       (next == (PixelPacket *) NULL))
                     {
+                      MagickFreeMemory(next);
+                      MagickFreeMemory(prev);
                       DestroyImageList(image);
                       MngInfoFreeStruct(mng_info,&have_mng_structure);
                       ThrowReaderException(ResourceLimitError,
                                            MemoryAllocationFailed,image)
                     }
                   n=GetImagePixels(image,0,0,image->columns,1);
+                  if(n == (PixelPacket *) NULL)
+                     return ((Image *) NULL);
                   (void) memcpy(next,n,row_length);
                   for (y=0; y < (long) image->rows; y++)
                     {
@@ -5203,6 +5547,8 @@ static Image *ReadMNGImage(const ImageIn
                       if (y < (long) image->rows-1)
                         {
                           n=GetImagePixels(image,0,y+1,image->columns,1);
+                          if(n == (PixelPacket *) NULL)
+                             break;
                           (void) memcpy(next,n,row_length);
                         }
                       for (i=0; i < m; i++, yy++)
@@ -5212,6 +5558,8 @@ static Image *ReadMNGImage(const ImageIn
                           n=next;
                           q=SetImagePixels(large_image,0,yy,
                                            large_image->columns,1);
+                          if (q == (const PixelPacket *) NULL)
+                            break;
                           q+=(large_image->columns-image->columns);
                           for (x=(long) image->columns; x > 0; x--)
                             {
@@ -5307,6 +5655,8 @@ static Image *ReadMNGImage(const ImageIn
                   for (y=0; y < (long) image->rows; y++)
                     {
                       q=GetImagePixels(image,0,y,image->columns,1);
+                      if(q == (PixelPacket * ) NULL)
+                        break;
                       p=q+(image->columns-row_length);
                       n=p+1;
                       for (x=(long) (image->columns-row_length);
@@ -5400,6 +5750,8 @@ static Image *ReadMNGImage(const ImageIn
                       for (y=0; y < (long) image->rows; y++)
                         {
                           q=GetImagePixels(image,0,y,image->columns,1);
+                          if(q == (PixelPacket *) NULL)
+                            break;
                           for (x=(long) image->columns; x > 0; x--)
                             {
                               q->red=ScaleShortToQuantum(q->red);
@@ -5833,7 +6185,7 @@ ModuleExport void RegisterPNGImage(void)
       if (*version != '\0')
         entry->version=version;
       entry->module="PNG";
-      entry->coder_class=PrimaryCoderClass;
+      entry->coder_class=StableCoderClass;
       entry->note=MNGNote;
       (void) RegisterMagickInfo(entry);
 
@@ -5964,7 +6316,7 @@ ModuleExport void RegisterPNGImage(void)
       if (*version != '\0')
         entry->version=version;
       entry->module="PNG";
-      entry->coder_class=PrimaryCoderClass;
+      entry->coder_class=StableCoderClass;
       (void) RegisterMagickInfo(entry);
 
 #if defined(GMPNG_SETJMP_NOT_THREAD_SAFE)
@@ -6173,6 +6525,18 @@ png_write_raw_profile(const ImageInfo *i
 static MagickPassFail WriteOnePNGImage(MngInfo *mng_info,
                                        const ImageInfo *image_info,Image *imagep)
 {
+  const char
+    *gm_vers,
+    *libpng_runv,
+    *libpng_vers,
+    *zlib_runv,
+    *zlib_vers;
+
+#ifdef HasLCMS
+  char
+    lcms_vers[32];
+#endif
+
   Image
     * volatile imagev = imagep,  /* Use only 'imagev' before setjmp() */
     *image;                      /* Use only 'image' after setjmp() */
@@ -6248,6 +6612,44 @@ static MagickPassFail WriteOnePNGImage(M
   logging=LogMagickEvent(CoderEvent,GetMagickModule(),
                          "  enter WriteOnePNGImage()");
 
+  if (imagev == (Image *) NULL)
+    return(MagickFalse);
+
+  /* Define these outside of the following "if logging()" block so they will
+   * show in debuggers.
+   */
+    gm_vers=MagickLibVersionText;
+#ifdef HasLCMS
+    (void) sprintf(lcms_vers,"%.4d",LCMS_VERSION);
+#endif
+    libpng_runv=png_get_libpng_ver(NULL);
+    libpng_vers=PNG_LIBPNG_VER_STRING;
+    zlib_runv=zlib_version;
+    zlib_vers=ZLIB_VERSION;
+
+  if (logging != MagickFalse)
+    {
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    GM version     = %.31s", gm_vers);
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    Libpng version = %.31s", libpng_vers);
+       if (LocaleCompare(libpng_vers,libpng_runv) != 0)
+       {
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "      running with   %.31s", libpng_runv);
+       }
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    Zlib version   = %.31s", zlib_vers);
+       if (LocaleCompare(zlib_vers,zlib_runv) != 0)
+       {
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "      running with   %.31s", zlib_runv);
+       }
+#ifdef HasLCMS
+       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "    LCMS version   = %.31s", lcms_vers);
+#endif
+    }
   /* Initialize some stuff */
   ping_background.red = 0;
   ping_background.green = 0;
@@ -6651,6 +7053,9 @@ static MagickPassFail WriteOnePNGImage(M
               unsigned int
                 mask;
 
+              MagickBool
+                opaque = MagickTrue;
+
               mask=0xffff;
               if (ping_bit_depth == 8)
                 mask=0x00ff;
@@ -6673,14 +7078,16 @@ static MagickPassFail WriteOnePNGImage(M
                   for (x=(long) image->columns; x > 0; x--)
                     {
                       if (p->opacity != OpaqueOpacity)
-                        break;
+                        {
+                          opaque=MagickFalse;
+                          break;
+                        }
                       p++;
                     }
-                  if (p->opacity != OpaqueOpacity)
+                  if (!opaque)
                     break;
                 }
-              if ((p != (const PixelPacket *) NULL) &&
-                  (p->opacity != OpaqueOpacity))
+              if ((!opaque) && (p != (const PixelPacket *) NULL))
                 {
                   ping_trans_color.red=ScaleQuantumToShort(p->red)&mask;
                   ping_trans_color.green=ScaleQuantumToShort(p->green)
@@ -6739,7 +7146,7 @@ static MagickPassFail WriteOnePNGImage(M
                     }
                   if (x != 0)
                     break;
-                } 
+                }
               if (x != 0)
                 {
                   ping_valid_trns = 0;
@@ -6781,7 +7188,7 @@ static MagickPassFail WriteOnePNGImage(M
           if (image_depth > QuantumDepth)
             image_depth=QuantumDepth;
           if (image_colors == 0 || image_colors-1 > MaxRGB)
-            image_colors=1 << image_depth;
+            image_colors=1U << image_depth;
           if (image_depth > 8)
             ping_bit_depth=16;
           else
@@ -6789,7 +7196,7 @@ static MagickPassFail WriteOnePNGImage(M
               if (ping_colortype == PNG_COLOR_TYPE_PALETTE)
                 {
                   ping_bit_depth=1;
-                  while ((int) (1 << ping_bit_depth) <
+                  while ((int) (1U << ping_bit_depth) <
                                 (long) image_colors)
                     ping_bit_depth <<= 1;
                 }
@@ -6839,7 +7246,7 @@ static MagickPassFail WriteOnePNGImage(M
                     MagickFreeMemory(palette);
                   }
                 ping_bit_depth=1;
-                while ((1UL << ping_bit_depth) < number_colors)
+                while ((1U << ping_bit_depth) < number_colors)
                   ping_bit_depth <<= 1;
                 ping_num_trans=0;
                 if (matte)
@@ -6906,6 +7313,7 @@ static MagickPassFail WriteOnePNGImage(M
                          ping_valid_trns = 0;
                          png_set_invalid(ping, ping_info, PNG_INFO_PLTE);
                          mng_info->IsPalette=MagickFalse;
+                         image_matte=MagickTrue;
                          (void) SyncImage(image);
                          if (logging)
                            (void) LogMagickEvent(CoderEvent,
@@ -6942,12 +7350,14 @@ static MagickPassFail WriteOnePNGImage(M
                           png_error(ping, "Could not allocate trans_alpha");
 
                         for (i=0; i<(int) number_colors; i++)
-                          if (trans_alpha[i] == 256)
-                             ping_trans_alpha[i]=255;
-                          else
-                             ping_trans_alpha[i]=(png_byte) trans_alpha[i];
-                         (void) LogMagickEvent(CoderEvent, GetMagickModule(),
-                            "    Alpha[%d]=%d",(int) i, (int) trans_alpha[i]);
+                          {
+                            if (trans_alpha[i] == 256)
+                               ping_trans_alpha[i]=255;
+                            else
+                               ping_trans_alpha[i]=(png_byte) trans_alpha[i];
+                           (void) LogMagickEvent(CoderEvent, GetMagickModule(),
+                              "    Alpha[%d]=%d",(int) i, (int) trans_alpha[i]);
+                          }
                       }
                   }
 
@@ -6984,7 +7394,7 @@ static MagickPassFail WriteOnePNGImage(M
           png_uint_16
             maxval;
 
-          maxval=(1 << ping_bit_depth)-1;
+          maxval=(1U << ping_bit_depth)-1;
 
           ping_trans_color.gray=(png_uint_16)(maxval*
                                 ping_trans_color.gray/
@@ -7120,7 +7530,7 @@ static MagickPassFail WriteOnePNGImage(M
           png_color_16
             background;
 
-          maxval=(1 << ping_bit_depth)-1;
+          maxval=(1U << ping_bit_depth)-1;
 
 
           background.gray=(png_uint_16)
@@ -7139,7 +7549,7 @@ static MagickPassFail WriteOnePNGImage(M
               int
                 maxval;
 
-              maxval=(1 << image_depth)-1;
+              maxval=(1U << image_depth)-1;
               background.red=(png_uint_16)
                 (maxval*image->background_color.red/MaxRGB);
               background.green=(png_uint_16)
@@ -7211,11 +7621,16 @@ static MagickPassFail WriteOnePNGImage(M
 #if defined(PNG_oFFs_SUPPORTED)
   if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
     {
-      png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
+      if (!((image->page.width != 0 && image->page.width != image->columns) ||
+          (image->page.height != 0 && image->page.height != image->rows)))
+        {
+          png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
                    (png_int_32) image->page.y, 0);
-      if (logging)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          if (logging)
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                               "    Setting up oFFs chunk");
+        }
+      /* else write caNv instead, later */
     }
 #endif
 
@@ -7282,6 +7697,9 @@ static MagickPassFail WriteOnePNGImage(M
                                       profile_info,
                                       (png_uint_32) profile_length);
               }
+            else if (LocaleCompare(profile_name,"exif") == 0)
+              /* Do not write exif; we'll write it later as eXIf */
+              ;
             else
               {
                 if (logging)
@@ -7318,7 +7736,7 @@ static MagickPassFail WriteOnePNGImage(M
         (void) png_set_sRGB(ping,ping_info,PerceptualIntent);
       png_set_gAMA(ping,ping_info,0.45455);
     }
-  if ((!mng_info->write_mng) || 
+  if ((!mng_info->write_mng) ||
        !png_get_valid(ping, ping_info, PNG_INFO_sRGB))
 #endif
     {
@@ -7361,6 +7779,38 @@ static MagickPassFail WriteOnePNGImage(M
 
   png_write_info(ping,ping_info);
 
+  /* write orNT if image->orientation is defined and not TopLeft */
+  if (image->orientation > 1 && image->orientation < 9)
+    {
+      unsigned char
+        chunk[6];
+      (void) WriteBlobMSBULong(image,1L);  /* data length=1 */
+      PNGType(chunk,mng_orNT);
+      LogPNGChunk(logging,mng_orNT,1L);
+      chunk[4]=image->orientation;
+      (void) WriteBlob(image,5,chunk);
+      (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
+    }
+
+  /* write caNv chunk */
+  if ((image->page.width != 0 && image->page.width != image->columns) ||
+      (image->page.height != 0 && image->page.height != image->rows) ||
+      image->page.x != 0 || image->page.y != 0)
+    {
+      unsigned char
+        chunk[22];
+
+      (void) WriteBlobMSBULong(image,16L);  /* data length=16 */
+      PNGType(chunk,mng_caNv);
+      LogPNGChunk(logging,mng_caNv,16L);
+      PNGLong(chunk+4,(png_uint_32) image->page.width);
+      PNGLong(chunk+8,(png_uint_32) image->page.height);
+      PNGsLong(chunk+12,(png_int_32) image->page.x);
+      PNGsLong(chunk+16,(png_int_32) image->page.y);
+      (void) WriteBlob(image,20,chunk);
+      (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
+    }
+
 #if (PNG_LIBPNG_VER == 10206)
   /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
 #define PNG_HAVE_IDAT               0x04
@@ -7372,6 +7822,17 @@ static MagickPassFail WriteOnePNGImage(M
   /*
     Allocate memory.
   */
+  if (logging)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "  mng_info: columns=%lu, image_depth=%u, "
+                          "write_png8=%u, write_png24=%u, write_png32=%u "
+                          "write_png48=%u, write_png64=%u, IsPalette=%u, "
+                          "image_matte=%u",
+                          image->columns, image_depth, mng_info->write_png8,
+                          mng_info->write_png24, mng_info->write_png32,
+                          mng_info->write_png48, mng_info->write_png64,
+                          mng_info->IsPalette, image_matte
+                          );
   rowbytes=image->columns;
   if (image_depth <= 8)
     {
@@ -7451,7 +7912,7 @@ static MagickPassFail WriteOnePNGImage(M
                                             &image->exception,
                                             SaveImageTag,
                                             image->filename,
-					    image->columns,image->rows))
+                                            image->columns,image->rows))
                   break;
 
           }
@@ -7509,7 +7970,7 @@ static MagickPassFail WriteOnePNGImage(M
                                                 num_passes,
                                                 &image->exception,SaveImageTag,
                                                 image->filename,
-					        image->columns,image->rows))
+                                                image->columns,image->rows))
                       break;
               }
           }
@@ -7576,7 +8037,7 @@ static MagickPassFail WriteOnePNGImage(M
                                                     &image->exception,
                                                     SaveImageTag,
                                                     image->filename,
-						    image->columns,image->rows))
+                                                    image->columns,image->rows))
                           break;
                     }
                   if (logging)
@@ -7622,7 +8083,7 @@ static MagickPassFail WriteOnePNGImage(M
                                                       &image->exception,
                                                       SaveImageTag,
                                                       image->filename,
-						      image->columns,
+                                                      image->columns,
                                                       image->rows))
                             break;
                     }
@@ -7661,10 +8122,10 @@ static MagickPassFail WriteOnePNGImage(M
         text;
 
       if (*attribute->key == '[')
-        continue; 
+        continue;
       if (LocaleCompare(attribute->key,"png:IHDR.color-type-orig") == 0 ||
           LocaleCompare(attribute->key,"png:IHDR.bit-depth-orig") == 0)
-        continue; 
+        continue;
 #if PNG_LIBPNG_VER >= 14000
             text=(png_textp) png_malloc(ping,
                  (png_alloc_size_t) sizeof(png_text));
@@ -7687,6 +8148,64 @@ static MagickPassFail WriteOnePNGImage(M
       png_set_text(ping,ping_info,text,1);
       png_free(ping,text);
     }
+
+  /* write eXIf profile */
+  {
+    ImageProfileIterator
+      *profile_iterator;
+
+    profile_iterator=AllocateImageProfileIterator(image);
+    if (profile_iterator)
+      {
+        const char
+          *profile_name;
+
+        const unsigned char
+          *profile_info;
+
+        size_t
+          profile_length;
+
+        while (NextImageProfile(profile_iterator,&profile_name,&profile_info,
+                                &profile_length) != MagickFail)
+          {
+            if (LocaleCompare(profile_name,"exif") == 0)
+              {
+                png_uint_32
+                  length;
+                unsigned char
+                  chunk[4];
+                const unsigned char
+                  *data;
+
+                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                   "  Have eXIf profile");
+
+                data=profile_info;
+
+                length=(png_uint_32) profile_length;
+
+                PNGType(chunk,mng_eXIf);
+
+                if (length < 7)
+                  break;  /* othewise crashes */
+
+                /* skip the "Exif\0\0" JFIF Exif Header ID */
+                length -= 6;
+
+                LogPNGChunk(logging,chunk,length);
+                (void) WriteBlobMSBULong(image,length);
+                (void) WriteBlob(image,4,chunk);
+                (void) WriteBlob(image,length,data+6);
+                (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),
+                  data+6, (uInt) length));
+                break;
+              }
+          }
+        DeallocateImageProfileIterator(profile_iterator);
+      }
+    }
+
   if (logging)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                           "  Writing PNG end info");
@@ -7810,7 +8329,7 @@ static MagickPassFail WriteOnePNGImage(M
 %    o PNG32: An 8-bit per sample RGBA PNG is written.  Partial
 %             transparency is permitted, i.e., the alpha sample for
 %             each pixel can have any value from 0 to 255. The alpha
-%             channel is present even if the image is fully opaque. 
+%             channel is present even if the image is fully opaque.
 %
 %    o PNG48:   A 16-bit per sample RGB PNG datastream is written.  The tRNS
 %               chunk can be present to convey binary transparency by naming
@@ -8346,10 +8865,7 @@ static MagickPassFail WriteOneJNGImage(M
           p=(unsigned char *) (blob+8);
           for (i=8; i<(long) length; i+=len+12)
             {
-              len=((*(p    ) & 0xff) << 24) +
-                  ((*(p + 1) & 0xff) << 16) +
-                  ((*(p + 2) & 0xff) <<  8) +
-                  ((*(p + 3) & 0xff)      ) ;
+              len=mng_get_long(p);
               p+=4;
               if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84)
                 {
openSUSE Build Service is sponsored by