cdisplay_lcms.c 17.5 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

21 22
#include <glib.h>  /* lcms.h uses the "inline" keyword */

23
#ifdef G_OS_WIN32
24
#define STRICT
25
#include <windows.h>
26
#define LCMS_WIN_TYPES_ALREADY_DEFINED
27 28
#endif

29
#ifdef HAVE_LCMS_LCMS_H
30 31 32 33 34 35 36
#include <lcms/lcms.h>
#else
#include <lcms.h>
#endif

#include <gtk/gtk.h>

37
#include "libgimpcolor/gimpcolor.h"
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
#include "libgimpconfig/gimpconfig.h"
#include "libgimpmath/gimpmath.h"
#include "libgimpmodule/gimpmodule.h"
#include "libgimpwidgets/gimpwidgets.h"

#include "libgimp/libgimp-intl.h"


#define CDISPLAY_TYPE_LCMS            (cdisplay_lcms_type)
#define CDISPLAY_LCMS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CDISPLAY_TYPE_LCMS, CdisplayLcms))
#define CDISPLAY_LCMS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CDISPLAY_TYPE_LCMS, CdisplayLcmsClass))
#define CDISPLAY_IS_LCMS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CDISPLAY_TYPE_LCMS))
#define CDISPLAY_IS_LCMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CDISPLAY_TYPE_LCMS))


typedef struct _CdisplayLcms CdisplayLcms;
typedef struct _CdisplayLcmsClass CdisplayLcmsClass;

struct _CdisplayLcms
{
  GimpColorDisplay  parent_instance;

  cmsHTRANSFORM     transform;
};

struct _CdisplayLcmsClass
{
  GimpColorDisplayClass parent_instance;
};


69 70 71
static GType     cdisplay_lcms_get_type     (GTypeModule       *module);
static void      cdisplay_lcms_class_init   (CdisplayLcmsClass *klass);
static void      cdisplay_lcms_init         (CdisplayLcms      *lcms);
72
static void      cdisplay_lcms_finalize     (GObject           *object);
73 74 75 76 77 78 79 80 81

static GtkWidget * cdisplay_lcms_configure  (GimpColorDisplay  *display);
static void        cdisplay_lcms_convert    (GimpColorDisplay  *display,
                                             guchar            *buf,
                                             gint               width,
                                             gint               height,
                                             gint               bpp,
                                             gint               bpl);
static void        cdisplay_lcms_changed    (GimpColorDisplay  *display);
82

83 84 85
static cmsHPROFILE  cdisplay_lcms_get_rgb_profile     (CdisplayLcms *lcms);
static cmsHPROFILE  cdisplay_lcms_get_display_profile (CdisplayLcms *lcms);
static cmsHPROFILE  cdisplay_lcms_get_printer_profile (CdisplayLcms *lcms);
86

87 88 89
static void         cdisplay_lcms_attach_labelled (GtkTable    *table,
                                                   gint         row,
                                                   const gchar *text,
90
                                                   GtkWidget   *widget,
91 92 93
                                                   gboolean     tooltip);
static void         cdisplay_lcms_label_set_text  (GtkLabel    *label,
                                                   const gchar *text,
94
                                                   const gchar *tooltip);
95 96 97 98 99 100
static void         cdisplay_lcms_update_profile_label (CdisplayLcms *lcms,
                                                        const gchar  *name);
static void         cdisplay_lcms_notify_profile       (GObject      *config,
                                                        GParamSpec   *pspec,
                                                        CdisplayLcms *lcms);

101 102 103 104 105 106

static const GimpModuleInfo cdisplay_lcms_info =
{
  GIMP_MODULE_ABI_VERSION,
  N_("Color management display filter using ICC color profiles"),
  "Sven Neumann",
107 108 109
  "v0.2",
  "(c) 2005 - 2007, released under the GPL",
  "2005 - 2007"
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
};

static GType                  cdisplay_lcms_type = 0;
static GimpColorDisplayClass *parent_class       = NULL;


G_MODULE_EXPORT const GimpModuleInfo *
gimp_module_query (GTypeModule *module)
{
  return &cdisplay_lcms_info;
}

G_MODULE_EXPORT gboolean
gimp_module_register (GTypeModule *module)
{
  cdisplay_lcms_get_type (module);

  return TRUE;
}

static GType
cdisplay_lcms_get_type (GTypeModule *module)
{
  if (! cdisplay_lcms_type)
    {
135
      const GTypeInfo display_info =
136 137 138 139 140
      {
        sizeof (CdisplayLcmsClass),
        (GBaseInitFunc)     NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) cdisplay_lcms_class_init,
141 142
        NULL,                   /* class_finalize */
        NULL,                   /* class_data     */
143
        sizeof (CdisplayLcms),
144
        0,                      /* n_preallocs    */
145 146 147 148
        (GInstanceInitFunc) cdisplay_lcms_init,
      };

       cdisplay_lcms_type =
149 150
        g_type_module_register_type (module, GIMP_TYPE_COLOR_DISPLAY,
                                     "CdisplayLcms", &display_info, 0);
151 152 153 154 155 156 157 158 159 160 161 162 163
    }

  return cdisplay_lcms_type;
}

static void
cdisplay_lcms_class_init (CdisplayLcmsClass *klass)
{
  GObjectClass          *object_class  = G_OBJECT_CLASS (klass);
  GimpColorDisplayClass *display_class = GIMP_COLOR_DISPLAY_CLASS (klass);

  parent_class = g_type_class_peek_parent (klass);

164
  object_class->finalize = cdisplay_lcms_finalize;
165 166 167

  display_class->name        = _("Color Management");
  display_class->help_id     = "gimp-colordisplay-lcms";
168 169
  display_class->stock_id    = GIMP_STOCK_DISPLAY_FILTER_LCMS;

170
  display_class->configure   = cdisplay_lcms_configure;
171 172 173 174 175 176 177 178 179 180 181 182 183
  display_class->convert     = cdisplay_lcms_convert;
  display_class->changed     = cdisplay_lcms_changed;

  cmsErrorAction (LCMS_ERROR_IGNORE);
}

static void
cdisplay_lcms_init (CdisplayLcms *lcms)
{
  lcms->transform = NULL;
}

static void
184
cdisplay_lcms_finalize (GObject *object)
185 186 187
{
  CdisplayLcms *lcms = CDISPLAY_LCMS (object);

188
  if (lcms->transform)
189
    {
190 191
      cmsDeleteTransform (lcms->transform);
      lcms->transform = NULL;
192 193
    }

194
  G_OBJECT_CLASS (parent_class)->finalize (object);
195 196
}

197 198 199 200
static void
cdisplay_lcms_profile_get_info (cmsHPROFILE   profile,
                                const gchar **name,
                                const gchar **info)
201 202 203
{
  if (profile)
    {
204 205 206
      *name = cmsTakeProductName (profile);
      if (! g_utf8_validate (*name, -1, NULL))
        *name = _("(invalid UTF-8 string)");
207

208 209 210 211 212 213 214 215
      *info = cmsTakeProductInfo (profile);
      if (! g_utf8_validate (*info, -1, NULL))
        *info = NULL;
    }
  else
    {
      *name = _("None");
      *info = NULL;
216 217 218
    }
}

219 220 221
static GtkWidget *
cdisplay_lcms_configure (GimpColorDisplay *display)
{
222
  CdisplayLcms *lcms   = CDISPLAY_LCMS (display);
223
  GObject      *config = G_OBJECT (gimp_color_display_get_config (display));
224
  GtkWidget    *vbox;
225
  GtkWidget    *hint;
226
  GtkWidget    *table;
227
  GtkWidget    *label;
228 229
  gint          row = 0;

230 231 232
  if (! config)
    return NULL;

233 234
  vbox = gtk_vbox_new (FALSE, 12);

235 236 237 238 239
  hint = gimp_hint_box_new (_("This filter takes its configuration "
                              "from the Color Management section "
                              "in the Preferences dialog."));
  gtk_box_pack_start (GTK_BOX (vbox), hint, FALSE, FALSE, 0);
  gtk_widget_show (hint);
240

241
  table = gtk_table_new (5, 2, FALSE);
242
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
243
  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 12);
244 245 246 247
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  gtk_widget_show (table);

248 249
  cdisplay_lcms_attach_labelled (GTK_TABLE (table), row++,
                                 _("Mode of operation:"),
250
                                 gimp_prop_enum_label_new (config, "mode"),
251
                                 FALSE);
252

253 254
  label = gtk_label_new (NULL);
  g_object_set_data (G_OBJECT (lcms), "rgb-profile", label);
255
  cdisplay_lcms_attach_labelled (GTK_TABLE (table), row++,
256
                                 _("Image profile:"),
257 258
                                 label, TRUE);
  cdisplay_lcms_update_profile_label (lcms, "rgb-profile");
259

260 261
  label = gtk_label_new (NULL);
  g_object_set_data (G_OBJECT (lcms), "display-profile", label);
262 263
  cdisplay_lcms_attach_labelled (GTK_TABLE (table), row++,
                                 _("Monitor profile:"),
264 265
                                 label, TRUE);
  cdisplay_lcms_update_profile_label (lcms, "display-profile");
266

267 268
  label = gtk_label_new (NULL);
  g_object_set_data (G_OBJECT (lcms), "printer-profile", label);
269 270
  cdisplay_lcms_attach_labelled (GTK_TABLE (table), row++,
                                 _("Print simulation profile:"),
271 272 273 274 275 276
                                 label, TRUE);
  cdisplay_lcms_update_profile_label (lcms, "printer-profile");

  g_signal_connect_object (config, "notify",
                           G_CALLBACK (cdisplay_lcms_notify_profile),
                           lcms, 0);
277 278

  return vbox;
279 280
}

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
static void
cdisplay_lcms_convert (GimpColorDisplay *display,
                       guchar           *buf,
                       gint              width,
                       gint              height,
                       gint              bpp,
                       gint              bpl)
{
  CdisplayLcms *lcms = CDISPLAY_LCMS (display);
  gint          y;

  if (bpp != 3)
    return;

  if (! lcms->transform)
    return;

  for (y = 0; y < height; y++, buf += bpl)
    cmsDoTransform (lcms->transform, buf, buf, width);
}

static void
cdisplay_lcms_changed (GimpColorDisplay *display)
{
  CdisplayLcms    *lcms   = CDISPLAY_LCMS (display);
306
  GimpColorConfig *config = gimp_color_display_get_config (display);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326

  cmsHPROFILE      src_profile   = NULL;
  cmsHPROFILE      dest_profile  = NULL;
  cmsHPROFILE      proof_profile = NULL;

  if (lcms->transform)
    {
      cmsDeleteTransform (lcms->transform);
      lcms->transform = NULL;
    }

  if (! config)
    return;

  switch (config->mode)
    {
    case GIMP_COLOR_MANAGEMENT_OFF:
      return;

    case GIMP_COLOR_MANAGEMENT_SOFTPROOF:
327
      proof_profile = cdisplay_lcms_get_printer_profile (lcms);
328 329 330
      /*  fallthru  */

    case GIMP_COLOR_MANAGEMENT_DISPLAY:
331 332
      src_profile = cdisplay_lcms_get_rgb_profile (lcms);
      dest_profile = cdisplay_lcms_get_display_profile (lcms);
333 334 335 336 337
      break;
    }

  if (proof_profile)
    {
338 339 340 341 342 343 344 345
      if (! src_profile)
       src_profile = cmsCreate_sRGBProfile ();

      if (! dest_profile)
       dest_profile = cmsCreate_sRGBProfile ();

      lcms->transform = cmsCreateProofingTransform (src_profile,  TYPE_RGB_8,
                                                    dest_profile, TYPE_RGB_8,
346 347
                                                    proof_profile,
                                                    config->simulation_intent,
348
                                                    config->display_intent,
349 350 351
                                                    cmsFLAGS_SOFTPROOFING);
      cmsCloseProfile (proof_profile);
    }
352
  else if (src_profile || dest_profile)
353
    {
354 355 356 357 358 359
      if (! src_profile)
       src_profile = cmsCreate_sRGBProfile ();

      if (! dest_profile)
       dest_profile = cmsCreate_sRGBProfile ();

360 361 362 363 364 365 366 367 368
      lcms->transform = cmsCreateTransform (src_profile,  TYPE_RGB_8,
                                            dest_profile, TYPE_RGB_8,
                                            config->display_intent,
                                            0);
    }

  if (dest_profile)
    cmsCloseProfile (dest_profile);

369 370
  if (src_profile)
    cmsCloseProfile (src_profile);
371 372
}

373 374
static gboolean
cdisplay_lcms_profile_is_rgb (cmsHPROFILE profile)
375
{
376 377
  return (cmsGetColorSpace (profile) == icSigRgbData);
}
378

379 380 381 382 383 384
static cmsHPROFILE
cdisplay_lcms_get_rgb_profile (CdisplayLcms *lcms)
{
  GimpColorConfig  *config;
  GimpColorManaged *managed;
  cmsHPROFILE       profile = NULL;
385

386
  managed = gimp_color_display_get_managed (GIMP_COLOR_DISPLAY (lcms));
387

388
  if (managed)
389
    {
390 391
      gsize         len;
      const guint8 *data = gimp_color_managed_get_icc_profile (managed, &len);
392

393 394
      if (data)
        profile = cmsOpenProfileFromMem ((gpointer) data, len);
395

396 397
      if (profile &&
          ! cdisplay_lcms_profile_is_rgb (profile))
398 399 400 401 402
        {
          cmsCloseProfile (profile);
          profile = NULL;
        }
    }
403

404 405 406
  if (! profile)
    {
      config = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms));
407

408 409 410
      if (config->rgb_profile)
        profile = cmsOpenProfileFromFile (config->rgb_profile, "r");
    }
411

412
  return profile;
413
}
414 415

static cmsHPROFILE
416
cdisplay_lcms_get_display_profile (CdisplayLcms *lcms)
417
{
418 419 420 421
  GimpColorConfig *config;
  cmsHPROFILE      profile = NULL;

  config = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms));
422

423
#if defined (GDK_WINDOWING_X11)
424 425
  if (config->display_profile_from_gdk)
    {
426 427 428 429 430 431 432 433 434 435 436 437 438
      GimpColorManaged *managed;
      GdkScreen        *screen;
      GdkAtom           type   = GDK_NONE;
      gint              format = 0;
      gint              nitems = 0;
      guchar           *data   = NULL;

      managed = gimp_color_display_get_managed (GIMP_COLOR_DISPLAY (lcms));

      if (GTK_IS_WIDGET (managed))
        screen = gtk_widget_get_screen (GTK_WIDGET (managed));
      else
        screen = gdk_screen_get_default ();
439 440 441 442

      g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);

      if (gdk_property_get (gdk_screen_get_root_window (screen),
443 444 445 446
                            gdk_atom_intern ("_ICC_PROFILE", FALSE),
                            GDK_NONE,
                            0, 64 * 1024 * 1024, FALSE,
                            &type, &format, &nitems, &data) && nitems > 0)
447
        {
448
          profile = cmsOpenProfileFromMem (data, nitems);
449 450 451
          g_free (data);
        }
    }
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
#elif defined G_OS_WIN32
  if (config->display_profile_from_gdk)
    {
      HDC hdc = GetDC (NULL);

      if (hdc)
        {
          gchar *path;
          gint32 len = 0;

          GetICMProfile (hdc, &len, NULL);
          path = g_new (gchar, len);

          if (GetICMProfile (hdc, &len, path))
            profile = cmsOpenProfileFromFile (path, "r");

          g_free (path);
          ReleaseDC (NULL, hdc);
        }
    }
472
#endif
473

474
  if (! profile && config->display_profile)
475
    profile = cmsOpenProfileFromFile (config->display_profile, "r");
476

477
  return profile;
478
}
479 480 481 482

static cmsHPROFILE
cdisplay_lcms_get_printer_profile (CdisplayLcms *lcms)
{
483 484 485
  GimpColorConfig *config;

  config = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms));
486 487 488 489 490 491

  if (config->printer_profile)
    return cmsOpenProfileFromFile (config->printer_profile, "r");

  return NULL;
}
492 493 494 495 496

static void
cdisplay_lcms_attach_labelled (GtkTable    *table,
                               gint         row,
                               const gchar *text,
497
                               GtkWidget   *widget,
498
                               gboolean     tooltip)
499
{
500
  GtkWidget *label;
501
  GtkWidget *ebox = NULL;
502 503
  GtkWidget *hbox;

504 505 506 507 508 509 510 511 512 513 514 515
  label = g_object_new (GTK_TYPE_LABEL,
                        "label",  text,
                        "xalign", 1.0,
                        "yalign", 0.5,
                        NULL);

  gimp_label_set_attributes (GTK_LABEL (label),
                             PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
                             -1);
  gtk_table_attach (table, label, 0, 1, row, row + 1,
                    GTK_FILL, GTK_FILL, 0, 0);
  gtk_widget_show (label);
516

517 518 519 520 521 522
  if (tooltip)
    {
      ebox = gtk_event_box_new ();
      gtk_table_attach (table, ebox, 1, 2, row, row + 1,
                        GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
      gtk_widget_show (ebox);
523 524

      g_object_set_data (G_OBJECT (label), "tooltip-widget", ebox);
525
    }
526 527

  hbox = gtk_hbox_new (FALSE, 0);
528 529 530 531 532 533 534

  if (ebox)
    gtk_container_add (GTK_CONTAINER (ebox), hbox);
  else
    gtk_table_attach (table, hbox, 1, 2, row, row + 1,
                      GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);

535 536 537 538 539
  gtk_widget_show (hbox);

  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
  gtk_widget_show (widget);
}
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600

static void
cdisplay_lcms_label_set_text (GtkLabel    *label,
                              const gchar *text,
                              const gchar *tooltip)
{
  GtkWidget *tooltip_widget;

  gtk_label_set_text (label, text);

  tooltip_widget = g_object_get_data (G_OBJECT (label), "tooltip-widget");

  if (tooltip_widget)
    gimp_help_set_help_data (tooltip_widget, tooltip, NULL);
}

static void
cdisplay_lcms_update_profile_label (CdisplayLcms *lcms,
                                    const gchar  *name)
{
  GtkWidget   *label;
  cmsHPROFILE  profile = NULL;
  const gchar *text;
  const gchar *tooltip;

  label = g_object_get_data (G_OBJECT (lcms), name);

  if (! label)
    return;

  if (strcmp (name, "rgb-profile") == 0)
    {
      profile = cdisplay_lcms_get_rgb_profile (lcms);
    }
  else if (g_str_has_prefix (name, "display-profile"))
    {
      profile = cdisplay_lcms_get_display_profile (lcms);
    }
  else if (strcmp (name, "printer-profile") == 0)
    {
      profile = cdisplay_lcms_get_printer_profile (lcms);
    }
  else
    {
      g_return_if_reached ();
    }

  cdisplay_lcms_profile_get_info (profile, &text, &tooltip);
  cdisplay_lcms_label_set_text (GTK_LABEL (label), text, tooltip);

  if (profile)
    cmsCloseProfile (profile);
}

static void
cdisplay_lcms_notify_profile (GObject      *config,
                              GParamSpec   *pspec,
                              CdisplayLcms *lcms)
{
  cdisplay_lcms_update_profile_label (lcms, pspec->name);
}