1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <gegl.h>
21 #include <gtk/gtk.h>
22 
23 #include "libgimpbase/gimpbase.h"
24 #include "libgimpcolor/gimpcolor.h"
25 #include "libgimpconfig/gimpconfig.h"
26 #include "libgimpmath/gimpmath.h"
27 #include "libgimpwidgets/gimpwidgets.h"
28 
29 #include "display-types.h"
30 
31 #include "config/gimpcoreconfig.h"
32 
33 #include "gegl/gimp-babl.h"
34 
35 #include "core/gimpimage.h"
36 #include "core/gimpprojectable.h"
37 
38 #include "gimpdisplay.h"
39 #include "gimpdisplayshell.h"
40 #include "gimpdisplayshell-actions.h"
41 #include "gimpdisplayshell-filter.h"
42 #include "gimpdisplayshell-profile.h"
43 #include "gimpdisplayxfer.h"
44 
45 #include "gimp-intl.h"
46 
47 
48 /*  local function prototypes  */
49 
50 static void   gimp_display_shell_profile_free        (GimpDisplayShell *shell);
51 
52 static void   gimp_display_shell_color_config_notify (GimpColorConfig  *config,
53                                                       const GParamSpec *pspec,
54                                                       GimpDisplayShell *shell);
55 
56 
57 /*  public functions  */
58 
59 void
gimp_display_shell_profile_init(GimpDisplayShell * shell)60 gimp_display_shell_profile_init (GimpDisplayShell *shell)
61 {
62   GimpColorConfig *color_config;
63 
64   color_config = GIMP_CORE_CONFIG (shell->display->config)->color_management;
65 
66   shell->color_config = gimp_config_duplicate (GIMP_CONFIG (color_config));
67 
68   /* use after so we are called after the profile cache is invalidated
69    * in gimp_widget_get_color_transform()
70    */
71   g_signal_connect_after (shell->color_config, "notify",
72                           G_CALLBACK (gimp_display_shell_color_config_notify),
73                           shell);
74 }
75 
76 void
gimp_display_shell_profile_finalize(GimpDisplayShell * shell)77 gimp_display_shell_profile_finalize (GimpDisplayShell *shell)
78 {
79   g_clear_object (&shell->color_config);
80 
81   gimp_display_shell_profile_free (shell);
82 }
83 
84 void
gimp_display_shell_profile_update(GimpDisplayShell * shell)85 gimp_display_shell_profile_update (GimpDisplayShell *shell)
86 {
87   GimpImage        *image;
88   GimpColorProfile *src_profile;
89   const Babl       *src_format;
90   GimpColorProfile *filter_profile;
91   const Babl       *filter_format;
92   const Babl       *dest_format;
93 
94   gimp_display_shell_profile_free (shell);
95 
96   image = gimp_display_get_image (shell->display);
97 
98   if (! image)
99     return;
100 
101   src_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (shell));
102 
103   if (! src_profile)
104     return;
105 
106   src_format = gimp_projectable_get_format (GIMP_PROJECTABLE (image));
107 
108   if (gimp_display_shell_has_filter (shell))
109     {
110       filter_format  = shell->filter_format;
111       filter_profile = gimp_babl_format_get_color_profile (filter_format);
112     }
113   else
114     {
115       filter_format  = src_format;
116       filter_profile = src_profile;
117     }
118 
119   if (! gimp_display_shell_profile_can_convert_to_u8 (shell))
120     {
121       dest_format = shell->filter_format;
122     }
123   else
124     {
125       dest_format = babl_format ("R'G'B'A u8");
126     }
127 
128 #if 0
129   g_printerr ("src_profile:    %s\n"
130               "src_format:     %s\n"
131               "filter_profile: %s\n"
132               "filter_format:  %s\n"
133               "dest_format:    %s\n",
134               gimp_color_profile_get_label (src_profile),
135               babl_get_name (src_format),
136               gimp_color_profile_get_label (filter_profile),
137               babl_get_name (filter_format),
138               babl_get_name (dest_format));
139 #endif
140 
141   if (! gimp_color_transform_can_gegl_copy (src_profile, filter_profile))
142     {
143       shell->filter_transform =
144         gimp_color_transform_new (src_profile,
145                                   src_format,
146                                   filter_profile,
147                                   filter_format,
148                                   GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
149                                   GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION |
150                                   GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE);
151     }
152 
153   shell->profile_transform =
154     gimp_widget_get_color_transform (gtk_widget_get_toplevel (GTK_WIDGET (shell)),
155                                      gimp_display_shell_get_color_config (shell),
156                                      filter_profile,
157                                      filter_format,
158                                      dest_format);
159 
160   if (shell->filter_transform || shell->profile_transform)
161     {
162       gint w = GIMP_DISPLAY_RENDER_BUF_WIDTH;
163       gint h = GIMP_DISPLAY_RENDER_BUF_HEIGHT;
164 
165       shell->profile_data =
166         gegl_malloc (w * h * babl_format_get_bytes_per_pixel (src_format));
167 
168       shell->profile_stride =
169         w * babl_format_get_bytes_per_pixel (src_format);
170 
171       shell->profile_buffer =
172         gegl_buffer_linear_new_from_data (shell->profile_data,
173                                           src_format,
174                                           GEGL_RECTANGLE (0, 0, w, h),
175                                           GEGL_AUTO_ROWSTRIDE,
176                                           (GDestroyNotify) gegl_free,
177                                           shell->profile_data);
178     }
179 }
180 
181 gboolean
gimp_display_shell_profile_can_convert_to_u8(GimpDisplayShell * shell)182 gimp_display_shell_profile_can_convert_to_u8 (GimpDisplayShell *shell)
183 {
184   GimpImage *image = gimp_display_get_image (shell->display);
185 
186   if (image)
187     {
188       GimpComponentType component_type;
189 
190       if (! gimp_display_shell_has_filter (shell))
191         component_type = gimp_image_get_component_type (image);
192       else
193         component_type = gimp_babl_format_get_component_type (shell->filter_format);
194 
195       switch (component_type)
196         {
197         case GIMP_COMPONENT_TYPE_U8:
198 #if 0
199           /* would like to convert directly for these too, but it
200            * produces inferior results, see bug 750874
201            */
202         case GIMP_COMPONENT_TYPE_U16:
203         case GIMP_COMPONENT_TYPE_U32:
204 #endif
205           return TRUE;
206 
207         default:
208           break;
209         }
210     }
211 
212   return FALSE;
213 }
214 
215 
216 /*  private functions  */
217 
218 static void
gimp_display_shell_profile_free(GimpDisplayShell * shell)219 gimp_display_shell_profile_free (GimpDisplayShell *shell)
220 {
221   g_clear_object (&shell->profile_transform);
222   g_clear_object (&shell->filter_transform);
223   g_clear_object (&shell->profile_buffer);
224   shell->profile_data   = NULL;
225   shell->profile_stride = 0;
226 }
227 
228 static void
gimp_display_shell_color_config_notify(GimpColorConfig * config,const GParamSpec * pspec,GimpDisplayShell * shell)229 gimp_display_shell_color_config_notify (GimpColorConfig  *config,
230                                         const GParamSpec *pspec,
231                                         GimpDisplayShell *shell)
232 {
233   if (! strcmp (pspec->name, "mode")                                    ||
234       ! strcmp (pspec->name, "display-rendering-intent")                ||
235       ! strcmp (pspec->name, "display-use-black-point-compensation")    ||
236       ! strcmp (pspec->name, "simulation-rendering-intent")             ||
237       ! strcmp (pspec->name, "simulation-use-black-point-compensation") ||
238       ! strcmp (pspec->name, "simulation-gamut-check"))
239     {
240       gboolean     managed   = FALSE;
241       gboolean     softproof = FALSE;
242       const gchar *action    = NULL;
243 
244 #define SET_SENSITIVE(action, sensitive) \
245       gimp_display_shell_set_action_sensitive (shell, action, sensitive);
246 
247 #define SET_ACTIVE(action, active) \
248       gimp_display_shell_set_action_active (shell, action, active);
249 
250       switch (gimp_color_config_get_mode (config))
251         {
252         case GIMP_COLOR_MANAGEMENT_OFF:
253           break;
254 
255         case GIMP_COLOR_MANAGEMENT_DISPLAY:
256           managed = TRUE;
257           break;
258 
259         case GIMP_COLOR_MANAGEMENT_SOFTPROOF:
260           managed   = TRUE;
261           softproof = TRUE;
262           break;
263         }
264 
265       SET_ACTIVE ("view-color-management-enable",    managed);
266       SET_ACTIVE ("view-color-management-softproof", softproof);
267 
268       switch (gimp_color_config_get_display_intent (config))
269         {
270         case GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL:
271           action = "view-display-intent-perceptual";
272           break;
273 
274         case GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC:
275           action = "view-display-intent-relative-colorimetric";
276           break;
277 
278         case GIMP_COLOR_RENDERING_INTENT_SATURATION:
279           action = "view-display-intent-saturation";
280           break;
281 
282         case GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
283           action = "view-display-intent-absolute-colorimetric";
284           break;
285         }
286 
287       SET_SENSITIVE ("view-display-intent-perceptual",            managed);
288       SET_SENSITIVE ("view-display-intent-relative-colorimetric", managed);
289       SET_SENSITIVE ("view-display-intent-saturation",            managed);
290       SET_SENSITIVE ("view-display-intent-absolute-colorimetric", managed);
291 
292       SET_ACTIVE (action, TRUE);
293 
294       SET_SENSITIVE ("view-display-black-point-compensation", managed);
295       SET_ACTIVE    ("view-display-black-point-compensation",
296                      gimp_color_config_get_display_bpc (config));
297 
298       SET_SENSITIVE ("view-softproof-profile", softproof);
299 
300       switch (gimp_color_config_get_simulation_intent (config))
301         {
302         case GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL:
303           action = "view-softproof-intent-perceptual";
304           break;
305 
306         case GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC:
307           action = "view-softproof-intent-relative-colorimetric";
308           break;
309 
310         case GIMP_COLOR_RENDERING_INTENT_SATURATION:
311           action = "view-softproof-intent-saturation";
312           break;
313 
314         case GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
315           action = "view-softproof-intent-absolute-colorimetric";
316           break;
317         }
318 
319       SET_SENSITIVE ("view-softproof-intent-perceptual",            softproof);
320       SET_SENSITIVE ("view-softproof-intent-relative-colorimetric", softproof);
321       SET_SENSITIVE ("view-softproof-intent-saturation",            softproof);
322       SET_SENSITIVE ("view-softproof-intent-absolute-colorimetric", softproof);
323 
324       SET_ACTIVE (action, TRUE);
325 
326       SET_SENSITIVE ("view-softproof-black-point-compensation", softproof);
327       SET_ACTIVE    ("view-softproof-black-point-compensation",
328                      gimp_color_config_get_simulation_bpc (config));
329 
330       SET_SENSITIVE ("view-softproof-gamut-check", softproof);
331       SET_ACTIVE    ("view-softproof-gamut-check",
332                      gimp_color_config_get_simulation_gamut_check (config));
333     }
334 
335   gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (shell));
336 }
337