[babl] babl: add support for grayscale spaces



commit 446331df3b1cceac4ec631a4ea4f675197ea20e3
Author: Øyvind Kolås <pippin gimp org>
Date:   Mon Aug 19 00:01:13 2019 +0200

    babl: add support for grayscale spaces
    
    A grayscale space is just like an RGB space, but has a default set
    of chromaticities for R,G,B. When ICC profiles are loaded only the TRC
    is considered is considered (we could also include the whitepoint),
    blackpoint tag is ignored (and should be baked into the used ICC
    profile instead.)
    
    This works with GIMP-2.10 but master of GIMP currently hangs when
    trying to load a grayscale jpeg with attached grayscale ICC profile,
    The if #0 on line 999 of babl/babl-icc.c needs to be turned into a
    1 to enable grayscale icc profiles for further testing.

 babl/babl-icc.c   | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 babl/babl-space.c |  72 +++++++++++++++++++++
 babl/babl-space.h |  11 +++-
 babl/babl.h       |   1 +
 export-symbols    |   1 +
 5 files changed, 257 insertions(+), 14 deletions(-)
---
diff --git a/babl/babl-icc.c b/babl/babl-icc.c
index e37197718..9808c75c5 100644
--- a/babl/babl-icc.c
+++ b/babl/babl-icc.c
@@ -561,12 +561,13 @@ switch (trc->type)
 static void 
 symmetry_test (ICC *state);
 
-char *
-babl_space_to_icc (const Babl  *babl,
-                         const char  *description,
-                         const char  *copyright,
-                         BablICCFlags flags,
-                         int         *ret_length)
+
+static char *
+babl_space_to_icc_rgb (const Babl  *babl,
+                       const char  *description,
+                       const char  *copyright,
+                       BablICCFlags flags,
+                       int         *ret_length)
 {
   const BablSpace *space = &babl->space;
   char icc[65536];
@@ -691,6 +692,119 @@ babl_space_to_icc (const Babl  *babl,
   }
 }
 
+
+static char *
+babl_space_to_icc_gray (const Babl  *babl,
+                        const char  *description,
+                        const char  *copyright,
+                        BablICCFlags flags,
+                        int         *ret_length)
+{
+  const BablSpace *space = &babl->space;
+  char icc[65536];
+  int length=65535;
+  ICC *state = icc_state_new (icc, length, 10);
+
+  icc[length]=0;
+
+  symmetry_test (state);
+
+  icc_write (sign, 4, "babl");  // ICC verison
+  icc_write (u8, 8, 2);         // ICC verison
+  icc_write (u8, 9, 0x20);      // 2.2 for now..
+  icc_write (u32,64, 0);        // rendering intent
+
+  icc_write (s15f16,68, 0.96421); // Illuminant
+  icc_write (s15f16,72, 1.0);
+  icc_write (s15f16,76, 0.82491);
+
+  icc_write (sign, 80, "babl"); // creator
+
+  icc_write (sign, 12, "mntr");
+  icc_write (sign, 16, "GRAY");
+  icc_write (sign, 20, "XYZ ");
+
+  icc_write (u16, 24, 2222);  // babl profiles
+  icc_write (u16, 26, 11);    // should
+  icc_write (u16, 28, 11);    // use a fixed
+  icc_write (u16, 30,  3);    // date
+  icc_write (u16, 32, 44);    // that gets updated
+  icc_write (u16, 34, 55);    // when the generator changes
+
+  icc_write (sign, 36, "acsp"); // changes
+
+  {
+    state->tags = 6; /* note: we could reserve a couple of spots and
+                        still use a very simple allocator and
+                        still be valid - albeit with tiny waste of
+                        space.
+                */
+    state->no = state->o = 128 + 4 + 12 * state->tags;
+
+    icc_write (u32,  128, state->tags);
+
+    icc_allocate_tag (state, "wtpt", 20);
+    icc_write (sign, state->o, "XYZ ");
+    icc_write (u32,  state->o + 4, 0);
+    icc_write (s15f16, state->o + 8,  space->whitepoint[0]);
+    icc_write (s15f16, state->o + 12, space->whitepoint[1]);
+    icc_write (s15f16, state->o + 16, space->whitepoint[2]);
+
+    write_trc (state, "kTRC", &space->trc[0]->trc, flags);
+
+    {
+      char str[128]="CC0/public domain";
+      int i;
+      if (!copyright) copyright = str;
+      icc_allocate_tag(state, "cprt", 8 + strlen (copyright) + 1);
+      icc_write (sign, state->o, "text");
+      icc_write (u32, state->o + 4, 0);
+      for (i = 0; copyright[i]; i++)
+        icc_write (u8, state->o + 8 + i, copyright[i]);
+    }
+    {
+      char str[128]="babl";
+      int i;
+      if (!description) description = str;
+      icc_allocate_tag(state, "desc", 90 + strlen (description) + 0);
+      icc_write (sign, state->o,"desc");
+      icc_write (u32, state->o + 4, 0);
+      icc_write (u32, state->o + 8, strlen(description) + 1);
+      for (i = 0; description[i]; i++)
+        icc_write (u8, state->o + 12 + i, description[i]);
+    }
+    icc_write (u32, 0, state->no + 0);
+    length = state->no + 0;
+  }
+
+  if (ret_length)
+    *ret_length = length;
+
+  babl_free (state);
+  {
+    char *ret = malloc (length);
+    memcpy (ret, icc, length);
+    return ret;
+  }
+}
+
+char *
+babl_space_to_icc (const Babl  *babl,
+                   const char  *description,
+                   const char  *copyright,
+                   BablICCFlags flags,
+                   int         *ret_length)
+{
+  if (babl->space.icc_type == BablICCTypeRGB)
+    return babl_space_to_icc_rgb (babl, description, copyright, flags,
+                                  ret_length);
+  else if (babl->space.icc_type == BablICCTypeGray)
+    return babl_space_to_icc_gray (babl, description, copyright, flags,
+                                   ret_length);
+  fprintf (stderr, "unexpected icc type in %s\n", __FUNCTION__);
+  return NULL;
+}
+
 const char *
 babl_space_get_icc (const Babl *babl, 
                     int        *length)
@@ -819,9 +933,11 @@ babl_space_from_icc (const char   *icc_data,
   const Babl *trc_red   = NULL;
   const Babl *trc_green = NULL;
   const Babl *trc_blue  = NULL;
+  const Babl *trc_gray  = NULL;
   const char *int_err;
   Babl *ret = NULL;
   int speed_over_accuracy = intent & BABL_ICC_INTENT_PERFORMANCE;
+  int is_gray = 0;
 
   sign_t profile_class, color_space, pcs;
 
@@ -842,7 +958,6 @@ babl_space_from_icc (const char   *icc_data,
        ret = _babl_space_for_lcms (icc_data, icc_length);
        if (ret->space.icc_type == BablICCTypeCMYK)
          return ret;
-       ret->space.icc_type = BablICCTypeCMYK;
        ret->space.icc_length = icc_length;
        ret->space.icc_profile = malloc (icc_length);
        memcpy (ret->space.icc_profile, icc_data, icc_length);
@@ -877,12 +992,23 @@ babl_space_from_icc (const char   *icc_data,
        return ret;
     }
 
-    if (strcmp (color_space.str, "RGB "))
-      *error = "not defining an RGB space";
+
+
+
+    if (strcmp (color_space.str, "RGB ")
+#if 0  /* XXX: commented out, as gimp-2.99 doesn't like loading grayscale jpegs with grayscale icc profiles 
when it is enabled */
+        && strcmp (color_space.str, "GRAY")
+#endif
+    )
+    {
+      *error = "not defining RGB, CMYK or GRAY space..";
+    }
     else
      {
        if (strcmp (profile_class.str, "mntr"))
          *error = "not a monitor-class profile";
+       if (!strcmp (color_space.str, "GRAY"))
+         is_gray = 1;
      }
   }
 
@@ -946,11 +1072,25 @@ babl_space_from_icc (const char   *icc_data,
      {
        trc_blue = babl_trc_from_icc (state, offset, error);
      }
+     if (!*error && icc_tag (state, "kTRC", &offset, &element_size))
+     {
+       trc_gray = babl_trc_from_icc (state, offset, error);
+     }
   }
 
-  if (!*error && (!trc_red || !trc_green || !trc_blue))
+  if (is_gray)
   {
-     *error = "missing TRCs";
+     if (!*error && (!trc_gray))
+     {
+        *error = "missing TRC";
+     }
+  }
+  else
+  {
+     if (!*error && (!trc_red || !trc_green || !trc_blue))
+     {
+        *error = "missing TRCs";
+     }
   }
 
   if (*error)
@@ -960,6 +1100,27 @@ babl_space_from_icc (const char   *icc_data,
     return NULL;
   }
 
+  if (is_gray)
+  {
+    int offset, element_size;
+    if (icc_tag (state, "wtpt", &offset, &element_size))
+    {
+    //   wX = icc_read (s15f16, offset + 8);
+    //   wY = icc_read (s15f16, offset + 8 + 4);
+    //   wZ = icc_read (s15f16, offset + 8 + 4 * 2);
+    }
+    ret  = (void*)babl_space_from_gray_trc (NULL, trc_gray, 1);
+    ret->space.icc_length = icc_length;
+    ret->space.icc_profile = malloc (icc_length);
+    memcpy (ret->space.icc_profile, icc_data, icc_length);
+    babl_free (state);
+    return ret;
+
+
+    *error = "gray parsing NYI";
+  }
+  else
+  {
   if (icc_tag (state, "rXYZ", NULL, NULL) &&
       icc_tag (state, "gXYZ", NULL, NULL) &&
       icc_tag (state, "bXYZ", NULL, NULL) &&
@@ -1076,8 +1237,9 @@ babl_space_from_icc (const char   *icc_data,
        return ret;
      }
   }
-
   *error = "didnt find RGB primaries";
+  }
+
   babl_free (state);
   return NULL;
 }
diff --git a/babl/babl-space.c b/babl/babl-space.c
index 7a8d7b1f7..c05796ca8 100644
--- a/babl/babl-space.c
+++ b/babl/babl-space.c
@@ -243,6 +243,7 @@ _babl_space_for_lcms (const char *icc_data,
   memset (&space, 0, sizeof(space));
   space.instance.class_type = BABL_SPACE;
   space.instance.id         = 0;
+  space.icc_type = BablICCTypeCMYK;
 
   if (i >= MAX_SPACES-1)
   {
@@ -292,12 +293,14 @@ babl_space_from_rgbxyz_matrix (const char *name,
   space.RGBtoXYZ[6] = rz;
   space.RGBtoXYZ[7] = gz;
   space.RGBtoXYZ[8] = bz;
+  space.icc_type = BablICCTypeRGB;
 
   babl_matrix_invert (space.RGBtoXYZ, space.XYZtoRGB);
 
   babl_matrix_to_float (space.RGBtoXYZ, space.RGBtoXYZf);
   babl_matrix_to_float (space.XYZtoRGB, space.XYZtoRGBf);
 
+  /* recover chromaticities from matrix */
   {
     double red[3]={1.,.0,.0};
     double xyz[3]={1.,.0,.0};
@@ -392,6 +395,7 @@ babl_space_from_chromaticities (const char *name,
   space.whitepoint[0] = wx / wy;
   space.whitepoint[1] = 1.0;
   space.whitepoint[2] = (1.0 - wx - wy) / wy;
+  space.icc_type = BablICCTypeRGB;
 
   for (i = 0; space_db[i].instance.class_type; i++)
   {
@@ -426,6 +430,67 @@ babl_space_from_chromaticities (const char *name,
   return (Babl*)&space_db[i];
 }
 
+const Babl *
+babl_space_from_gray_trc (const char *name,
+                          const Babl *trc_gray,
+                          BablSpaceFlags flags)
+{
+  int i=0;
+  BablSpace space = {0,};
+  space.instance.class_type = BABL_SPACE;
+  space.instance.id         = 0;
+
+  space.xw = 0.3127;
+  space.yw = 0.3290;
+
+  space.xr = 0.639998686;
+  space.yr = 0.330010138;
+  space.xg = 0.300003784;
+  space.yg = 0.600003357;
+  space.xb = 0.150002046;
+  space.yb = 0.059997204;
+  space.trc[0] = trc_gray;
+  space.trc[1] = trc_gray;
+  space.trc[2] = trc_gray;
+
+  space.whitepoint[0] = space.xw / space.yw;
+  space.whitepoint[1] = 1.0;
+  space.whitepoint[2] = (1.0 - space.xw - space.yw) / space.yw;
+  space.icc_type = BablICCTypeGray;
+
+  for (i = 0; space_db[i].instance.class_type; i++)
+  {
+    int offset = ((char*)&space_db[i].xr) - (char*)(&space_db[i]);
+    int size   = ((char*)&space_db[i].trc) + sizeof(space_db[i].trc) - ((char*)&space_db[i].xr);
+
+    if (memcmp ((char*)(&space_db[i]) + offset, ((char*)&space) + offset, size)==0)
+      {
+        return (void*)&space_db[i];
+      }
+  }
+  if (i >= MAX_SPACES-1)
+  {
+    babl_log ("too many BablSpaces");
+    return NULL;
+  }
+  space_db[i]=space;
+  space_db[i].instance.name = space_db[i].name;
+  if (name)
+    snprintf (space_db[i].name, sizeof (space_db[i].name), "%s", name);
+  else
+          /* XXX: this can get longer than 256bytes ! */
+    snprintf (space_db[i].name, sizeof (space_db[i].name),
+             "space-gray-%s", babl_get_name(space.trc[0]));
+
+  /* compute matrixes */
+  babl_space_compute_matrices (&space_db[i], 1);
+
+  //babl_space_get_icc ((Babl*)&space_db[i], NULL);
+  return (Babl*)&space_db[i];
+
+}
+
+
 void
 babl_space_class_for_each (BablEachFunction each_fun,
                            void            *user_data)
@@ -1309,6 +1374,13 @@ babl_space_is_cmyk (const Babl *space)
   return space?space->space.icc_type == BablICCTypeCMYK:0;
 }
 
+int
+babl_space_is_gray (const Babl *space)
+{
+  return space?space->space.icc_type == BablICCTypeGray:0;
+}
+
+
 /* Trademarks:
  *
  * International Color Consortium is a registered trademarks of the.
diff --git a/babl/babl-space.h b/babl/babl-space.h
index 1d9934a20..86692e95b 100644
--- a/babl/babl-space.h
+++ b/babl/babl-space.h
@@ -111,10 +111,14 @@ typedef struct
   double           xb;  // blue primary chromaticity
   double           yb;
 
+  BablICCType icc_type;  /* taken into account when looking for duplicate spaces*/
+  double whitepoint[3]; /* CIE XYZ whitepoint */
   const Babl      *trc[3];
+
+  /* ------------- end of dedup zone --------------  */
+
   char             name[512]; // XXX: allocate this dynamically instead -
                               //      or use iccv4 style hashes for name.
-  double whitepoint[3]; /* CIE XYZ whitepoint */
 
   double RGBtoXYZ[9]; /* matrices for conversions */
   double XYZtoRGB[9];
@@ -131,7 +135,6 @@ typedef struct
    */
   char *icc_profile;
   int   icc_length;
-  BablICCType icc_type;
   BablCMYK cmyk;
 } BablSpace;
 
@@ -163,6 +166,10 @@ static inline void _babl_space_from_xyz (const Babl *space, const double *xyz, d
 void
 babl_space_class_init (void);
 
+const Babl *
+babl_space_from_gray_trc (const char *name,
+                          const Babl *trc_gray,
+                          BablSpaceFlags flags);
 
 
 #endif
diff --git a/babl/babl.h b/babl/babl.h
index 25e5aec76..3c025bb80 100644
--- a/babl/babl.h
+++ b/babl/babl.h
@@ -704,6 +704,7 @@ babl_space_from_rgbxyz_matrix (const char *name,
 const char * babl_format_get_encoding (const Babl *babl);
 
 int babl_space_is_cmyk (const Babl *space);
+int babl_space_is_gray (const Babl *space);
 
 /* values below this are stored associated with this value, it should also be
  * used as a generic alpha zero epsilon in GEGL to keep the threshold effects
diff --git a/export-symbols b/export-symbols
index d692f46d7..9123e7e36 100644
--- a/export-symbols
+++ b/export-symbols
@@ -55,6 +55,7 @@ babl_space_from_xyz
 babl_space_to_icc
 babl_space_with_trc
 babl_space_is_cmyk
+babl_space_is_gray
 babl_icc_make_space
 babl_icc_get_key
 babl_ticks


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]