1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3  *
4  * gimpcolorprofile.c
5  * Copyright (C) 2014  Michael Natterer <mitch@gimp.org>
6  *                     Elle Stone <ellestone@ninedegreesbelow.com>
7  *                     Øyvind Kolås <pippin@gimp.org>
8  *
9  * This library is free software: you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library.  If not, see
21  * <https://www.gnu.org/licenses/>.
22  */
23 
24 #include "config.h"
25 
26 #include <string.h>
27 
28 #include <lcms2.h>
29 
30 #include <gio/gio.h>
31 #include <gegl.h>
32 
33 #include "libgimpbase/gimpbase.h"
34 
35 #include "gimpcolortypes.h"
36 
37 #include "gimpcolorprofile.h"
38 
39 #include "libgimp/libgimp-intl.h"
40 
41 
42 #ifndef TYPE_RGBA_DBL
43 #define TYPE_RGBA_DBL       (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(0))
44 #endif
45 
46 #ifndef TYPE_GRAYA_HALF_FLT
47 #define TYPE_GRAYA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2))
48 #endif
49 
50 #ifndef TYPE_GRAYA_FLT
51 #define TYPE_GRAYA_FLT      (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(4))
52 #endif
53 
54 #ifndef TYPE_GRAYA_DBL
55 #define TYPE_GRAYA_DBL      (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(0))
56 #endif
57 
58 #ifndef TYPE_CMYKA_DBL
59 #define TYPE_CMYKA_DBL      (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(0))
60 #endif
61 
62 #ifndef TYPE_CMYKA_HALF_FLT
63 #define TYPE_CMYKA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(2))
64 #endif
65 
66 #ifndef TYPE_CMYKA_FLT
67 #define TYPE_CMYKA_FLT      (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(4))
68 #endif
69 
70 #ifndef TYPE_CMYKA_16
71 #define TYPE_CMYKA_16       (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(2))
72 #endif
73 
74 
75 /**
76  * SECTION: gimpcolorprofile
77  * @title: GimpColorProfile
78  * @short_description: Definitions and Functions relating to LCMS.
79  *
80  * Definitions and Functions relating to LCMS.
81  **/
82 
83 /**
84  * GimpColorProfile:
85  *
86  * Simply a typedef to #gpointer, but actually is a cmsHPROFILE. It's
87  * used in public GIMP APIs in order to avoid having to include LCMS
88  * headers.
89  **/
90 
91 
92 struct _GimpColorProfilePrivate
93 {
94   cmsHPROFILE  lcms_profile;
95   guint8      *data;
96   gsize        length;
97 
98   gchar       *description;
99   gchar       *manufacturer;
100   gchar       *model;
101   gchar       *copyright;
102   gchar       *label;
103   gchar       *summary;
104 };
105 
106 
107 static void   gimp_color_profile_finalize (GObject *object);
108 
109 
G_DEFINE_TYPE_WITH_PRIVATE(GimpColorProfile,gimp_color_profile,G_TYPE_OBJECT)110 G_DEFINE_TYPE_WITH_PRIVATE (GimpColorProfile, gimp_color_profile, G_TYPE_OBJECT)
111 
112 #define parent_class gimp_color_profile_parent_class
113 
114 
115 #define GIMP_COLOR_PROFILE_ERROR gimp_color_profile_error_quark ()
116 
117 static GQuark
118 gimp_color_profile_error_quark (void)
119 {
120   static GQuark quark = 0;
121 
122   if (G_UNLIKELY (quark == 0))
123     quark = g_quark_from_static_string ("gimp-color-profile-error-quark");
124 
125   return quark;
126 }
127 
128 static void
gimp_color_profile_class_init(GimpColorProfileClass * klass)129 gimp_color_profile_class_init (GimpColorProfileClass *klass)
130 {
131   GObjectClass *object_class = G_OBJECT_CLASS (klass);
132 
133   object_class->finalize = gimp_color_profile_finalize;
134 }
135 
136 static void
gimp_color_profile_init(GimpColorProfile * profile)137 gimp_color_profile_init (GimpColorProfile *profile)
138 {
139   profile->priv = gimp_color_profile_get_instance_private (profile);
140 }
141 
142 static void
gimp_color_profile_finalize(GObject * object)143 gimp_color_profile_finalize (GObject *object)
144 {
145   GimpColorProfile *profile = GIMP_COLOR_PROFILE (object);
146 
147   g_clear_pointer (&profile->priv->lcms_profile, cmsCloseProfile);
148 
149   g_clear_pointer (&profile->priv->data, g_free);
150   profile->priv->length = 0;
151 
152   g_clear_pointer (&profile->priv->description,  g_free);
153   g_clear_pointer (&profile->priv->manufacturer, g_free);
154   g_clear_pointer (&profile->priv->model,        g_free);
155   g_clear_pointer (&profile->priv->copyright,    g_free);
156   g_clear_pointer (&profile->priv->label,        g_free);
157   g_clear_pointer (&profile->priv->summary,      g_free);
158 
159   G_OBJECT_CLASS (parent_class)->finalize (object);
160 }
161 
162 
163 /**
164  * gimp_color_profile_new_from_file:
165  * @file:  a #GFile
166  * @error: return location for #GError
167  *
168  * This function opens an ICC color profile from @file.
169  *
170  * Return value: the #GimpColorProfile, or %NULL. On error, %NULL is
171  *               returned and @error is set.
172  *
173  * Since: 2.10
174  **/
175 GimpColorProfile *
gimp_color_profile_new_from_file(GFile * file,GError ** error)176 gimp_color_profile_new_from_file (GFile   *file,
177                                   GError **error)
178 {
179   GimpColorProfile *profile      = NULL;
180   cmsHPROFILE       lcms_profile = NULL;
181   guint8           *data         = NULL;
182   gsize             length       = 0;
183   gchar            *path;
184 
185   g_return_val_if_fail (G_IS_FILE (file), NULL);
186   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
187 
188   path = g_file_get_path (file);
189 
190   if (path)
191     {
192       GMappedFile *mapped;
193 
194       mapped = g_mapped_file_new (path, FALSE, error);
195       g_free (path);
196 
197       if (! mapped)
198         return NULL;
199 
200       length = g_mapped_file_get_length (mapped);
201       data   = g_memdup (g_mapped_file_get_contents (mapped), length);
202 
203       lcms_profile = cmsOpenProfileFromMem (data, length);
204 
205       g_mapped_file_unref (mapped);
206     }
207   else
208     {
209       GFileInfo *info;
210 
211       info = g_file_query_info (file,
212                                 G_FILE_ATTRIBUTE_STANDARD_SIZE,
213                                 G_FILE_QUERY_INFO_NONE,
214                                 NULL, error);
215       if (info)
216         {
217           GInputStream *input;
218 
219           length = g_file_info_get_size (info);
220           data   = g_malloc (length);
221 
222           g_object_unref (info);
223 
224           input = G_INPUT_STREAM (g_file_read (file, NULL, error));
225 
226           if (input)
227             {
228               gsize bytes_read;
229 
230               if (g_input_stream_read_all (input, data, length,
231                                            &bytes_read, NULL, error) &&
232                   bytes_read == length)
233                 {
234                   lcms_profile = cmsOpenProfileFromMem (data, length);
235                 }
236 
237               g_object_unref (input);
238             }
239         }
240     }
241 
242   if (lcms_profile)
243     {
244       profile = g_object_new (GIMP_TYPE_COLOR_PROFILE, NULL);
245 
246       profile->priv->lcms_profile = lcms_profile;
247       profile->priv->data         = data;
248       profile->priv->length       = length;
249     }
250   else
251     {
252       if (data)
253         g_free (data);
254 
255       if (error && *error == NULL)
256         {
257           g_set_error (error, GIMP_COLOR_PROFILE_ERROR, 0,
258                        _("'%s' does not appear to be an ICC color profile"),
259                        gimp_file_get_utf8_name (file));
260         }
261     }
262 
263   return profile;
264 }
265 
266 /**
267  * gimp_color_profile_new_from_icc_profile:
268  * @data:   pointer to memory containing an ICC profile
269  * @length: length of the profile in memory, in bytes
270  * @error:  return location for #GError
271  *
272  * This function opens an ICC color profile from memory. On error,
273  * %NULL is returned and @error is set.
274  *
275  * Return value: the #GimpColorProfile, or %NULL.
276  *
277  * Since: 2.10
278  **/
279 GimpColorProfile *
gimp_color_profile_new_from_icc_profile(const guint8 * data,gsize length,GError ** error)280 gimp_color_profile_new_from_icc_profile (const guint8  *data,
281                                          gsize          length,
282                                          GError       **error)
283 {
284   cmsHPROFILE       lcms_profile = 0;
285   GimpColorProfile *profile      = NULL;
286 
287   g_return_val_if_fail (data != NULL || length == 0, NULL);
288   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
289 
290   if (length > 0)
291     lcms_profile = cmsOpenProfileFromMem (data, length);
292 
293   if (lcms_profile)
294     {
295       profile = g_object_new (GIMP_TYPE_COLOR_PROFILE, NULL);
296 
297       profile->priv->lcms_profile = lcms_profile;
298       profile->priv->data         = g_memdup (data, length);
299       profile->priv->length       = length;
300    }
301   else
302     {
303       g_set_error_literal (error, GIMP_COLOR_PROFILE_ERROR, 0,
304                            _("Data does not appear to be an ICC color profile"));
305     }
306 
307   return profile;
308 }
309 
310 /**
311  * gimp_color_profile_new_from_lcms_profile:
312  * @lcms_profile: an LCMS cmsHPROFILE pointer
313  * @error:        return location for #GError
314  *
315  * This function creates a GimpColorProfile from a cmsHPROFILE. On
316  * error, %NULL is returned and @error is set. The passed
317  * @lcms_profile pointer is not retained by the created
318  * #GimpColorProfile.
319  *
320  * Return value: the #GimpColorProfile, or %NULL.
321  *
322  * Since: 2.10
323  **/
324 GimpColorProfile *
gimp_color_profile_new_from_lcms_profile(gpointer lcms_profile,GError ** error)325 gimp_color_profile_new_from_lcms_profile (gpointer   lcms_profile,
326                                           GError   **error)
327 {
328   cmsUInt32Number size;
329 
330   g_return_val_if_fail (lcms_profile != NULL, NULL);
331   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
332 
333   if (cmsSaveProfileToMem (lcms_profile, NULL, &size))
334     {
335       guint8 *data = g_malloc (size);
336 
337       if (cmsSaveProfileToMem (lcms_profile, data, &size))
338         {
339           gsize length = size;
340 
341           lcms_profile = cmsOpenProfileFromMem (data, length);
342 
343           if (lcms_profile)
344             {
345               GimpColorProfile *profile;
346 
347               profile = g_object_new (GIMP_TYPE_COLOR_PROFILE, NULL);
348 
349               profile->priv->lcms_profile = lcms_profile;
350               profile->priv->data         = data;
351               profile->priv->length       = length;
352 
353               return profile;
354             }
355         }
356 
357       g_free (data);
358     }
359 
360   g_set_error_literal (error, GIMP_COLOR_PROFILE_ERROR, 0,
361                        _("Could not save color profile to memory"));
362 
363   return NULL;
364 }
365 
366 /**
367  * gimp_color_profile_save_to_file:
368  * @profile: a #GimpColorProfile
369  * @file:    a #GFile
370  * @error:   return location for #GError
371  *
372  * This function saves @profile to @file as ICC profile.
373  *
374  * Return value: %TRUE on success, %FALSE if an error occurred.
375  *
376  * Since: 2.10
377  **/
378 gboolean
gimp_color_profile_save_to_file(GimpColorProfile * profile,GFile * file,GError ** error)379 gimp_color_profile_save_to_file (GimpColorProfile  *profile,
380                                  GFile             *file,
381                                  GError           **error)
382 {
383   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
384   g_return_val_if_fail (G_IS_FILE (file), FALSE);
385   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
386 
387   return g_file_replace_contents (file,
388                                   (const gchar *) profile->priv->data,
389                                   profile->priv->length,
390                                   NULL, FALSE,
391                                   G_FILE_CREATE_NONE,
392                                   NULL,
393                                   NULL,
394                                   error);
395 }
396 
397 /**
398  * gimp_color_profile_get_icc_profile:
399  * @profile: a #GimpColorProfile
400  * @length:  return location for the number of bytes
401  *
402  * This function returns @profile as ICC profile data. The returned
403  * memory belongs to @profile and must not be modified or freed.
404  *
405  * Return value: a pointer to the IIC profile data.
406  *
407  * Since: 2.10
408  **/
409 const guint8 *
gimp_color_profile_get_icc_profile(GimpColorProfile * profile,gsize * length)410 gimp_color_profile_get_icc_profile (GimpColorProfile  *profile,
411                                     gsize             *length)
412 {
413   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
414   g_return_val_if_fail (length != NULL, NULL);
415 
416   *length = profile->priv->length;
417 
418   return profile->priv->data;
419 }
420 
421 /**
422  * gimp_color_profile_get_lcms_profile:
423  * @profile: a #GimpColorProfile
424  *
425  * This function returns @profile's cmsHPROFILE. The returned
426  * value belongs to @profile and must not be modified or freed.
427  *
428  * Return value: a pointer to the cmsHPROFILE.
429  *
430  * Since: 2.10
431  **/
432 gpointer
gimp_color_profile_get_lcms_profile(GimpColorProfile * profile)433 gimp_color_profile_get_lcms_profile (GimpColorProfile *profile)
434 {
435   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
436 
437   return profile->priv->lcms_profile;
438 }
439 
440 static gchar *
gimp_color_profile_get_info(GimpColorProfile * profile,cmsInfoType info)441 gimp_color_profile_get_info (GimpColorProfile *profile,
442                              cmsInfoType       info)
443 {
444   cmsUInt32Number  size;
445   gchar           *text = NULL;
446 
447   size = cmsGetProfileInfoASCII (profile->priv->lcms_profile, info,
448                                  "en", "US", NULL, 0);
449   if (size > 0)
450     {
451       gchar *data = g_new (gchar, size + 1);
452 
453       size = cmsGetProfileInfoASCII (profile->priv->lcms_profile, info,
454                                      "en", "US", data, size);
455       if (size > 0)
456         text = gimp_any_to_utf8 (data, -1, NULL);
457 
458       g_free (data);
459     }
460 
461   return text;
462 }
463 
464 /**
465  * gimp_color_profile_get_description:
466  * @profile: a #GimpColorProfile
467  *
468  * Return value: a string containing @profile's description. The
469  *               returned value belongs to @profile and must not be
470  *               modified or freed.
471  *
472  * Since: 2.10
473  **/
474 const gchar *
gimp_color_profile_get_description(GimpColorProfile * profile)475 gimp_color_profile_get_description (GimpColorProfile *profile)
476 {
477   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
478 
479   if (! profile->priv->description)
480     profile->priv->description =
481       gimp_color_profile_get_info (profile, cmsInfoDescription);
482 
483   return profile->priv->description;
484 }
485 
486 /**
487  * gimp_color_profile_get_manufacturer:
488  * @profile: a #GimpColorProfile
489  *
490  * Return value: a string containing @profile's manufacturer. The
491  *               returned value belongs to @profile and must not be
492  *               modified or freed.
493  *
494  * Since: 2.10
495  **/
496 const gchar *
gimp_color_profile_get_manufacturer(GimpColorProfile * profile)497 gimp_color_profile_get_manufacturer (GimpColorProfile *profile)
498 {
499   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
500 
501   if (! profile->priv->manufacturer)
502     profile->priv->manufacturer =
503       gimp_color_profile_get_info (profile, cmsInfoManufacturer);
504 
505   return profile->priv->manufacturer;
506 }
507 
508 /**
509  * gimp_color_profile_get_model:
510  * @profile: a #GimpColorProfile
511  *
512  * Return value: a string containing @profile's model. The returned
513  *               value belongs to @profile and must not be modified or
514  *               freed.
515  *
516  * Since: 2.10
517  **/
518 const gchar *
gimp_color_profile_get_model(GimpColorProfile * profile)519 gimp_color_profile_get_model (GimpColorProfile *profile)
520 {
521   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
522 
523   if (! profile->priv->model)
524     profile->priv->model =
525       gimp_color_profile_get_info (profile, cmsInfoModel);
526 
527   return profile->priv->model;
528 }
529 
530 /**
531  * gimp_color_profile_get_copyright:
532  * @profile: a #GimpColorProfile
533  *
534  * Return value: a string containing @profile's copyright. The
535  *               returned value belongs to @profile and must not be
536  *               modified or freed.
537  *
538  * Since: 2.10
539  **/
540 const gchar *
gimp_color_profile_get_copyright(GimpColorProfile * profile)541 gimp_color_profile_get_copyright (GimpColorProfile *profile)
542 {
543   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
544 
545   if (! profile->priv->copyright)
546     profile->priv->copyright =
547       gimp_color_profile_get_info (profile, cmsInfoCopyright);
548 
549   return profile->priv->copyright;
550 }
551 
552 /**
553  * gimp_color_profile_get_label:
554  * @profile: a #GimpColorProfile
555  *
556  * This function returns a string containing @profile's "title", a
557  * string that can be used to label the profile in a user interface.
558  *
559  * Unlike gimp_color_profile_get_description(), this function always
560  * returns a string (as a fallback, it returns "(unnamed profile)").
561  *
562  * Return value: the @profile's label. The returned value belongs to
563  *               @profile and must not be modified or freed.
564  *
565  * Since: 2.10
566  **/
567 const gchar *
gimp_color_profile_get_label(GimpColorProfile * profile)568 gimp_color_profile_get_label (GimpColorProfile *profile)
569 {
570 
571   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
572 
573   if (! profile->priv->label)
574     {
575       const gchar *label = gimp_color_profile_get_description (profile);
576 
577       if (! label || ! strlen (label))
578         label = _("(unnamed profile)");
579 
580       profile->priv->label = g_strdup (label);
581     }
582 
583   return profile->priv->label;
584 }
585 
586 /**
587  * gimp_color_profile_get_summary:
588  * @profile: a #GimpColorProfile
589  *
590  * This function return a string containing a multi-line summary of
591  * @profile's description, model, manufacturer and copyright, to be
592  * used as detailed information about the profile in a user
593  * interface.
594  *
595  * Return value: the @profile's summary. The returned value belongs to
596  *               @profile and must not be modified or freed.
597  *
598  * Since: 2.10
599  **/
600 const gchar *
gimp_color_profile_get_summary(GimpColorProfile * profile)601 gimp_color_profile_get_summary (GimpColorProfile *profile)
602 {
603   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
604 
605   if (! profile->priv->summary)
606     {
607       GString     *string = g_string_new (NULL);
608       const gchar *text;
609 
610       text = gimp_color_profile_get_description (profile);
611       if (text)
612         g_string_append (string, text);
613 
614       text = gimp_color_profile_get_model (profile);
615       if (text)
616         {
617           if (string->len > 0)
618             g_string_append (string, "\n");
619 
620           g_string_append_printf (string, _("Model: %s"), text);
621         }
622 
623       text = gimp_color_profile_get_manufacturer (profile);
624       if (text)
625         {
626           if (string->len > 0)
627             g_string_append (string, "\n");
628 
629           g_string_append_printf (string, _("Manufacturer: %s"), text);
630         }
631 
632       text = gimp_color_profile_get_copyright (profile);
633       if (text)
634         {
635           if (string->len > 0)
636             g_string_append (string, "\n");
637 
638           g_string_append_printf (string, _("Copyright: %s"), text);
639         }
640 
641       profile->priv->summary = g_string_free (string, FALSE);
642     }
643 
644   return profile->priv->summary;
645 }
646 
647 /**
648  * gimp_color_profile_is_equal:
649  * @profile1: a #GimpColorProfile
650  * @profile2: a #GimpColorProfile
651  *
652  * Compares two profiles.
653  *
654  * Return value: %TRUE if the profiles are equal, %FALSE otherwise.
655  *
656  * Since: 2.10
657  **/
658 gboolean
gimp_color_profile_is_equal(GimpColorProfile * profile1,GimpColorProfile * profile2)659 gimp_color_profile_is_equal (GimpColorProfile *profile1,
660                              GimpColorProfile *profile2)
661 {
662   const gsize header_len = sizeof (cmsICCHeader);
663 
664   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile1), FALSE);
665   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile2), FALSE);
666 
667   return profile1 == profile2                              ||
668          (profile1->priv->length == profile2->priv->length &&
669           memcmp (profile1->priv->data + header_len,
670                   profile2->priv->data + header_len,
671                   profile1->priv->length - header_len) == 0);
672 }
673 
674 /**
675  * gimp_color_profile_is_rgb:
676  * @profile: a #GimpColorProfile
677  *
678  * Return value: %TRUE if the profile's color space is RGB, %FALSE
679  * otherwise.
680  *
681  * Since: 2.10
682  **/
683 gboolean
gimp_color_profile_is_rgb(GimpColorProfile * profile)684 gimp_color_profile_is_rgb (GimpColorProfile *profile)
685 {
686   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
687 
688   return (cmsGetColorSpace (profile->priv->lcms_profile) == cmsSigRgbData);
689 }
690 
691 /**
692  * gimp_color_profile_is_gray:
693  * @profile: a #GimpColorProfile
694  *
695  * Return value: %TRUE if the profile's color space is grayscale, %FALSE
696  * otherwise.
697  *
698  * Since: 2.10
699  **/
700 gboolean
gimp_color_profile_is_gray(GimpColorProfile * profile)701 gimp_color_profile_is_gray (GimpColorProfile *profile)
702 {
703   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
704 
705   return (cmsGetColorSpace (profile->priv->lcms_profile) == cmsSigGrayData);
706 }
707 
708 /**
709  * gimp_color_profile_is_cmyk:
710  * @profile: a #GimpColorProfile
711  *
712  * Return value: %TRUE if the profile's color space is CMYK, %FALSE
713  * otherwise.
714  *
715  * Since: 2.10
716  **/
717 gboolean
gimp_color_profile_is_cmyk(GimpColorProfile * profile)718 gimp_color_profile_is_cmyk (GimpColorProfile *profile)
719 {
720   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
721 
722   return (cmsGetColorSpace (profile->priv->lcms_profile) == cmsSigCmykData);
723 }
724 
725 
726 /**
727  * gimp_color_profile_is_linear:
728  * @profile: a #GimpColorProfile
729  *
730  * This function determines is the ICC profile represented by a GimpColorProfile
731  * is a linear RGB profile or not, some profiles that are LUTs though linear
732  * will also return FALSE;
733  *
734  * Return value: %TRUE if the profile is a matrix shaping profile with linear
735  * TRCs, %FALSE otherwise.
736  *
737  * Since: 2.10
738  **/
739 gboolean
gimp_color_profile_is_linear(GimpColorProfile * profile)740 gimp_color_profile_is_linear (GimpColorProfile *profile)
741 {
742   cmsHPROFILE   prof;
743   cmsToneCurve *curve;
744 
745   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
746 
747   prof = profile->priv->lcms_profile;
748 
749   if (! cmsIsMatrixShaper (prof))
750     return FALSE;
751 
752   if (cmsIsCLUT (prof, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT))
753     return FALSE;
754 
755   if (cmsIsCLUT (prof, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT))
756     return FALSE;
757 
758   if (gimp_color_profile_is_rgb (profile))
759     {
760       curve = cmsReadTag(prof, cmsSigRedTRCTag);
761       if (curve == NULL || ! cmsIsToneCurveLinear (curve))
762         return FALSE;
763 
764       curve = cmsReadTag (prof, cmsSigGreenTRCTag);
765       if (curve == NULL || ! cmsIsToneCurveLinear (curve))
766         return FALSE;
767 
768       curve = cmsReadTag (prof, cmsSigBlueTRCTag);
769       if (curve == NULL || ! cmsIsToneCurveLinear (curve))
770         return FALSE;
771     }
772   else if (gimp_color_profile_is_gray (profile))
773     {
774       curve = cmsReadTag(prof, cmsSigGrayTRCTag);
775       if (curve == NULL || ! cmsIsToneCurveLinear (curve))
776         return FALSE;
777     }
778   else
779     {
780       return FALSE;
781     }
782 
783   return TRUE;
784 }
785 
786 static void
gimp_color_profile_set_tag(cmsHPROFILE profile,cmsTagSignature sig,const gchar * tag)787 gimp_color_profile_set_tag (cmsHPROFILE      profile,
788                             cmsTagSignature  sig,
789                             const gchar     *tag)
790 {
791   cmsMLU *mlu;
792 
793   mlu = cmsMLUalloc (NULL, 1);
794   cmsMLUsetASCII (mlu, "en", "US", tag);
795   cmsWriteTag (profile, sig, mlu);
796   cmsMLUfree (mlu);
797 }
798 
799 static gboolean
gimp_color_profile_get_rgb_matrix_colorants(GimpColorProfile * profile,GimpMatrix3 * matrix)800 gimp_color_profile_get_rgb_matrix_colorants (GimpColorProfile *profile,
801                                              GimpMatrix3      *matrix)
802 {
803   cmsHPROFILE  lcms_profile;
804   cmsCIEXYZ   *red;
805   cmsCIEXYZ   *green;
806   cmsCIEXYZ   *blue;
807 
808   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
809 
810   lcms_profile = profile->priv->lcms_profile;
811 
812   red   = cmsReadTag (lcms_profile, cmsSigRedColorantTag);
813   green = cmsReadTag (lcms_profile, cmsSigGreenColorantTag);
814   blue  = cmsReadTag (lcms_profile, cmsSigBlueColorantTag);
815 
816   if (red && green && blue)
817     {
818       if (matrix)
819         {
820           matrix->coeff[0][0] = red->X;
821           matrix->coeff[0][1] = red->Y;
822           matrix->coeff[0][2] = red->Z;
823 
824           matrix->coeff[1][0] = green->X;
825           matrix->coeff[1][1] = green->Y;
826           matrix->coeff[1][2] = green->Z;
827 
828           matrix->coeff[2][0] = blue->X;
829           matrix->coeff[2][1] = blue->Y;
830           matrix->coeff[2][2] = blue->Z;
831         }
832 
833       return TRUE;
834     }
835 
836   return FALSE;
837 }
838 
839 static void
gimp_color_profile_make_tag(cmsHPROFILE profile,cmsTagSignature sig,const gchar * gimp_tag,const gchar * gimp_prefix,const gchar * gimp_prefix_alt,const gchar * original_tag)840 gimp_color_profile_make_tag (cmsHPROFILE       profile,
841                              cmsTagSignature   sig,
842                              const gchar      *gimp_tag,
843                              const gchar      *gimp_prefix,
844                              const gchar      *gimp_prefix_alt,
845                              const gchar      *original_tag)
846 {
847   if (! original_tag || ! strlen (original_tag) ||
848       ! strcmp (original_tag, gimp_tag))
849     {
850       /* if there is no original tag (or it is the same as the new
851        * tag), just use the new tag
852        */
853 
854       gimp_color_profile_set_tag (profile, sig, gimp_tag);
855     }
856   else
857     {
858       /* otherwise prefix the existing tag with a gimp prefix
859        * indicating that the profile has been generated
860        */
861 
862       if (g_str_has_prefix (original_tag, gimp_prefix))
863         {
864           /* don't add multiple GIMP prefixes */
865           gimp_color_profile_set_tag (profile, sig, original_tag);
866         }
867       else if (gimp_prefix_alt &&
868                g_str_has_prefix (original_tag, gimp_prefix_alt))
869         {
870           /* replace GIMP prefix_alt by prefix */
871           gchar *new_tag = g_strconcat (gimp_prefix,
872                                         original_tag + strlen (gimp_prefix_alt),
873                                         NULL);
874 
875           gimp_color_profile_set_tag (profile, sig, new_tag);
876           g_free (new_tag);
877         }
878       else
879         {
880           gchar *new_tag = g_strconcat (gimp_prefix,
881                                         original_tag,
882                                         NULL);
883 
884           gimp_color_profile_set_tag (profile, sig, new_tag);
885           g_free (new_tag);
886         }
887     }
888 }
889 
890 static GimpColorProfile *
gimp_color_profile_new_from_color_profile(GimpColorProfile * profile,gboolean linear)891 gimp_color_profile_new_from_color_profile (GimpColorProfile *profile,
892                                            gboolean          linear)
893 {
894   GimpColorProfile *new_profile;
895   cmsHPROFILE       target_profile;
896   GimpMatrix3       matrix = { { { 0, } } };
897   cmsCIEXYZ        *whitepoint;
898   cmsToneCurve     *curve;
899 
900   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
901 
902   if (gimp_color_profile_is_rgb (profile))
903     {
904       if (! gimp_color_profile_get_rgb_matrix_colorants (profile, &matrix))
905         return NULL;
906     }
907   else if (! gimp_color_profile_is_gray (profile))
908     {
909       return NULL;
910     }
911 
912   whitepoint = cmsReadTag (profile->priv->lcms_profile,
913                            cmsSigMediaWhitePointTag);
914 
915   target_profile = cmsCreateProfilePlaceholder (0);
916 
917   cmsSetProfileVersion (target_profile, 4.3);
918   cmsSetDeviceClass (target_profile, cmsSigDisplayClass);
919   cmsSetPCS (target_profile, cmsSigXYZData);
920 
921   cmsWriteTag (target_profile, cmsSigMediaWhitePointTag, whitepoint);
922 
923   if (linear)
924     {
925       /* linear light */
926       curve = cmsBuildGamma (NULL, 1.00);
927 
928       gimp_color_profile_make_tag (target_profile, cmsSigProfileDescriptionTag,
929                                    "linear TRC from unnamed profile",
930                                    "linear TRC from ",
931                                    "sRGB TRC from ",
932                                    gimp_color_profile_get_description (profile));
933     }
934   else
935     {
936       cmsFloat64Number srgb_parameters[5] =
937         { 2.4, 1.0 / 1.055,  0.055 / 1.055, 1.0 / 12.92, 0.04045 };
938 
939       /* sRGB curve */
940       curve = cmsBuildParametricToneCurve (NULL, 4, srgb_parameters);
941 
942       gimp_color_profile_make_tag (target_profile, cmsSigProfileDescriptionTag,
943                                    "sRGB TRC from unnamed profile",
944                                    "sRGB TRC from ",
945                                    "linear TRC from ",
946                                    gimp_color_profile_get_description (profile));
947     }
948 
949   if (gimp_color_profile_is_rgb (profile))
950     {
951       cmsCIEXYZ red;
952       cmsCIEXYZ green;
953       cmsCIEXYZ blue;
954 
955       cmsSetColorSpace (target_profile, cmsSigRgbData);
956 
957       red.X = matrix.coeff[0][0];
958       red.Y = matrix.coeff[0][1];
959       red.Z = matrix.coeff[0][2];
960 
961       green.X = matrix.coeff[1][0];
962       green.Y = matrix.coeff[1][1];
963       green.Z = matrix.coeff[1][2];
964 
965       blue.X = matrix.coeff[2][0];
966       blue.Y = matrix.coeff[2][1];
967       blue.Z = matrix.coeff[2][2];
968 
969       cmsWriteTag (target_profile, cmsSigRedColorantTag,   &red);
970       cmsWriteTag (target_profile, cmsSigGreenColorantTag, &green);
971       cmsWriteTag (target_profile, cmsSigBlueColorantTag,  &blue);
972 
973       cmsWriteTag (target_profile, cmsSigRedTRCTag,   curve);
974       cmsWriteTag (target_profile, cmsSigGreenTRCTag, curve);
975       cmsWriteTag (target_profile, cmsSigBlueTRCTag,  curve);
976     }
977   else
978     {
979       cmsSetColorSpace (target_profile, cmsSigGrayData);
980 
981       cmsWriteTag (target_profile, cmsSigGrayTRCTag, curve);
982     }
983 
984   cmsFreeToneCurve (curve);
985 
986   gimp_color_profile_make_tag (target_profile, cmsSigDeviceMfgDescTag,
987                                "GIMP",
988                                "GIMP from ", NULL,
989                                gimp_color_profile_get_manufacturer (profile));
990   gimp_color_profile_make_tag (target_profile, cmsSigDeviceModelDescTag,
991                                "Generated by GIMP",
992                                "GIMP from ", NULL,
993                                gimp_color_profile_get_model (profile));
994   gimp_color_profile_make_tag (target_profile, cmsSigCopyrightTag,
995                                "Public Domain",
996                                "GIMP from ", NULL,
997                                gimp_color_profile_get_copyright (profile));
998 
999   new_profile = gimp_color_profile_new_from_lcms_profile (target_profile, NULL);
1000 
1001   cmsCloseProfile (target_profile);
1002 
1003   return new_profile;
1004 }
1005 
1006 /**
1007  * gimp_color_profile_new_srgb_trc_from_color_profile:
1008  * @profile: a #GimpColorProfile
1009  *
1010  * This function creates a new RGB #GimpColorProfile with a sRGB gamma
1011  * TRC and @profile's RGB chromacities and whitepoint.
1012  *
1013  * Return value: the new #GimpColorProfile, or %NULL if @profile is not
1014  *               an RGB profile or not matrix-based.
1015  *
1016  * Since: 2.10
1017  **/
1018 GimpColorProfile *
gimp_color_profile_new_srgb_trc_from_color_profile(GimpColorProfile * profile)1019 gimp_color_profile_new_srgb_trc_from_color_profile (GimpColorProfile *profile)
1020 {
1021   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
1022 
1023   return gimp_color_profile_new_from_color_profile (profile, FALSE);
1024 }
1025 
1026 /**
1027  * gimp_color_profile_new_linear_from_color_profile:
1028  * @profile: a #GimpColorProfile
1029  *
1030  * This function creates a new RGB #GimpColorProfile with a linear TRC
1031  * and @profile's RGB chromacities and whitepoint.
1032  *
1033  * Return value: the new #GimpColorProfile, or %NULL if @profile is not
1034  *               an RGB profile or not matrix-based.
1035  *
1036  * Since: 2.10
1037  **/
1038 GimpColorProfile *
gimp_color_profile_new_linear_from_color_profile(GimpColorProfile * profile)1039 gimp_color_profile_new_linear_from_color_profile (GimpColorProfile *profile)
1040 {
1041   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
1042 
1043   return gimp_color_profile_new_from_color_profile (profile, TRUE);
1044 }
1045 
1046 static cmsHPROFILE *
gimp_color_profile_new_rgb_srgb_internal(void)1047 gimp_color_profile_new_rgb_srgb_internal (void)
1048 {
1049   cmsHPROFILE profile;
1050 
1051   /* white point is D65 from the sRGB specs */
1052   cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
1053 
1054   /* primaries are ITU‐R BT.709‐5 (xYY), which are also the primaries
1055    * from the sRGB specs, modified to properly account for hexadecimal
1056    * quantization during the profile making process.
1057    */
1058   cmsCIExyYTRIPLE primaries =
1059     {
1060       /* R { 0.6400, 0.3300, 1.0 }, */
1061       /* G { 0.3000, 0.6000, 1.0 }, */
1062       /* B { 0.1500, 0.0600, 1.0 }  */
1063       /* R */ { 0.639998686, 0.330010138, 1.0 },
1064       /* G */ { 0.300003784, 0.600003357, 1.0 },
1065       /* B */ { 0.150002046, 0.059997204, 1.0 }
1066     };
1067 
1068   cmsFloat64Number srgb_parameters[5] =
1069     { 2.4, 1.0 / 1.055,  0.055 / 1.055, 1.0 / 12.92, 0.04045 };
1070 
1071   cmsToneCurve *curve[3];
1072 
1073   /* sRGB curve */
1074   curve[0] = curve[1] = curve[2] = cmsBuildParametricToneCurve (NULL, 4,
1075                                                                 srgb_parameters);
1076 
1077   profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
1078 
1079   cmsFreeToneCurve (curve[0]);
1080 
1081   gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
1082                               "GIMP built-in sRGB");
1083   gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
1084                               "GIMP");
1085   gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
1086                               "sRGB");
1087   gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
1088                               "Public Domain");
1089 
1090   /* The following line produces a V2 profile with a point curve TRC.
1091    * Profiles with point curve TRCs can't be used in LCMS2 unbounded
1092    * mode ICC profile conversions. A V2 profile might be appropriate
1093    * for embedding in sRGB images saved to disk, if the image is to be
1094    * opened by an image editing application that doesn't understand V4
1095    * profiles.
1096    *
1097    * cmsSetProfileVersion (srgb_profile, 2.1);
1098    */
1099 
1100   return profile;
1101 }
1102 
1103 /**
1104  * gimp_color_profile_new_rgb_srgb:
1105  *
1106  * This function is a replacement for cmsCreate_sRGBProfile() and
1107  * returns an sRGB profile that is functionally the same as the
1108  * ArgyllCMS sRGB.icm profile. "Functionally the same" means it has
1109  * the same red, green, and blue colorants and the V4 "chad"
1110  * equivalent of the ArgyllCMS V2 white point. The profile TRC is also
1111  * functionally equivalent to the ArgyllCMS sRGB.icm TRC and is the
1112  * same as the LCMS sRGB built-in profile TRC.
1113  *
1114  * The actual primaries in the sRGB specification are
1115  * red xy:   {0.6400, 0.3300, 1.0}
1116  * green xy: {0.3000, 0.6000, 1.0}
1117  * blue xy:  {0.1500, 0.0600, 1.0}
1118  *
1119  * The sRGB primaries given below are "pre-quantized" to compensate
1120  * for hexadecimal quantization during the profile-making process.
1121  * Unless the profile-making code compensates for this quantization,
1122  * the resulting profile's red, green, and blue colorants will deviate
1123  * slightly from the correct XYZ values.
1124  *
1125  * LCMS2 doesn't compensate for hexadecimal quantization. The
1126  * "pre-quantized" primaries below were back-calculated from the
1127  * ArgyllCMS sRGB.icm profile. The resulting sRGB profile's colorants
1128  * exactly matches the ArgyllCMS sRGB.icm profile colorants.
1129  *
1130  * Return value: the sRGB #GimpColorProfile.
1131  *
1132  * Since: 2.10
1133  **/
1134 GimpColorProfile *
gimp_color_profile_new_rgb_srgb(void)1135 gimp_color_profile_new_rgb_srgb (void)
1136 {
1137   static GimpColorProfile *profile = NULL;
1138 
1139   const guint8 *data;
1140   gsize         length;
1141 
1142   if (G_UNLIKELY (profile == NULL))
1143     {
1144       cmsHPROFILE lcms_profile = gimp_color_profile_new_rgb_srgb_internal ();
1145 
1146       profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
1147 
1148       cmsCloseProfile (lcms_profile);
1149     }
1150 
1151   data = gimp_color_profile_get_icc_profile (profile, &length);
1152 
1153   return gimp_color_profile_new_from_icc_profile (data, length, NULL);
1154 }
1155 
1156 static cmsHPROFILE
gimp_color_profile_new_rgb_srgb_linear_internal(void)1157 gimp_color_profile_new_rgb_srgb_linear_internal (void)
1158 {
1159   cmsHPROFILE profile;
1160 
1161   /* white point is D65 from the sRGB specs */
1162   cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
1163 
1164   /* primaries are ITU‐R BT.709‐5 (xYY), which are also the primaries
1165    * from the sRGB specs, modified to properly account for hexadecimal
1166    * quantization during the profile making process.
1167    */
1168   cmsCIExyYTRIPLE primaries =
1169     {
1170       /* R { 0.6400, 0.3300, 1.0 }, */
1171       /* G { 0.3000, 0.6000, 1.0 }, */
1172       /* B { 0.1500, 0.0600, 1.0 }  */
1173       /* R */ { 0.639998686, 0.330010138, 1.0 },
1174       /* G */ { 0.300003784, 0.600003357, 1.0 },
1175       /* B */ { 0.150002046, 0.059997204, 1.0 }
1176     };
1177 
1178   cmsToneCurve *curve[3];
1179 
1180   /* linear light */
1181   curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 1.0);
1182 
1183   profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
1184 
1185   cmsFreeToneCurve (curve[0]);
1186 
1187   gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
1188                               "GIMP built-in Linear sRGB");
1189   gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
1190                               "GIMP");
1191   gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
1192                               "Linear sRGB");
1193   gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
1194                               "Public Domain");
1195 
1196   return profile;
1197 }
1198 
1199 /**
1200  * gimp_color_profile_new_rgb_srgb_linear:
1201  *
1202  * This function creates a profile for babl_model("RGB"). Please
1203  * somebody write something smarter here.
1204  *
1205  * Return value: the linear RGB #GimpColorProfile.
1206  *
1207  * Since: 2.10
1208  **/
1209 GimpColorProfile *
gimp_color_profile_new_rgb_srgb_linear(void)1210 gimp_color_profile_new_rgb_srgb_linear (void)
1211 {
1212   static GimpColorProfile *profile = NULL;
1213 
1214   const guint8 *data;
1215   gsize         length;
1216 
1217   if (G_UNLIKELY (profile == NULL))
1218     {
1219       cmsHPROFILE lcms_profile = gimp_color_profile_new_rgb_srgb_linear_internal ();
1220 
1221       profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
1222 
1223       cmsCloseProfile (lcms_profile);
1224     }
1225 
1226   data = gimp_color_profile_get_icc_profile (profile, &length);
1227 
1228   return gimp_color_profile_new_from_icc_profile (data, length, NULL);
1229 }
1230 
1231 static cmsHPROFILE *
gimp_color_profile_new_rgb_adobe_internal(void)1232 gimp_color_profile_new_rgb_adobe_internal (void)
1233 {
1234   cmsHPROFILE profile;
1235 
1236   /* white point is D65 from the sRGB specs */
1237   cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
1238 
1239   /* AdobeRGB1998 and sRGB have the same white point.
1240    *
1241    * The primaries below are technically correct, but because of
1242    * hexadecimal rounding these primaries don't make a profile that
1243    * matches the original.
1244    *
1245    *  cmsCIExyYTRIPLE primaries = {
1246    *    { 0.6400, 0.3300, 1.0 },
1247    *    { 0.2100, 0.7100, 1.0 },
1248    *    { 0.1500, 0.0600, 1.0 }
1249    *  };
1250    */
1251   cmsCIExyYTRIPLE primaries =
1252     {
1253       { 0.639996511, 0.329996864, 1.0 },
1254       { 0.210005295, 0.710004866, 1.0 },
1255       { 0.149997606, 0.060003644, 1.0 }
1256     };
1257 
1258   cmsToneCurve *curve[3];
1259 
1260   /* gamma 2.2 */
1261   curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 2.19921875);
1262 
1263   profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
1264 
1265   cmsFreeToneCurve (curve[0]);
1266 
1267   gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
1268                               "Compatible with Adobe RGB (1998)");
1269   gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
1270                               "GIMP");
1271   gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
1272                               "Compatible with Adobe RGB (1998)");
1273   gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
1274                               "Public Domain");
1275 
1276   return profile;
1277 }
1278 
1279 /**
1280  * gimp_color_profile_new_rgb_adobe:
1281  *
1282  * This function creates a profile compatible with AbobeRGB (1998).
1283  *
1284  * Return value: the AdobeRGB-compatible #GimpColorProfile.
1285  *
1286  * Since: 2.10
1287  **/
1288 GimpColorProfile *
gimp_color_profile_new_rgb_adobe(void)1289 gimp_color_profile_new_rgb_adobe (void)
1290 {
1291   static GimpColorProfile *profile = NULL;
1292 
1293   const guint8 *data;
1294   gsize         length;
1295 
1296   if (G_UNLIKELY (profile == NULL))
1297     {
1298       cmsHPROFILE lcms_profile = gimp_color_profile_new_rgb_adobe_internal ();
1299 
1300       profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
1301 
1302       cmsCloseProfile (lcms_profile);
1303     }
1304 
1305   data = gimp_color_profile_get_icc_profile (profile, &length);
1306 
1307   return gimp_color_profile_new_from_icc_profile (data, length, NULL);
1308 }
1309 
1310 static cmsHPROFILE *
gimp_color_profile_new_d65_gray_srgb_trc_internal(void)1311 gimp_color_profile_new_d65_gray_srgb_trc_internal (void)
1312 {
1313   cmsHPROFILE profile;
1314 
1315   /* white point is D65 from the sRGB specs */
1316   cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
1317 
1318   cmsFloat64Number srgb_parameters[5] =
1319     { 2.4, 1.0 / 1.055,  0.055 / 1.055, 1.0 / 12.92, 0.04045 };
1320 
1321   cmsToneCurve *curve = cmsBuildParametricToneCurve (NULL, 4,
1322                                                      srgb_parameters);
1323 
1324   profile = cmsCreateGrayProfile (&whitepoint, curve);
1325 
1326   cmsFreeToneCurve (curve);
1327 
1328   gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
1329                               "GIMP built-in D65 Grayscale with sRGB TRC");
1330   gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
1331                               "GIMP");
1332   gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
1333                               "D65 Grayscale with sRGB TRC");
1334   gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
1335                               "Public Domain");
1336 
1337   return profile;
1338 }
1339 
1340 /**
1341  * gimp_color_profile_new_d65_gray_srgb_trc
1342  *
1343  * This function creates a grayscale #GimpColorProfile with an
1344  * sRGB TRC. See gimp_color_profile_new_rgb_srgb().
1345  *
1346  * Return value: the sRGB-gamma grayscale #GimpColorProfile.
1347  *
1348  * Since: 2.10
1349  **/
1350 GimpColorProfile *
gimp_color_profile_new_d65_gray_srgb_trc(void)1351 gimp_color_profile_new_d65_gray_srgb_trc (void)
1352 {
1353   static GimpColorProfile *profile = NULL;
1354 
1355   const guint8 *data;
1356   gsize         length;
1357 
1358   if (G_UNLIKELY (profile == NULL))
1359     {
1360       cmsHPROFILE lcms_profile = gimp_color_profile_new_d65_gray_srgb_trc_internal ();
1361 
1362       profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
1363 
1364       cmsCloseProfile (lcms_profile);
1365     }
1366 
1367   data = gimp_color_profile_get_icc_profile (profile, &length);
1368 
1369   return gimp_color_profile_new_from_icc_profile (data, length, NULL);
1370 }
1371 
1372 static cmsHPROFILE
gimp_color_profile_new_d65_gray_linear_internal(void)1373 gimp_color_profile_new_d65_gray_linear_internal (void)
1374 {
1375   cmsHPROFILE profile;
1376 
1377   /* white point is D65 from the sRGB specs */
1378   cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
1379 
1380   cmsToneCurve *curve = cmsBuildGamma (NULL, 1.0);
1381 
1382   profile = cmsCreateGrayProfile (&whitepoint, curve);
1383 
1384   cmsFreeToneCurve (curve);
1385 
1386   gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
1387                               "GIMP built-in D65 Linear Grayscale");
1388   gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
1389                               "GIMP");
1390   gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
1391                               "D65 Linear Grayscale");
1392   gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
1393                               "Public Domain");
1394 
1395   return profile;
1396 }
1397 
1398 /**
1399  * gimp_color_profile_new_d65_gray_srgb_gray:
1400  *
1401  * This function creates a profile for babl_model("Y"). Please
1402  * somebody write something smarter here.
1403  *
1404  * Return value: the linear grayscale #GimpColorProfile.
1405  *
1406  * Since: 2.10
1407  **/
1408 GimpColorProfile *
gimp_color_profile_new_d65_gray_linear(void)1409 gimp_color_profile_new_d65_gray_linear (void)
1410 {
1411   static GimpColorProfile *profile = NULL;
1412 
1413   const guint8 *data;
1414   gsize         length;
1415 
1416   if (G_UNLIKELY (profile == NULL))
1417     {
1418       cmsHPROFILE lcms_profile = gimp_color_profile_new_d65_gray_linear_internal ();
1419 
1420       profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
1421 
1422       cmsCloseProfile (lcms_profile);
1423     }
1424 
1425   data = gimp_color_profile_get_icc_profile (profile, &length);
1426 
1427   return gimp_color_profile_new_from_icc_profile (data, length, NULL);
1428 }
1429 
1430 static cmsHPROFILE *
gimp_color_profile_new_d50_gray_lab_trc_internal(void)1431 gimp_color_profile_new_d50_gray_lab_trc_internal (void)
1432 {
1433   cmsHPROFILE profile;
1434 
1435   /* white point is D50 from the ICC profile illuminant specs */
1436   cmsCIExyY whitepoint = {0.345702915, 0.358538597, 1.0};
1437 
1438   cmsFloat64Number lab_parameters[5] =
1439     { 3.0, 1.0 / 1.16,  0.16 / 1.16, 2700.0 / 24389.0, 0.08000  };
1440 
1441   cmsToneCurve *curve = cmsBuildParametricToneCurve (NULL, 4,
1442                                                      lab_parameters);
1443 
1444   profile = cmsCreateGrayProfile (&whitepoint, curve);
1445 
1446   cmsFreeToneCurve (curve);
1447 
1448   gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
1449                               "GIMP built-in D50 Grayscale with LAB L TRC");
1450   gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
1451                               "GIMP");
1452   gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
1453                               "D50 Grayscale with LAB L TRC");
1454   gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
1455                               "Public Domain");
1456 
1457   return profile;
1458 }
1459 
1460 
1461 /**
1462  * gimp_color_profile_new_d50_gray_lab_trc
1463  *
1464  * This function creates a grayscale #GimpColorProfile with the
1465  * D50 ICC profile illuminant as the profile white point and the
1466  * LAB companding curve as the TRC.
1467  *
1468  * Return value: a gray profile with the D50 ICC profile illuminant
1469  * as the profile white point and the LAB companding curve as the TRC.
1470  * as the TRC.
1471  *
1472  * Since: 2.10
1473  **/
1474 GimpColorProfile *
gimp_color_profile_new_d50_gray_lab_trc(void)1475 gimp_color_profile_new_d50_gray_lab_trc (void)
1476 {
1477   static GimpColorProfile *profile = NULL;
1478 
1479   const guint8 *data;
1480   gsize         length;
1481 
1482   if (G_UNLIKELY (profile == NULL))
1483     {
1484       cmsHPROFILE lcms_profile = gimp_color_profile_new_d50_gray_lab_trc_internal ();
1485 
1486       profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
1487 
1488       cmsCloseProfile (lcms_profile);
1489     }
1490 
1491   data = gimp_color_profile_get_icc_profile (profile, &length);
1492 
1493   return gimp_color_profile_new_from_icc_profile (data, length, NULL);
1494 }
1495 
1496 /**
1497  * gimp_color_profile_get_space:
1498  * @profile: a #GimpColorProfile
1499  * @intent:  a #GimpColorRenderingIntent
1500  * @error:   return location for #GError
1501  *
1502  * This function returns the #Babl space of @profile, for the
1503  * specified @intent.
1504  *
1505  * Return value: the new #Babl space.
1506  *
1507  * Since: 2.10.6
1508  **/
1509 const Babl *
gimp_color_profile_get_space(GimpColorProfile * profile,GimpColorRenderingIntent intent,GError ** error)1510 gimp_color_profile_get_space (GimpColorProfile          *profile,
1511                               GimpColorRenderingIntent   intent,
1512                               GError                   **error)
1513 {
1514   const Babl  *space;
1515   const gchar *babl_error = NULL;
1516 
1517   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
1518   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1519 
1520   space = babl_icc_make_space ((const gchar *) profile->priv->data,
1521                                profile->priv->length,
1522                                (BablIccIntent) intent,
1523                                &babl_error);
1524 
1525   if (! space)
1526     g_set_error (error, GIMP_COLOR_PROFILE_ERROR, 0,
1527                  "%s: %s",
1528                  gimp_color_profile_get_label (profile), babl_error);
1529 
1530   return space;
1531 }
1532 
1533 /**
1534  * gimp_color_profile_get_format:
1535  * @profile: a #GimpColorProfile
1536  * @format:  a #Babl format
1537  * @intent:  a #GimpColorRenderingIntent
1538  * @error:   return location for #GError
1539  *
1540  * This function takes a #GimpColorProfile and a #Babl format and
1541  * returns a new #Babl format with @profile's RGB primaries and TRC,
1542  * and @format's pixel layout.
1543  *
1544  * Return value: the new #Babl format.
1545  *
1546  * Since: 2.10
1547  **/
1548 const Babl *
gimp_color_profile_get_format(GimpColorProfile * profile,const Babl * format,GimpColorRenderingIntent intent,GError ** error)1549 gimp_color_profile_get_format (GimpColorProfile          *profile,
1550                                const Babl                *format,
1551                                GimpColorRenderingIntent   intent,
1552                                GError                   **error)
1553 {
1554   const Babl *space;
1555 
1556   g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
1557   g_return_val_if_fail (format != NULL, NULL);
1558   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1559 
1560   space = gimp_color_profile_get_space (profile, intent, error);
1561 
1562   if (! space)
1563     return NULL;
1564 
1565   return babl_format_with_space (babl_get_name (format), space);
1566 }
1567 
1568 /**
1569  * gimp_color_profile_get_lcms_format:
1570  * @format:      a #Babl format
1571  * @lcms_format: return location for an lcms format
1572  *
1573  * This function takes a #Babl format and returns the lcms format to
1574  * be used with that @format. It also returns a #Babl format to be
1575  * used instead of the passed @format, which usually is the same as
1576  * @format, unless lcms doesn't support @format.
1577  *
1578  * Note that this function currently only supports RGB, RGBA, R'G'B',
1579  * R'G'B'A, Y, YA, Y', Y'A and the cairo-RGB24 and cairo-ARGB32 formats.
1580  *
1581  * Return value: the #Babl format to be used instead of @format, or %NULL
1582  *               if the passed @format is not supported at all.
1583  *
1584  * Since: 2.10
1585  **/
1586 const Babl *
gimp_color_profile_get_lcms_format(const Babl * format,guint32 * lcms_format)1587 gimp_color_profile_get_lcms_format (const Babl *format,
1588                                     guint32    *lcms_format)
1589 {
1590   const Babl *output_format = NULL;
1591   const Babl *type;
1592   const Babl *model;
1593   gboolean    has_alpha;
1594   gboolean    rgb    = FALSE;
1595   gboolean    gray   = FALSE;
1596   gboolean    cmyk   = FALSE;
1597   gboolean    linear = FALSE;
1598 
1599   g_return_val_if_fail (format != NULL, NULL);
1600   g_return_val_if_fail (lcms_format != NULL, NULL);
1601 
1602   has_alpha = babl_format_has_alpha (format);
1603   type      = babl_format_get_type (format, 0);
1604   model     = babl_format_get_model (format);
1605 
1606   if (format == babl_format ("cairo-RGB24"))
1607     {
1608 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1609       *lcms_format = TYPE_BGRA_8;
1610 #else
1611       *lcms_format = TYPE_ARGB_8;
1612 #endif
1613 
1614       return format;
1615     }
1616   else if (format == babl_format ("cairo-ARGB32"))
1617     {
1618       rgb = TRUE;
1619     }
1620   else if (model == babl_model ("RGB")  ||
1621            model == babl_model ("RGBA") ||
1622            model == babl_model ("RaGaBaA"))
1623     {
1624       rgb    = TRUE;
1625       linear = TRUE;
1626     }
1627   else if (model == babl_model ("R'G'B'")  ||
1628            model == babl_model ("R'G'B'A") ||
1629            model == babl_model ("R'aG'aB'aA"))
1630     {
1631       rgb = TRUE;
1632     }
1633   else if (model == babl_model ("Y")  ||
1634            model == babl_model ("YA") ||
1635            model == babl_model ("YaA"))
1636     {
1637       gray   = TRUE;
1638       linear = TRUE;
1639     }
1640   else if (model == babl_model ("Y'")  ||
1641            model == babl_model ("Y'A") ||
1642            model == babl_model ("Y'aA"))
1643     {
1644       gray = TRUE;
1645     }
1646   else if (model == babl_model ("CMYK"))
1647 #if 0
1648     /* FIXME missing from babl */
1649            || model == babl_model ("CMYKA"))
1650 #endif
1651     {
1652       cmyk = TRUE;
1653     }
1654   else if (model == babl_model ("CIE Lab")       ||
1655            model == babl_model ("CIE Lab alpha") ||
1656            model == babl_model ("CIE LCH(ab)")   ||
1657            model == babl_model ("CIE LCH(ab) alpha"))
1658     {
1659       if (has_alpha)
1660         {
1661           *lcms_format = TYPE_RGBA_FLT;
1662 
1663           return babl_format ("RGBA float");
1664         }
1665       else
1666         {
1667           *lcms_format = TYPE_RGB_FLT;
1668 
1669           return babl_format ("RGB float");
1670         }
1671     }
1672   else if (babl_format_is_palette (format))
1673     {
1674       if (has_alpha)
1675         {
1676           *lcms_format = TYPE_RGBA_8;
1677 
1678           return babl_format ("R'G'B'A u8");
1679         }
1680       else
1681         {
1682           *lcms_format = TYPE_RGB_8;
1683 
1684           return babl_format ("R'G'B' u8");
1685         }
1686     }
1687   else
1688     {
1689       g_printerr ("format not supported: %s\n"
1690                   "has_alpha = %s\n"
1691                   "type = %s\n"
1692                   "model = %s\n",
1693                   babl_get_name (format),
1694                   has_alpha ? "TRUE" : "FALSE",
1695                   babl_get_name (type),
1696                   babl_get_name (model));
1697       g_return_val_if_reached (NULL);
1698     }
1699 
1700   *lcms_format = 0;
1701 
1702   #define FIND_FORMAT_FOR_TYPE(babl_t, lcms_t)                                 \
1703     do                                                                         \
1704       {                                                                        \
1705         if (has_alpha)                                                         \
1706           {                                                                    \
1707             if (rgb)                                                           \
1708               {                                                                \
1709                 *lcms_format = TYPE_RGBA_##lcms_t;                             \
1710                                                                                \
1711                 if (linear)                                                    \
1712                   output_format = babl_format ("RGBA " babl_t);                \
1713                 else                                                           \
1714                   output_format = babl_format ("R'G'B'A " babl_t);             \
1715               }                                                                \
1716             else if (gray)                                                     \
1717               {                                                                \
1718                 *lcms_format = TYPE_GRAYA_##lcms_t;                            \
1719                                                                                \
1720                 if (linear)                                                    \
1721                   output_format = babl_format ("YA " babl_t);                  \
1722                 else                                                           \
1723                   output_format = babl_format ("Y'A " babl_t);                 \
1724               }                                                                \
1725             else if (cmyk)                                                     \
1726               {                                                                \
1727                 *lcms_format = TYPE_CMYKA_##lcms_t;                            \
1728                                                                                \
1729                 output_format = format;                                        \
1730               }                                                                \
1731           }                                                                    \
1732         else                                                                   \
1733           {                                                                    \
1734             if (rgb)                                                           \
1735               {                                                                \
1736                 *lcms_format = TYPE_RGB_##lcms_t;                              \
1737                                                                                \
1738                 if (linear)                                                    \
1739                   output_format = babl_format ("RGB " babl_t);                 \
1740                 else                                                           \
1741                   output_format = babl_format ("R'G'B' " babl_t);              \
1742               }                                                                \
1743             else if (gray)                                                     \
1744               {                                                                \
1745                 *lcms_format = TYPE_GRAY_##lcms_t;                             \
1746                                                                                \
1747                 if (linear)                                                    \
1748                   output_format = babl_format ("Y " babl_t);                   \
1749                 else                                                           \
1750                   output_format = babl_format ("Y' " babl_t);                  \
1751               }                                                                \
1752             else if (cmyk)                                                     \
1753               {                                                                \
1754                 *lcms_format = TYPE_CMYK_##lcms_t;                             \
1755                                                                                \
1756                 output_format = format;                                        \
1757               }                                                                \
1758           }                                                                    \
1759       }                                                                        \
1760     while (FALSE)
1761 
1762   if (type == babl_type ("u8"))
1763     FIND_FORMAT_FOR_TYPE ("u8", 8);
1764   else if (type == babl_type ("u16"))
1765     FIND_FORMAT_FOR_TYPE ("u16", 16);
1766   else if (type == babl_type ("half")) /* 16-bit floating point (half) */
1767     FIND_FORMAT_FOR_TYPE ("half", HALF_FLT);
1768   else if (type == babl_type ("float"))
1769     FIND_FORMAT_FOR_TYPE ("float", FLT);
1770   else if (type == babl_type ("double"))
1771     FIND_FORMAT_FOR_TYPE ("double", DBL);
1772 
1773   if (*lcms_format == 0)
1774     {
1775       g_printerr ("%s: format %s not supported, "
1776                   "falling back to float\n",
1777                   G_STRFUNC, babl_get_name (format));
1778 
1779       rgb = ! gray;
1780 
1781       FIND_FORMAT_FOR_TYPE ("float", FLT);
1782 
1783       g_return_val_if_fail (output_format != NULL, NULL);
1784     }
1785 
1786   #undef FIND_FORMAT_FOR_TYPE
1787 
1788   return output_format;
1789 }
1790