[gimp] Bug 478528 - Layer and Image previews are not color managed



commit 9e8499bb48c8ceda5864e0b877ffb7a43a22d605
Author: Michael Natterer <mitch gimp org>
Date:   Fri Apr 15 16:52:25 2016 +0100

    Bug 478528 - Layer and Image previews are not color managed
    
    Change gimp_viewable_get_[new]_preview() to return buffers of the
    image's and layers' colorspace, but in u8. This way layer and image
    previews can transform them correctly to the display profile.
    
    Note: this makes plug-ins receive thumbnail buffers in that
    pixel format too.
    
    Also change gimp_viewable_get_[new]_pixbuf() to always return sRGB
    buffers that can reasonably be put to screen directly, or put into DND
    buffers. This is at least more correct now.

 app/core/gimpdrawable-preview.c |  149 +++++++++++++++++++++++++++++++++++++--
 app/core/gimpdrawable-preview.h |   14 ++++-
 app/core/gimpdrawable.c         |    1 +
 app/core/gimpimage-preview.c    |   83 +++++++++++++++++++++-
 app/core/gimpimage-preview.h    |    4 +
 app/core/gimpimage.c            |    1 +
 6 files changed, 244 insertions(+), 8 deletions(-)
---
diff --git a/app/core/gimpdrawable-preview.c b/app/core/gimpdrawable-preview.c
index c4647c8..6e1ce74 100644
--- a/app/core/gimpdrawable-preview.c
+++ b/app/core/gimpdrawable-preview.c
@@ -19,18 +19,24 @@
 
 #include <string.h>
 
+#include <cairo.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gegl.h>
 
+#include "libgimpcolor/gimpcolor.h"
 #include "libgimpmath/gimpmath.h"
 
 #include "core-types.h"
 
 #include "config/gimpcoreconfig.h"
 
+#include "gegl/gimp-babl.h"
+#include "gegl/gimp-gegl-loops.h"
+
 #include "gimp.h"
 #include "gimpchannel.h"
 #include "gimpimage.h"
+#include "gimpimage-color-profile.h"
 #include "gimpdrawable-preview.h"
 #include "gimpdrawable-private.h"
 #include "gimplayer.h"
@@ -59,22 +65,53 @@ gimp_drawable_get_new_preview (GimpViewable *viewable,
                                         height);
 }
 
+GdkPixbuf *
+gimp_drawable_get_new_pixbuf (GimpViewable *viewable,
+                              GimpContext  *context,
+                              gint          width,
+                              gint          height)
+{
+  GimpItem  *item  = GIMP_ITEM (viewable);
+  GimpImage *image = gimp_item_get_image (item);
+
+  if (! image->gimp->config->layer_previews)
+    return NULL;
+
+  return gimp_drawable_get_sub_pixbuf (GIMP_DRAWABLE (viewable),
+                                       0, 0,
+                                       gimp_item_get_width  (item),
+                                       gimp_item_get_height (item),
+                                       width,
+                                       height);
+}
+
 const Babl *
 gimp_drawable_get_preview_format (GimpDrawable *drawable)
 {
+  gboolean alpha;
+  gboolean linear;
+
   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
 
+  alpha  = gimp_drawable_has_alpha (drawable);
+  linear = gimp_drawable_get_linear (drawable);
+
   switch (gimp_drawable_get_base_type (drawable))
     {
     case GIMP_GRAY:
-      if (gimp_drawable_has_alpha (drawable))
-        return babl_format ("Y'A u8");
-      else
-        return babl_format ("Y' u8");
+      return gimp_babl_format (GIMP_GRAY,
+                               gimp_babl_precision (GIMP_COMPONENT_TYPE_U8,
+                                                    linear),
+                               alpha);
 
     case GIMP_RGB:
+      return gimp_babl_format (GIMP_RGB,
+                               gimp_babl_precision (GIMP_COMPONENT_TYPE_U8,
+                                                    linear),
+                               alpha);
+
     case GIMP_INDEXED:
-      if (gimp_drawable_has_alpha (drawable))
+      if (alpha)
         return babl_format ("R'G'B'A u8");
       else
         return babl_format ("R'G'B' u8");
@@ -138,3 +175,105 @@ gimp_drawable_get_sub_preview (GimpDrawable *drawable,
 
   return preview;
 }
+
+GdkPixbuf *
+gimp_drawable_get_sub_pixbuf (GimpDrawable *drawable,
+                              gint          src_x,
+                              gint          src_y,
+                              gint          src_width,
+                              gint          src_height,
+                              gint          dest_width,
+                              gint          dest_height)
+{
+  GimpItem           *item;
+  GimpImage          *image;
+  GeglBuffer         *buffer;
+  GdkPixbuf          *pixbuf;
+  gdouble             scale;
+  gint                scaled_x;
+  gint                scaled_y;
+  GimpColorTransform  transform;
+  const Babl         *src_format;
+  const Babl         *dest_format;
+
+  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
+  g_return_val_if_fail (src_x >= 0, NULL);
+  g_return_val_if_fail (src_y >= 0, NULL);
+  g_return_val_if_fail (src_width  > 0, NULL);
+  g_return_val_if_fail (src_height > 0, NULL);
+  g_return_val_if_fail (dest_width  > 0, NULL);
+  g_return_val_if_fail (dest_height > 0, NULL);
+
+  item = GIMP_ITEM (drawable);
+
+  g_return_val_if_fail ((src_x + src_width)  <= gimp_item_get_width  (item), NULL);
+  g_return_val_if_fail ((src_y + src_height) <= gimp_item_get_height (item), NULL);
+
+  image = gimp_item_get_image (item);
+
+  if (! image->gimp->config->layer_previews)
+    return NULL;
+
+  buffer = gimp_drawable_get_buffer (drawable);
+
+  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+                           dest_width, dest_height);
+
+  scale = MIN ((gdouble) dest_width  / (gdouble) src_width,
+               (gdouble) dest_height / (gdouble) src_height);
+
+  scaled_x = RINT ((gdouble) src_x * scale);
+  scaled_y = RINT ((gdouble) src_y * scale);
+
+  transform = gimp_image_get_color_transform_to_srgb_u8 (image,
+                                                         &src_format,
+                                                         &dest_format);
+
+  if (transform)
+    {
+      GimpTempBuf *temp_buf;
+      GeglBuffer  *src_buf;
+      GeglBuffer  *dest_buf;
+
+      temp_buf = gimp_temp_buf_new (dest_width, dest_height, src_format);
+
+      gegl_buffer_get (buffer,
+                       GEGL_RECTANGLE (scaled_x, scaled_y,
+                                       dest_width, dest_height),
+                       scale,
+                       gimp_temp_buf_get_format (temp_buf),
+                       gimp_temp_buf_get_data (temp_buf),
+                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+
+      src_buf  = gimp_temp_buf_create_buffer (temp_buf);
+      dest_buf = gimp_pixbuf_create_buffer (pixbuf);
+
+      gimp_temp_buf_unref (temp_buf);
+
+      gimp_gegl_convert_color_transform (src_buf,
+                                         GEGL_RECTANGLE (0, 0,
+                                                         dest_width, dest_height),
+                                         src_format,
+                                         dest_buf,
+                                         GEGL_RECTANGLE (0, 0, 0, 0),
+                                         dest_format,
+                                         transform,
+                                         NULL);
+
+      g_object_unref (src_buf);
+      g_object_unref (dest_buf);
+    }
+  else
+    {
+      gegl_buffer_get (buffer,
+                       GEGL_RECTANGLE (scaled_x, scaled_y,
+                                       dest_width, dest_height),
+                       scale,
+                       gimp_pixbuf_get_format (pixbuf),
+                       gdk_pixbuf_get_pixels (pixbuf),
+                       gdk_pixbuf_get_rowstride (pixbuf),
+                       GEGL_ABYSS_CLAMP);
+    }
+
+  return pixbuf;
+}
diff --git a/app/core/gimpdrawable-preview.h b/app/core/gimpdrawable-preview.h
index 0a552ce..e058934 100644
--- a/app/core/gimpdrawable-preview.h
+++ b/app/core/gimpdrawable-preview.h
@@ -20,17 +20,22 @@
 
 
 /*
- *  virtual function of GimpDrawable -- dont't call directly
+ *  virtual functions of GimpDrawable -- dont't call directly
  */
 GimpTempBuf * gimp_drawable_get_new_preview    (GimpViewable *viewable,
                                                 GimpContext  *context,
                                                 gint          width,
                                                 gint          height);
+GdkPixbuf   * gimp_drawable_get_new_pixbuf     (GimpViewable *viewable,
+                                                GimpContext  *context,
+                                                gint          width,
+                                                gint          height);
 
 /*
  *  normal functions (no virtuals)
  */
 const Babl  * gimp_drawable_get_preview_format (GimpDrawable *drawable);
+
 GimpTempBuf * gimp_drawable_get_sub_preview    (GimpDrawable *drawable,
                                                 gint          src_x,
                                                 gint          src_y,
@@ -38,6 +43,13 @@ GimpTempBuf * gimp_drawable_get_sub_preview    (GimpDrawable *drawable,
                                                 gint          src_height,
                                                 gint          dest_width,
                                                 gint          dest_height);
+GdkPixbuf   * gimp_drawable_get_sub_pixbuf     (GimpDrawable *drawable,
+                                                gint          src_x,
+                                                gint          src_y,
+                                                gint          src_width,
+                                                gint          src_height,
+                                                gint          dest_width,
+                                                gint          dest_height);
 
 
 #endif /* __GIMP_DRAWABLE__PREVIEW_H__ */
diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c
index 2af04d1..bc96c1f 100644
--- a/app/core/gimpdrawable.c
+++ b/app/core/gimpdrawable.c
@@ -245,6 +245,7 @@ gimp_drawable_class_init (GimpDrawableClass *klass)
 
   viewable_class->get_size           = gimp_drawable_get_size;
   viewable_class->get_new_preview    = gimp_drawable_get_new_preview;
+  viewable_class->get_new_pixbuf     = gimp_drawable_get_new_pixbuf;
 
   filter_class->get_node             = gimp_drawable_get_node;
 
diff --git a/app/core/gimpimage-preview.c b/app/core/gimpimage-preview.c
index 405a629..374ce9c 100644
--- a/app/core/gimpimage-preview.c
+++ b/app/core/gimpimage-preview.c
@@ -17,16 +17,20 @@
 
 #include "config.h"
 
+#include <cairo.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gegl.h>
 
+#include "libgimpcolor/gimpcolor.h"
+
 #include "core-types.h"
 
 #include "gegl/gimp-babl.h"
+#include "gegl/gimp-gegl-loops.h"
 
 #include "gimpimage.h"
+#include "gimpimage-color-profile.h"
 #include "gimpimage-preview.h"
-#include "gimpimage-private.h"
 #include "gimppickable.h"
 #include "gimpprojectable.h"
 #include "gimpprojection.h"
@@ -103,6 +107,7 @@ gimp_image_get_new_preview (GimpViewable *viewable,
 {
   GimpImage   *image = GIMP_IMAGE (viewable);
   const Babl  *format;
+  gboolean     linear;
   GimpTempBuf *buf;
   gdouble      scale_x;
   gdouble      scale_y;
@@ -111,8 +116,11 @@ gimp_image_get_new_preview (GimpViewable *viewable,
   scale_y = (gdouble) height / (gdouble) gimp_image_get_height (image);
 
   format = gimp_projectable_get_format (GIMP_PROJECTABLE (image));
+  linear = gimp_babl_format_get_linear (format);
+
   format = gimp_babl_format (gimp_babl_format_get_base_type (format),
-                             GIMP_PRECISION_U8_GAMMA,
+                             gimp_babl_precision (GIMP_COMPONENT_TYPE_U8,
+                                                  linear),
                              babl_format_has_alpha (format));
 
   buf = gimp_temp_buf_new (width, height, format);
@@ -126,3 +134,74 @@ gimp_image_get_new_preview (GimpViewable *viewable,
 
   return buf;
 }
+
+GdkPixbuf *
+gimp_image_get_new_pixbuf (GimpViewable *viewable,
+                           GimpContext  *context,
+                           gint          width,
+                           gint          height)
+{
+  GimpImage          *image = GIMP_IMAGE (viewable);
+  GdkPixbuf          *pixbuf;
+  gdouble             scale_x;
+  gdouble             scale_y;
+  GimpColorTransform  transform;
+  const Babl         *src_format;
+  const Babl         *dest_format;
+
+  scale_x = (gdouble) width  / (gdouble) gimp_image_get_width  (image);
+  scale_y = (gdouble) height / (gdouble) gimp_image_get_height (image);
+
+  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+                           width, height);
+
+  transform = gimp_image_get_color_transform_to_srgb_u8 (image,
+                                                         &src_format,
+                                                         &dest_format);
+
+  if (transform)
+    {
+      GimpTempBuf *temp_buf;
+      GeglBuffer  *src_buf;
+      GeglBuffer  *dest_buf;
+
+      temp_buf = gimp_temp_buf_new (width, height, src_format);
+
+      gegl_buffer_get (gimp_pickable_get_buffer (GIMP_PICKABLE (image)),
+                       GEGL_RECTANGLE (0, 0, width, height),
+                       MIN (scale_x, scale_y),
+                       gimp_temp_buf_get_format (temp_buf),
+                       gimp_temp_buf_get_data (temp_buf),
+                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+
+      src_buf  = gimp_temp_buf_create_buffer (temp_buf);
+      dest_buf = gimp_pixbuf_create_buffer (pixbuf);
+
+      gimp_temp_buf_unref (temp_buf);
+
+      gimp_gegl_convert_color_transform (src_buf,
+                                         GEGL_RECTANGLE (0, 0,
+                                                         width, height),
+                                         src_format,
+                                         dest_buf,
+                                         GEGL_RECTANGLE (0, 0, 0, 0),
+                                         dest_format,
+                                         transform,
+                                         NULL);
+
+      g_object_unref (src_buf);
+      g_object_unref (dest_buf);
+    }
+  else
+    {
+      gegl_buffer_get (gimp_pickable_get_buffer (GIMP_PICKABLE (image)),
+                       GEGL_RECTANGLE (0, 0, width, height),
+                       MIN (scale_x, scale_y),
+                       gimp_pixbuf_get_format (pixbuf),
+                       gdk_pixbuf_get_pixels (pixbuf),
+                       gdk_pixbuf_get_rowstride (pixbuf),
+                       GEGL_ABYSS_CLAMP);
+    }
+
+  return pixbuf;
+}
diff --git a/app/core/gimpimage-preview.h b/app/core/gimpimage-preview.h
index 283e4b3..e6515d0 100644
--- a/app/core/gimpimage-preview.h
+++ b/app/core/gimpimage-preview.h
@@ -39,6 +39,10 @@ GimpTempBuf * gimp_image_get_new_preview  (GimpViewable *viewable,
                                            GimpContext  *context,
                                            gint          width,
                                            gint          height);
+GdkPixbuf   * gimp_image_get_new_pixbuf   (GimpViewable *viewable,
+                                           GimpContext  *context,
+                                           gint          width,
+                                           gint          height);
 
 
 #endif /* __GIMP_IMAGE_PREVIEW_H__ */
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index 02ba6be..72a6270 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -550,6 +550,7 @@ gimp_image_class_init (GimpImageClass *klass)
   viewable_class->get_preview_size    = gimp_image_get_preview_size;
   viewable_class->get_popup_size      = gimp_image_get_popup_size;
   viewable_class->get_new_preview     = gimp_image_get_new_preview;
+  viewable_class->get_new_pixbuf      = gimp_image_get_new_pixbuf;
   viewable_class->get_description     = gimp_image_get_description;
 
   klass->mode_changed                 = gimp_image_real_mode_changed;


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