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