app: apply display filters in sRGB, not monitor profile

When we have display filters, break the color profile transform in
two: first, convert from the image profile to sRGB, then apply the
filters, then convert from sRGB to the monitor profile.
This commit is contained in:
Ell 2017-11-03 03:59:06 -04:00
parent 22a28a23cc
commit 9cd8e7f9c6
3 changed files with 147 additions and 67 deletions

View File

@ -87,6 +87,8 @@ gimp_display_shell_profile_update (GimpDisplayShell *shell)
GimpImage *image;
GimpColorProfile *src_profile;
const Babl *src_format;
GimpColorProfile *filter_profile;
const Babl *filter_format;
const Babl *dest_format;
gimp_display_shell_profile_free (shell);
@ -103,8 +105,18 @@ gimp_display_shell_profile_update (GimpDisplayShell *shell)
src_format = gimp_projectable_get_format (GIMP_PROJECTABLE (image));
if (gimp_display_shell_has_filter (shell) ||
! gimp_display_shell_profile_can_convert_to_u8 (shell))
if (gimp_display_shell_has_filter (shell))
{
filter_format = shell->filter_format;
filter_profile = gimp_babl_format_get_color_profile (filter_format);
}
else
{
filter_format = src_format;
filter_profile = src_profile;
}
if (! gimp_display_shell_profile_can_convert_to_u8 (shell))
{
dest_format = shell->filter_format;
}
@ -114,22 +126,38 @@ gimp_display_shell_profile_update (GimpDisplayShell *shell)
}
#if 0
g_printerr ("src_profile: %s\n"
"src_format: %s\n"
"dest_format: %s\n",
g_printerr ("src_profile: %s\n"
"src_format: %s\n"
"filter_profile: %s\n"
"filter_format: %s\n"
"dest_format: %s\n",
gimp_color_profile_get_label (src_profile),
babl_get_name (src_format),
gimp_color_profile_get_label (filter_profile),
babl_get_name (filter_format),
babl_get_name (dest_format));
#endif
if (! gimp_color_transform_can_gegl_copy (src_profile, filter_profile))
{
shell->filter_transform =
gimp_color_transform_new (src_profile,
src_format,
filter_profile,
filter_format,
GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION |
GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE);
}
shell->profile_transform =
gimp_widget_get_color_transform (gtk_widget_get_toplevel (GTK_WIDGET (shell)),
gimp_display_shell_get_color_config (shell),
src_profile,
src_format,
filter_profile,
filter_format,
dest_format);
if (shell->profile_transform)
if (shell->filter_transform || shell->profile_transform)
{
gint w = GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE;
gint h = GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE;
@ -157,7 +185,14 @@ gimp_display_shell_profile_can_convert_to_u8 (GimpDisplayShell *shell)
if (image)
{
switch (gimp_image_get_component_type (image))
GimpComponentType component_type;
if (! gimp_display_shell_has_filter (shell))
component_type = gimp_image_get_component_type (image);
else
component_type = gimp_babl_format_get_component_type (shell->filter_format);
switch (component_type)
{
case GIMP_COMPONENT_TYPE_U8:
#if 0
@ -184,6 +219,7 @@ static void
gimp_display_shell_profile_free (GimpDisplayShell *shell)
{
g_clear_object (&shell->profile_transform);
g_clear_object (&shell->filter_transform);
g_clear_object (&shell->profile_buffer);
shell->profile_data = NULL;
shell->profile_stride = 0;

View File

@ -171,7 +171,8 @@ gimp_display_shell_render (GimpDisplayShell *shell,
can_convert_to_u8 = gimp_display_shell_profile_can_convert_to_u8 (shell);
/* create the filter buffer if we have filters
/* create the filter buffer if we have filters, or can't convert
* to u8 directly
*/
if ((gimp_display_shell_has_filter (shell) || ! can_convert_to_u8) &&
! shell->filter_buffer)
@ -194,10 +195,10 @@ gimp_display_shell_render (GimpDisplayShell *shell,
shell->filter_data);
}
if (shell->profile_transform)
if (! gimp_display_shell_has_filter (shell) || shell->filter_transform)
{
/* if there is a profile transform, load the projection
* pixels into the profile_buffer
/* if there are no filters, or there is a filter transform,
* load the projection pixels into the profile_buffer
*/
#ifndef USE_NODE_BLIT
gegl_buffer_get (buffer,
@ -216,11 +217,96 @@ gimp_display_shell_render (GimpDisplayShell *shell,
shell->profile_data, shell->profile_stride,
GEGL_BLIT_CACHE);
#endif
}
else
{
/* otherwise, load the pixels directly into the filter_buffer
*/
#ifndef USE_NODE_BLIT
gegl_buffer_get (buffer,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width, scaled_height),
buffer_scale,
shell->filter_format,
shell->filter_data, shell->filter_stride,
GEGL_ABYSS_CLAMP);
#else
gegl_node_blit (node,
buffer_scale,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width, scaled_height),
shell->filter_format,
shell->filter_data, shell->filter_stride,
GEGL_BLIT_CACHE);
#endif
}
if (gimp_display_shell_has_filter (shell) || ! can_convert_to_u8)
/* if there is a filter transform, convert the pixels from
* the profile_buffer to the filter_buffer
*/
if (shell->filter_transform)
{
gimp_color_transform_process_buffer (shell->filter_transform,
shell->profile_buffer,
GEGL_RECTANGLE (0, 0,
scaled_width,
scaled_height),
shell->filter_buffer,
GEGL_RECTANGLE (0, 0,
scaled_width,
scaled_height));
}
/* if there are filters, apply them
*/
if (gimp_display_shell_has_filter (shell))
{
GeglBuffer *filter_buffer;
/* shift the filter_buffer so that the area passed to
* the filters is the real render area, allowing for
* position-dependent filters
*/
filter_buffer = g_object_new (GEGL_TYPE_BUFFER,
"source", shell->filter_buffer,
"shift-x", -scaled_x,
"shift-y", -scaled_y,
NULL);
/* convert the filter_buffer in place
*/
gimp_color_display_stack_convert_buffer (shell->filter_stack,
filter_buffer,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width,
scaled_height));
g_object_unref (filter_buffer);
}
/* if there is a profile transform...
*/
if (shell->profile_transform)
{
if (gimp_display_shell_has_filter (shell))
{
/* if there are filters, convert the pixels from the
* profile_buffer to the filter_buffer
/* if we have filters, convert the pixels in the filter_buffer
* in-place
*/
gimp_color_transform_process_buffer (shell->profile_transform,
shell->filter_buffer,
GEGL_RECTANGLE (0, 0,
scaled_width,
scaled_height),
shell->filter_buffer,
GEGL_RECTANGLE (0, 0,
scaled_width,
scaled_height));
}
else if (! can_convert_to_u8)
{
/* otherwise, if we can't convert to u8 directly, convert
* the pixels from the profile_buffer to the filter_buffer
*/
gimp_color_transform_process_buffer (shell->profile_transform,
shell->profile_buffer,
@ -248,55 +334,12 @@ gimp_display_shell_render (GimpDisplayShell *shell,
scaled_height));
}
}
else
{
/* otherwise, load the projection pixels directly into the
* filter_buffer
*/
#ifndef USE_NODE_BLIT
gegl_buffer_get (buffer,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width, scaled_height),
buffer_scale,
shell->filter_format,
shell->filter_data, shell->filter_stride,
GEGL_ABYSS_CLAMP);
#else
gegl_node_blit (node,
buffer_scale,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width, scaled_height),
shell->filter_format,
shell->filter_data, shell->filter_stride,
GEGL_BLIT_CACHE);
#endif
}
if (gimp_display_shell_has_filter (shell))
{
GeglBuffer *filter_buffer;
filter_buffer = g_object_new (GEGL_TYPE_BUFFER,
"source", shell->filter_buffer,
"shift-x", -scaled_x,
"shift-y", -scaled_y,
NULL);
/* convert the filter_buffer in place
*/
gimp_color_display_stack_convert_buffer (shell->filter_stack,
filter_buffer,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width,
scaled_height));
g_object_unref (filter_buffer);
}
/* finally, copy the filter buffer to the cairo-ARGB32 buffer,
* if necessary
*/
if (gimp_display_shell_has_filter (shell) || ! can_convert_to_u8)
{
/* finally, copy the filter buffer to the cairo-ARGB32 buffer
*/
gegl_buffer_get (shell->filter_buffer,
GEGL_RECTANGLE (0, 0,
scaled_width,

View File

@ -157,13 +157,14 @@ struct _GimpDisplayShell
guchar *profile_data; /* profile_buffer's pixels */
gint profile_stride; /* profile_buffer's stride */
GimpColorDisplayStack *filter_stack; /* color display conversion stuff */
GimpColorDisplayStack *filter_stack; /* color display conversion stuff */
guint filter_idle_id;
const Babl *filter_format; /* filter_buffer's format */
GeglBuffer *filter_buffer; /* buffer for display filters */
guchar *filter_data; /* filter_buffer's pixels */
gint filter_stride; /* filter_buffer's stride */
GimpColorTransform *filter_transform;
const Babl *filter_format; /* filter_buffer's format */
GeglBuffer *filter_buffer; /* buffer for display filters */
guchar *filter_data; /* filter_buffer's pixels */
gint filter_stride; /* filter_buffer's stride */
GimpDisplayXfer *xfer; /* manages image buffer transfers */
cairo_surface_t *mask_surface; /* buffer for rendering the mask */