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.
This commit is contained in:
Michael Natterer 2016-04-15 16:52:25 +01:00
parent 0ee27de463
commit 9e8499bb48
6 changed files with 244 additions and 8 deletions

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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;

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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;