316 lines
10 KiB
C
316 lines
10 KiB
C
/* PIKA - Photo and Image Kooker Application
|
|
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
|
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
|
*
|
|
* Original copyright, applying to most contents (license remains unchanged):
|
|
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gegl.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libpikabase/pikabase.h"
|
|
#include "libpikacolor/pikacolor.h"
|
|
#include "libpikaconfig/pikaconfig.h"
|
|
#include "libpikamath/pikamath.h"
|
|
#include "libpikawidgets/pikawidgets.h"
|
|
|
|
#include "display-types.h"
|
|
|
|
#include "config/pikacoreconfig.h"
|
|
|
|
#include "gegl/pika-babl.h"
|
|
|
|
#include "core/pikaimage.h"
|
|
#include "core/pikaprojectable.h"
|
|
|
|
#include "pikadisplay.h"
|
|
#include "pikadisplayshell.h"
|
|
#include "pikadisplayshell-actions.h"
|
|
#include "pikadisplayshell-filter.h"
|
|
#include "pikadisplayshell-profile.h"
|
|
|
|
#include "pika-intl.h"
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
static void pika_display_shell_profile_free (PikaDisplayShell *shell);
|
|
|
|
static void pika_display_shell_color_config_notify (PikaColorConfig *config,
|
|
const GParamSpec *pspec,
|
|
PikaDisplayShell *shell);
|
|
|
|
|
|
/* public functions */
|
|
|
|
void
|
|
pika_display_shell_profile_init (PikaDisplayShell *shell)
|
|
{
|
|
PikaColorConfig *color_config;
|
|
|
|
color_config = PIKA_CORE_CONFIG (shell->display->config)->color_management;
|
|
|
|
shell->color_config = pika_config_duplicate (PIKA_CONFIG (color_config));
|
|
|
|
/* use after so we are called after the profile cache is invalidated
|
|
* in pika_widget_get_color_transform()
|
|
*/
|
|
g_signal_connect_after (shell->color_config, "notify",
|
|
G_CALLBACK (pika_display_shell_color_config_notify),
|
|
shell);
|
|
}
|
|
|
|
void
|
|
pika_display_shell_profile_finalize (PikaDisplayShell *shell)
|
|
{
|
|
g_clear_object (&shell->color_config);
|
|
|
|
pika_display_shell_profile_free (shell);
|
|
}
|
|
|
|
void
|
|
pika_display_shell_profile_update (PikaDisplayShell *shell)
|
|
{
|
|
PikaImage *image;
|
|
PikaColorProfile *src_profile;
|
|
const Babl *src_format;
|
|
PikaColorProfile *filter_profile;
|
|
const Babl *filter_format;
|
|
const Babl *dest_format;
|
|
PikaColorProfile *proof_profile;
|
|
PikaColorRenderingIntent simulation_intent =
|
|
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC;
|
|
gboolean simulation_bpc = FALSE;
|
|
|
|
pika_display_shell_profile_free (shell);
|
|
|
|
image = pika_display_get_image (shell->display);
|
|
|
|
if (! image)
|
|
return;
|
|
|
|
src_profile = pika_color_managed_get_color_profile (PIKA_COLOR_MANAGED (shell));
|
|
|
|
if (! src_profile)
|
|
return;
|
|
|
|
proof_profile = pika_color_managed_get_simulation_profile (PIKA_COLOR_MANAGED (image));
|
|
simulation_intent = pika_color_managed_get_simulation_intent (PIKA_COLOR_MANAGED (image));
|
|
simulation_bpc = pika_color_managed_get_simulation_bpc (PIKA_COLOR_MANAGED (image));
|
|
|
|
src_format = pika_projectable_get_format (PIKA_PROJECTABLE (image));
|
|
|
|
if (pika_display_shell_has_filter (shell))
|
|
{
|
|
filter_format = shell->filter_format;
|
|
filter_profile = shell->filter_profile;
|
|
}
|
|
else
|
|
{
|
|
filter_format = src_format;
|
|
filter_profile = src_profile;
|
|
}
|
|
|
|
if (! pika_display_shell_profile_can_convert_to_u8 (shell))
|
|
{
|
|
dest_format = shell->filter_format;
|
|
}
|
|
else
|
|
{
|
|
dest_format = babl_format ("R'G'B'A u8");
|
|
}
|
|
|
|
#if 0
|
|
g_printerr ("src_profile: %s\n"
|
|
"src_format: %s\n"
|
|
"filter_profile: %s\n"
|
|
"filter_format: %s\n"
|
|
"dest_format: %s\n",
|
|
pika_color_profile_get_label (src_profile),
|
|
babl_get_name (src_format),
|
|
pika_color_profile_get_label (filter_profile),
|
|
babl_get_name (filter_format),
|
|
babl_get_name (dest_format));
|
|
#endif
|
|
|
|
if (! pika_color_transform_can_gegl_copy (src_profile, filter_profile))
|
|
{
|
|
shell->filter_transform =
|
|
pika_color_transform_new (src_profile,
|
|
src_format,
|
|
filter_profile,
|
|
filter_format,
|
|
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
|
|
PIKA_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION |
|
|
PIKA_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE);
|
|
}
|
|
|
|
shell->profile_transform =
|
|
pika_widget_get_color_transform (gtk_widget_get_toplevel (GTK_WIDGET (shell)),
|
|
pika_display_shell_get_color_config (shell),
|
|
filter_profile,
|
|
filter_format,
|
|
dest_format,
|
|
proof_profile,
|
|
simulation_intent,
|
|
simulation_bpc);
|
|
|
|
if (shell->filter_transform || shell->profile_transform)
|
|
{
|
|
gint w = shell->render_buf_width;
|
|
gint h = shell->render_buf_height;
|
|
|
|
shell->profile_data =
|
|
gegl_malloc (w * h * babl_format_get_bytes_per_pixel (src_format));
|
|
|
|
shell->profile_stride =
|
|
w * babl_format_get_bytes_per_pixel (src_format);
|
|
|
|
shell->profile_buffer =
|
|
gegl_buffer_linear_new_from_data (shell->profile_data,
|
|
src_format,
|
|
GEGL_RECTANGLE (0, 0, w, h),
|
|
GEGL_AUTO_ROWSTRIDE,
|
|
(GDestroyNotify) gegl_free,
|
|
shell->profile_data);
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
pika_display_shell_profile_can_convert_to_u8 (PikaDisplayShell *shell)
|
|
{
|
|
PikaImage *image = pika_display_get_image (shell->display);
|
|
|
|
if (image)
|
|
{
|
|
PikaComponentType component_type;
|
|
|
|
if (! pika_display_shell_has_filter (shell))
|
|
component_type = pika_image_get_component_type (image);
|
|
else
|
|
component_type = pika_babl_format_get_component_type (shell->filter_format);
|
|
|
|
switch (component_type)
|
|
{
|
|
case PIKA_COMPONENT_TYPE_U8:
|
|
#if 0
|
|
/* would like to convert directly for these too, but it
|
|
* produces inferior results, see bug 750874
|
|
*/
|
|
case PIKA_COMPONENT_TYPE_U16:
|
|
case PIKA_COMPONENT_TYPE_U32:
|
|
#endif
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static void
|
|
pika_display_shell_profile_free (PikaDisplayShell *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;
|
|
}
|
|
|
|
static void
|
|
pika_display_shell_color_config_notify (PikaColorConfig *config,
|
|
const GParamSpec *pspec,
|
|
PikaDisplayShell *shell)
|
|
{
|
|
if (! strcmp (pspec->name, "mode") ||
|
|
! strcmp (pspec->name, "display-rendering-intent") ||
|
|
! strcmp (pspec->name, "display-use-black-point-compensation") ||
|
|
! strcmp (pspec->name, "simulation-gamut-check"))
|
|
{
|
|
gboolean managed = FALSE;
|
|
gboolean softproof = FALSE;
|
|
const gchar *action = NULL;
|
|
|
|
#define SET_SENSITIVE(action, sensitive) \
|
|
pika_display_shell_set_action_sensitive (shell, action, sensitive);
|
|
|
|
#define SET_ACTIVE(action, active) \
|
|
pika_display_shell_set_action_active (shell, action, active);
|
|
|
|
switch (pika_color_config_get_mode (config))
|
|
{
|
|
case PIKA_COLOR_MANAGEMENT_OFF:
|
|
break;
|
|
|
|
case PIKA_COLOR_MANAGEMENT_DISPLAY:
|
|
managed = TRUE;
|
|
break;
|
|
|
|
case PIKA_COLOR_MANAGEMENT_SOFTPROOF:
|
|
managed = TRUE;
|
|
softproof = TRUE;
|
|
break;
|
|
}
|
|
|
|
SET_ACTIVE ("view-color-management-enable", managed);
|
|
SET_ACTIVE ("view-color-management-softproof", softproof);
|
|
|
|
switch (pika_color_config_get_display_intent (config))
|
|
{
|
|
case PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL:
|
|
action = "view-display-intent-perceptual";
|
|
break;
|
|
|
|
case PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC:
|
|
action = "view-display-intent-relative-colorimetric";
|
|
break;
|
|
|
|
case PIKA_COLOR_RENDERING_INTENT_SATURATION:
|
|
action = "view-display-intent-saturation";
|
|
break;
|
|
|
|
case PIKA_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
|
|
action = "view-display-intent-absolute-colorimetric";
|
|
break;
|
|
}
|
|
|
|
SET_SENSITIVE ("view-display-intent-perceptual", managed);
|
|
SET_SENSITIVE ("view-display-intent-relative-colorimetric", managed);
|
|
SET_SENSITIVE ("view-display-intent-saturation", managed);
|
|
SET_SENSITIVE ("view-display-intent-absolute-colorimetric", managed);
|
|
|
|
SET_ACTIVE (action, TRUE);
|
|
|
|
SET_SENSITIVE ("view-display-black-point-compensation", managed);
|
|
SET_ACTIVE ("view-display-black-point-compensation",
|
|
pika_color_config_get_display_bpc (config));
|
|
SET_SENSITIVE ("view-softproof-gamut-check", softproof);
|
|
SET_ACTIVE ("view-softproof-gamut-check",
|
|
pika_color_config_get_simulation_gamut_check (config));
|
|
}
|
|
|
|
pika_color_managed_profile_changed (PIKA_COLOR_MANAGED (shell));
|
|
}
|