[gimp] Bug 770853 - Opening and overwriting a linear gamma png produces wrong colors



commit e404e6ba93ca70183d9f063b5eb2d1543c956e9b
Author: Michael Natterer <mitch gimp org>
Date:   Sun Sep 4 22:12:30 2016 +0200

    Bug 770853 - Opening and overwriting a linear gamma png produces wrong colors
    
    Add support for writing linear PNGs. But only if we also save a color
    profile, otherwise we would get loaders confused. Please test, I might
    have a knot in my brain...
    
    Also clean up some formatting and fix compile warnings, now let's wait
    for bugs about shit libpng versions which break the build.

 plug-ins/common/file-png.c |  232 ++++++++++++++++++++++++++++----------------
 1 files changed, 150 insertions(+), 82 deletions(-)
---
diff --git a/plug-ins/common/file-png.c b/plug-ins/common/file-png.c
index 70d6eaa..fd04a7f 100644
--- a/plug-ins/common/file-png.c
+++ b/plug-ins/common/file-png.c
@@ -794,7 +794,7 @@ load_color_profile (png_structp   pp,
 #if defined(PNG_iCCP_SUPPORTED)
   png_uint_32       proflen;
   png_charp         profname;
-  png_charp         prof;
+  png_bytep         prof;
   int               profcomp;
 
   if (png_get_iCCP (pp, info, &profname, &profcomp, &prof, &proflen))
@@ -1426,49 +1426,83 @@ save_image (const gchar  *filename,
             gint32        orig_image_ID,
             GError      **error)
 {
-  gint i, k,                    /* Looping vars */
-    bpp = 0,                    /* Bytes per pixel */
-    type,                       /* Type of drawable/layer */
-    num_passes,                 /* Number of interlace passes in file */
-    pass,                       /* Current pass in file */
-    tile_height,                /* Height of tile in GIMP */
-    width,                      /* image width */
-    height,                     /* image height */
-    begin,                      /* Beginning tile row */
-    end,                        /* Ending tile row */
-    num;                        /* Number of rows to load */
-  FILE *fp;                     /* File pointer */
-  GeglBuffer *buffer;           /* GEGL buffer for layer */
-  const Babl *file_format;      /* BABL format of file */
-  png_structp pp;               /* PNG read pointer */
-  png_infop info;               /* PNG info pointer */
-  gint offx, offy;              /* Drawable offsets from origin */
-  guchar **pixels,              /* Pixel rows */
-   *fixed,                      /* Fixed-up pixel data */
-   *pixel;                      /* Pixel data */
-  gdouble xres, yres;           /* GIMP resolution (dpi) */
-  png_color_16 background;      /* Background color */
-  png_time mod_time;            /* Modification time (ie NOW) */
-  time_t cutime;                /* Time since epoch */
-  struct tm *gmt;               /* GMT broken down */
-  int color_type;
-  int bit_depth;
-
-  guchar remap[256];            /* Re-mapping for the palette */
-
-  png_textp  text = NULL;
-
-  if (gimp_image_get_precision (image_ID) == GIMP_PRECISION_U8_GAMMA)
-    bit_depth = 8;
-  else
-    bit_depth = 16;
+  gint              i, k;             /* Looping vars */
+  gint              bpp = 0;          /* Bytes per pixel */
+  gint              type;             /* Type of drawable/layer */
+  gint              num_passes;       /* Number of interlace passes in file */
+  gint              pass;             /* Current pass in file */
+  gint              tile_height;      /* Height of tile in GIMP */
+  gint              width;            /* image width */
+  gint              height;           /* image height */
+  gint              begin;            /* Beginning tile row */
+  gint              end;              /* Ending tile row */
+  gint              num;              /* Number of rows to load */
+  FILE             *fp;               /* File pointer */
+  GimpColorProfile *profile = NULL;   /* Color profile */
+  gboolean          linear;           /* Save linear RGB */
+  GeglBuffer       *buffer;           /* GEGL buffer for layer */
+  const Babl       *file_format;      /* BABL format of file */
+  png_structp       pp;               /* PNG read pointer */
+  png_infop         info;             /* PNG info pointer */
+  gint              offx, offy;       /* Drawable offsets from origin */
+  guchar          **pixels;           /* Pixel rows */
+  guchar           *fixed;            /* Fixed-up pixel data */
+  guchar           *pixel;            /* Pixel data */
+  gdouble           xres, yres;       /* GIMP resolution (dpi) */
+  png_color_16      background;       /* Background color */
+  png_time          mod_time;         /* Modification time (ie NOW) */
+  time_t            cutime;           /* Time since epoch */
+  struct tm        *gmt;              /* GMT broken down */
+  gint              color_type;       /* PNG color type */
+  gint              bit_depth = 16;   /* Default to bit bepth 16 */
+
+  guchar            remap[256];       /* Re-mapping for the palette */
+
+  png_textp         text = NULL;
+
+#if defined(PNG_iCCP_SUPPORTED)
+  profile = gimp_image_get_color_profile (orig_image_ID);
+#endif
+
+  switch (gimp_image_get_precision (image_ID))
+    {
+    case GIMP_PRECISION_U8_LINEAR:
+      /* only keep 8 bit linear RGB if we also save a profile */
+      if (profile)
+        bit_depth = 8;
+
+    case GIMP_PRECISION_U16_LINEAR:
+    case GIMP_PRECISION_U32_LINEAR:
+    case GIMP_PRECISION_HALF_LINEAR:
+    case GIMP_PRECISION_FLOAT_LINEAR:
+    case GIMP_PRECISION_DOUBLE_LINEAR:
+      /* save linear RGB only if we save a profile, or a loader won't
+       * do the right thing
+       */
+      if (profile)
+        linear = TRUE;
+      else
+        linear = FALSE;
+      break;
+
+    case GIMP_PRECISION_U8_GAMMA:
+      bit_depth = 8;
+
+    case GIMP_PRECISION_U16_GAMMA:
+    case GIMP_PRECISION_U32_GAMMA:
+    case GIMP_PRECISION_HALF_GAMMA:
+    case GIMP_PRECISION_FLOAT_GAMMA:
+    case GIMP_PRECISION_DOUBLE_GAMMA:
+      linear = FALSE;
+      break;
+    }
 
   pp = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   if (!pp)
     {
       /* this could happen if the compile time and run-time libpng
-         versions do not match. */
-
+       * versions do not match.
+       */
       g_set_error (error, 0, 0,
                    _("Error creating PNG write struct while exporting '%s'."),
                    gimp_filename_to_utf8 (filename));
@@ -1513,9 +1547,9 @@ save_image (const gchar  *filename,
    */
 
   buffer = gimp_drawable_get_buffer (drawable_ID);
-  width = gegl_buffer_get_width (buffer);
+  width  = gegl_buffer_get_width (buffer);
   height = gegl_buffer_get_height (buffer);
-  type = gimp_drawable_type (drawable_ID);
+  type   = gimp_drawable_type (drawable_ID);
 
   /*
    * Initialise remap[]
@@ -1532,33 +1566,73 @@ save_image (const gchar  *filename,
     case GIMP_RGB_IMAGE:
       color_type = PNG_COLOR_TYPE_RGB;
       if (bit_depth == 8)
-        file_format = babl_format ("R'G'B' u8");
+        {
+          if (linear)
+            file_format = babl_format ("RGB u8");
+          else
+            file_format = babl_format ("R'G'B' u8");
+        }
       else
-        file_format = babl_format ("R'G'B' u16");
+        {
+          if (linear)
+            file_format = babl_format ("RGB u16");
+          else
+            file_format = babl_format ("R'G'B' u16");
+        }
       break;
 
     case GIMP_RGBA_IMAGE:
       color_type = PNG_COLOR_TYPE_RGB_ALPHA;
       if (bit_depth == 8)
-        file_format = babl_format ("R'G'B'A u8");
+        {
+          if (linear)
+            file_format = babl_format ("RGBA u8");
+          else
+            file_format = babl_format ("R'G'B'A u8");
+        }
       else
-        file_format = babl_format ("R'G'B'A u16");
+        {
+          if (linear)
+            file_format = babl_format ("RGBA u16");
+          else
+            file_format = babl_format ("R'G'B'A u16");
+        }
       break;
 
     case GIMP_GRAY_IMAGE:
       color_type = PNG_COLOR_TYPE_GRAY;
       if (bit_depth == 8)
-        file_format = babl_format ("Y' u8");
+        {
+          if (linear)
+            file_format = babl_format ("Y u8");
+          else
+            file_format = babl_format ("Y' u8");
+        }
       else
-        file_format = babl_format ("Y' u16");
+        {
+          if (linear)
+            file_format = babl_format ("Y u16");
+          else
+            file_format = babl_format ("Y' u16");
+        }
       break;
 
     case GIMP_GRAYA_IMAGE:
       color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
       if (bit_depth == 8)
-        file_format = babl_format ("Y'A u8");
+        {
+          if (linear)
+            file_format = babl_format ("YA u8");
+          else
+            file_format = babl_format ("Y'A u8");
+        }
       else
-        file_format = babl_format ("Y'A u16");
+        {
+          if (linear)
+            file_format = babl_format ("YA u16");
+          else
+            file_format = babl_format ("Y'A u16");
+        }
       break;
 
     case GIMP_INDEXED_IMAGE:
@@ -1664,39 +1738,33 @@ save_image (const gchar  *filename,
     }
 
 #if defined(PNG_iCCP_SUPPORTED)
-  {
-    GimpColorProfile *profile;
-
-    profile = gimp_image_get_color_profile (orig_image_ID);
-
-    if (profile)
-      {
-        GimpParasite *parasite;
-        gchar        *profile_name = NULL;
-        const guint8 *icc_data;
-        gsize         icc_length;
-
-        icc_data = gimp_color_profile_get_icc_profile (profile, &icc_length);
-
-        parasite = gimp_image_get_parasite (orig_image_ID,
-                                            "icc-profile-name");
-        if (parasite)
-          profile_name = g_convert (gimp_parasite_data (parasite),
-                                    gimp_parasite_data_size (parasite),
-                                    "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
-
-        png_set_iCCP (pp,
-                      info,
-                      profile_name ? profile_name : "ICC profile",
-                      0,
-                      (png_charp) icc_data,
-                      icc_length);
-
-        g_free (profile_name);
-
-        g_object_unref (profile);
-      }
-  }
+  if (profile)
+    {
+      GimpParasite *parasite;
+      gchar        *profile_name = NULL;
+      const guint8 *icc_data;
+      gsize         icc_length;
+
+      icc_data = gimp_color_profile_get_icc_profile (profile, &icc_length);
+
+      parasite = gimp_image_get_parasite (orig_image_ID,
+                                          "icc-profile-name");
+      if (parasite)
+        profile_name = g_convert (gimp_parasite_data (parasite),
+                                  gimp_parasite_data_size (parasite),
+                                  "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
+
+      png_set_iCCP (pp,
+                    info,
+                    profile_name ? profile_name : "ICC profile",
+                    0,
+                    icc_data,
+                    icc_length);
+
+      g_free (profile_name);
+
+      g_object_unref (profile);
+    }
 #endif
 
 #ifdef PNG_zTXt_SUPPORTED


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]