]> granicus.if.org Git - imagemagick/commitdiff
* Renamed read_vpag_chunk_callback() function to png_user_chunk_callback()
authorGlenn Randers-Pehrson <glennrp@gmail.com>
Sun, 22 Jan 2017 17:58:11 +0000 (12:58 -0500)
committerGlenn Randers-Pehrson <glennrp@gmail.com>
Sun, 22 Jan 2017 17:58:11 +0000 (12:58 -0500)
  in coders/png.c
* Implemented a private PNG caNv (canvas) chunk for remembering the
  original dimensions and offsets when an image is cropped.  Previously
  we used the oFFs and vpAg chunks for this purpose, but this had potential
  conflicts with other applications that also use the oFFs chunk.

ChangeLog
coders/png.c

index bd70aa8d4dc6fe61382b2c6c4313eb3b07bf314a..085f76b85bf3038e90107f3b4ca567cdb9c2cdb5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2017-01-22  7.0.4-6 Glenn Randers-Pehrson <glennrp@image...>
+  * Renamed read_vpag_chunk_callback() function to png_user_chunk_callback()
+    in coders/png.c
+  * Implemented a private PNG caNv (canvas) chunk for remembering the
+    original dimensions and offsets when an image is cropped.  Previously
+    we used the oFFs and vpAg chunks for this purpose, but this had potential
+    conflicts with other applications that also use the oFFs chunk.
+
 2017-01-22  7.0.4-6 Dirk Lemstra <dirk@lem.....org>
   * Replaced CoderSeekableStreamFlag with CoderDecoderSeekableStreamFlag and
     CoderEncoderSeekableStreamFlag.
index 2d8b7f4e0472523253e6f93afed2f7260a269eb9..8fc7d581c4c1a143846751b56d2c624c9da6320f 100644 (file)
@@ -549,6 +549,7 @@ static const png_byte mng_SEEK[5]={ 83,  69,  69,  75, (png_byte) '\0'};
 static const png_byte mng_SHOW[5]={ 83,  72,  79,  87, (png_byte) '\0'};
 static const png_byte mng_TERM[5]={ 84,  69,  82,  77, (png_byte) '\0'};
 static const png_byte mng_bKGD[5]={ 98,  75,  71,  68, (png_byte) '\0'};
+static const png_byte mng_caNv[5]={ 99,  97,  78, 118, (png_byte) '\0'};
 static const png_byte mng_cHRM[5]={ 99,  72,  82,  77, (png_byte) '\0'};
 static const png_byte mng_gAMA[5]={103,  65,  77,  65, (png_byte) '\0'};
 static const png_byte mng_iCCP[5]={105,  67,  67,  80, (png_byte) '\0'};
@@ -811,6 +812,7 @@ typedef struct _MngInfo
     ping_exclude_tEXt,
     ping_exclude_tRNS,
     ping_exclude_vpAg,
+    ping_exclude_caNv,
     ping_exclude_zCCP, /* hex-encoded iCCP */
     ping_exclude_zTXt,
     ping_preserve_colormap,
@@ -1806,7 +1808,7 @@ Magick_png_read_raw_profile(png_struct *ping,Image *image,
 }
 
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
-static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
+static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
 {
   Image
     *image;
@@ -1821,36 +1823,68 @@ static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
   */
 
   LogMagickEvent(CoderEvent,GetMagickModule(),
-     " read_vpag_chunk: found %c%c%c%c chunk",
+     "    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] != 118 || chunk->name[1] != 112 ||
-      chunk->name[2] != 65 ||chunk-> name[3] != 103)
-    return(0); /* Did not recognize */
+  /* vpAg (deprecated, replaced by caNv) */
+  if (chunk->name[0] == 118 &&
+      chunk->name[1] == 112 &&
+      chunk->name[2] ==  65 &&
+      chunk->name[3] == 103)
+    {
+     /* recognized vpAg */
+
+     if (chunk->size != 9)
+       return(-1); /* Error return */
+
+     if (chunk->data[8] != 0)
+       return(0);  /* ImageMagick requires pixel units */
+
+     image=(Image *) png_get_user_chunk_ptr(ping);
+
+     image->page.width=(size_t) ((chunk->data[0] << 24) |
+        (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
 
-  /* recognized vpAg */
+     image->page.height=(size_t) ((chunk->data[4] << 24) |
+        (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
+
+     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 != 9)
-    return(-1); /* Error return */
+     if (chunk->size != 16)
+       return(-1); /* Error return */
 
-  if (chunk->data[8] != 0)
-    return(0);  /* ImageMagick requires pixel units */
+     image=(Image *) png_get_user_chunk_ptr(ping);
 
-  image=(Image *) png_get_user_chunk_ptr(ping);
+     image->page.width=(size_t) ((chunk->data[0] << 24) |
+        (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
 
-  image->page.width=(size_t) ((chunk->data[0] << 24) |
-     (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
+     image->page.height=(size_t) ((chunk->data[4] << 24) |
+        (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
 
-  image->page.height=(size_t) ((chunk->data[4] << 24) |
-     (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
+     image->page.x=(size_t) ((chunk->data[8] << 24) |
+        (chunk->data[9] << 16) | (chunk->data[10] << 8) | chunk->data[11]);
 
-  /* Return one of the following: */
-     /* return(-n);  chunk had an error */
-     /* return(0);  did not recognize */
-     /* return(n);  success */
+     image->page.y=(size_t) ((chunk->data[12] << 24) |
+        (chunk->data[13] << 16) | (chunk->data[14] << 8) | chunk->data[15]);
 
-  return(1);
+     /* Return one of the following: */
+        /* return(-n);  chunk had an error */
+        /* return(0);  did not recognize */
+        /* return(n);  success */
 
+     return(1);
+    }
+
+  return(0); /* Did not recognize */
 }
 #endif
 
@@ -2263,22 +2297,23 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
     else
     {
-       png_set_keep_unknown_chunks(ping, 1, mng_iCCP, 1);
+       png_set_keep_unknown_chunks(ping, 1, (png_bytep) mng_iCCP, 1);
     }
 #endif
   }
 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
-  /* Ignore unused chunks and all unknown chunks except for vpAg */
-#if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */
+  /* Ignore unused chunks and all unknown chunks except for caNv and vpAg */
+# if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */
   png_set_keep_unknown_chunks(ping, 2, NULL, 0);
-#else
+# else
   png_set_keep_unknown_chunks(ping, 1, NULL, 0);
-#endif
-  png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
+# endif
+  png_set_keep_unknown_chunks(ping, 2, (png_bytep) mng_caNv, 1);
+  png_set_keep_unknown_chunks(ping, 2, (png_bytep) mng_vpAg, 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_vpag_chunk_callback);
+  png_set_read_user_chunk_fn(ping, image, read_user_chunk_callback);
 #endif
 
 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
@@ -3823,6 +3858,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                 exception);
        }
 
+     /* cHRM chunk: */
      if (ping_found_cHRM != MagickFalse)
        {
          (void) FormatLocaleString(msg,MagickPathExtent,"%s",
@@ -3831,6 +3867,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                 exception);
        }
 
+     /* bKGD chunk: */
      if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
        {
          (void) FormatLocaleString(msg,MagickPathExtent,"%s",
@@ -3843,6 +3880,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
         "chunk was found");
 
 #if defined(PNG_iCCP_SUPPORTED)
+     /* iCCP chunk: */
      if (ping_found_iCCP != MagickFalse)
         (void) SetImageProperty(image,"png:iCCP",msg,
                 exception);
@@ -3853,6 +3891,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
                 exception);
 
 #if defined(PNG_sRGB_SUPPORTED)
+     /* sRGB chunk: */
      if (ping_found_sRGB != MagickFalse)
        {
          (void) FormatLocaleString(msg,MagickPathExtent,
@@ -3864,6 +3903,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
        }
 #endif
 
+     /* gAMA chunk: */
      if (ping_found_gAMA != MagickFalse)
        {
          (void) FormatLocaleString(msg,MagickPathExtent,
@@ -3874,6 +3914,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
        }
 
 #if defined(PNG_pHYs_SUPPORTED)
+     /* pHYs chunk: */
      if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
        {
          (void) FormatLocaleString(msg,MagickPathExtent,
@@ -3885,6 +3926,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
 #endif
 
 #if defined(PNG_oFFs_SUPPORTED)
+     /* oFFs chunk: */
      if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
        {
          (void) FormatLocaleString(msg,MagickPathExtent,"x_off=%.20g, y_off=%.20g",
@@ -3898,6 +3940,20 @@ static Image *ReadOnePNGImage(MngInfo *mng_info,
      read_tIME_chunk(image,ping,end_info,exception);
 #endif
 
+     /* 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))
+       {
+         (void) FormatLocaleString(msg,MagickPathExtent,
+            "width=%.20g, height=%.20g, x_offset=%.20g, y_offset=%.20g",
+            (double) image->page.width,(double) image->page.height,
+            (double) image->page.x,(double) image->page.y);
+         (void) SetImageProperty(image,"png:caNv",msg,
+                exception);
+       }
+
+     /* vpAg chunk: */
      if ((image->page.width != 0 && image->page.width != image->columns) ||
          (image->page.height != 0 && image->page.height != image->rows))
        {
@@ -7414,7 +7470,7 @@ ModuleExport size_t RegisterPNGImage(void)
 #endif
 
   entry=AcquireMagickInfo("PNG","MNG","Multiple-image Network Graphics");
-  entry->flags|=CoderDecoderSeekableStreamFlag;  /* To do: eliminate this. */
+  entry->flags|=CoderSeekableStreamFlag;  /* To do: eliminate this. */
 
 #if defined(MAGICKCORE_PNG_DELEGATE)
   entry->decoder=(DecodeImageHandler *) ReadMNGImage;
@@ -7906,7 +7962,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
 
   int
     num_passes,
-    pass;
+    pass,
+    ping_wrote_caNv;
 
   png_byte
      ping_trans_alpha[256];
@@ -7961,6 +8018,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
     ping_exclude_tIME,
     /* ping_exclude_tRNS, */
     ping_exclude_vpAg,
+    ping_exclude_caNv,
     ping_exclude_zCCP, /* hex-encoded iCCP */
     ping_exclude_zTXt,
 
@@ -8105,6 +8163,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   ping_have_tRNS=MagickFalse;
 
   ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
+  ping_exclude_caNv=mng_info->ping_exclude_caNv;
   ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
   ping_exclude_date=mng_info->ping_exclude_date;
   /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
@@ -10708,22 +10767,6 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
         }
     }
 
-#if defined(PNG_oFFs_SUPPORTED)
-  if (ping_exclude_oFFs == MagickFalse)
-    {
-      if (image->page.x || image->page.y)
-        {
-           png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
-              (png_int_32) image->page.y, 0);
-
-           if (logging != MagickFalse)
-             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                 "    Setting up oFFs chunk with x=%d, y=%d, units=0",
-                 (int) image->page.x, (int) image->page.y);
-        }
-    }
-#endif
-
 #if defined(PNG_tIME_SUPPORTED)
   if (ping_exclude_tIME == MagickFalse)
     {
@@ -10802,7 +10845,49 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
   /* write any PNG-chunk-m profiles */
   (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
 
-  if (ping_exclude_vpAg == MagickFalse)
+  ping_wrote_caNv = MagickFalse;
+
+  /* write caNv chunk */
+  if (ping_exclude_caNv == MagickFalse)
+    {
+      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[20];
+
+          (void) WriteBlobMSBULong(image,16L);  /* data length=8 */
+          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));
+          ping_wrote_caNv = MagickTrue;
+        }
+    }
+
+#if defined(PNG_oFFs_SUPPORTED)
+  if (ping_exclude_oFFs == MagickFalse && ping_wrote_caNv == MagickFalse)
+    {
+      if (image->page.x || image->page.y)
+        {
+           png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
+              (png_int_32) image->page.y, 0);
+
+           if (logging != MagickFalse)
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                 "    Setting up oFFs chunk with x=%d, y=%d, units=0",
+                 (int) image->page.x, (int) image->page.y);
+        }
+    }
+#endif
+
+  /* write vpAg chunk (deprecated, replaced by caNv) */
+  if (ping_exclude_vpAg == MagickFalse && ping_wrote_caNv == MagickFalse)
     {
       if ((image->page.width != 0 && image->page.width != image->columns) ||
           (image->page.height != 0 && image->page.height != image->rows))
@@ -11809,6 +11894,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
    */
 
   mng_info->ping_exclude_bKGD=MagickFalse;
+  mng_info->ping_exclude_caNv=MagickFalse;
   mng_info->ping_exclude_cHRM=MagickFalse;
   mng_info->ping_exclude_date=MagickFalse;
   mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
@@ -12016,6 +12102,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
     if (IsOptionMember("all",value) != MagickFalse)
       {
         mng_info->ping_exclude_bKGD=excluding;
+        mng_info->ping_exclude_caNv=excluding;
         mng_info->ping_exclude_cHRM=excluding;
         mng_info->ping_exclude_date=excluding;
         mng_info->ping_exclude_EXIF=excluding;
@@ -12037,6 +12124,8 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
       {
         mng_info->ping_exclude_bKGD=excluding != MagickFalse ? MagickFalse :
           MagickTrue;
+        mng_info->ping_exclude_caNv=excluding != MagickFalse ? MagickFalse :
+          MagickTrue;
         mng_info->ping_exclude_cHRM=excluding != MagickFalse ? MagickFalse :
           MagickTrue;
         mng_info->ping_exclude_date=excluding != MagickFalse ? MagickFalse :
@@ -12071,6 +12160,9 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
     if (IsOptionMember("bkgd",value) != MagickFalse)
       mng_info->ping_exclude_bKGD=excluding;
 
+    if (IsOptionMember("caNv",value) != MagickFalse)
+      mng_info->ping_exclude_caNv=excluding;
+
     if (IsOptionMember("chrm",value) != MagickFalse)
       mng_info->ping_exclude_cHRM=excluding;
 
@@ -12126,6 +12218,9 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
     if (mng_info->ping_exclude_bKGD != MagickFalse)
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "    bKGD");
+    if (mng_info->ping_exclude_caNv != MagickFalse)
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    caNv");
     if (mng_info->ping_exclude_cHRM != MagickFalse)
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "    cHRM");
@@ -13652,6 +13747,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
 
        /* We don't want any ancillary chunks written */
        mng_info->ping_exclude_bKGD=MagickTrue;
+       mng_info->ping_exclude_caNv=MagickTrue;
        mng_info->ping_exclude_cHRM=MagickTrue;
        mng_info->ping_exclude_date=MagickTrue;
        mng_info->ping_exclude_EXIF=MagickTrue;