[babl] babl: add parametric handling for sRGB style TRCs (icc V4)



commit 01d6e09e590d5537e1d66d2e4e2e68e534b0db43
Author: Øyvind Kolås <pippin gimp org>
Date:   Sat Sep 2 17:09:20 2017 +0200

    babl: add parametric handling for sRGB style TRCs (icc V4)

 babl/babl-icc.c      |  100 +++++++++++++++++++++++++++++++++-----------------
 babl/babl-internal.h |    2 +
 babl/babl-trc.c      |   77 ++++++++++++++++++++++++++++++++++----
 babl/babl-trc.h      |    3 +-
 4 files changed, 139 insertions(+), 43 deletions(-)
---
diff --git a/babl/babl-icc.c b/babl/babl-icc.c
index 5ae66bc..debbc69 100644
--- a/babl/babl-icc.c
+++ b/babl/babl-icc.c
@@ -315,22 +315,45 @@ static const Babl *babl_trc_from_icc (ICC  *state, int offset,
               g = icc_read (s15f16, offset + 12 + 2 * 0);
               return babl_trc_gamma (g);
               break;
-
             case 3:
-#if 0
-         float a,b,c,d,e,f;
-              g = icc_read (s15f16, offset + 12 + 2 * 0);
-              a = icc_read (s15f16, offset + 12 + 2 * 1);
-              b = icc_read (s15f16, offset + 12 + 2 * 2);
-              c = icc_read (s15f16, offset + 12 + 2 * 3);
-              d = icc_read (s15f16, offset + 12 + 2 * 4);
-              e = icc_read (s15f16, offset + 12 + 2 * 5);
-              f = icc_read (s15f16, offset + 12 + 2 * 6);
-#endif
-              return babl_trc ("sRGB"); // XXX: not true... and I suspect the CIE L* curve might be 
expressed as this,
-                                        // formula as well, depending on arguments.
+              {
+                float a,b,c,d;
+                g = icc_read (s15f16, offset + 12 + 2 * 0);
+                a = icc_read (s15f16, offset + 12 + 2 * 1);
+                b = icc_read (s15f16, offset + 12 + 2 * 2);
+                c = icc_read (s15f16, offset + 12 + 2 * 3);
+                d = icc_read (s15f16, offset + 12 + 2 * 4);
+                //fprintf (stderr, "%f %f %f %f %f\n", g, a, b, c, d);
+                if (fabs (g - 2.40)     < 0.01 &&
+                    fabs (a - 26214)    < 0.01 &&
+                    fabs (b - 0.947875) < 0.01 &&
+                    fabs (c - (-3417))  < 0.01)
+                  return babl_trc ("sRGB");
+                else
+                  return babl_trc_formula_srgb (g, a, b, c, d);
+              }
+              break;
+            case 4:
+              {
+                float a,b,c,d,e,f;
+                g = icc_read (s15f16, offset + 12 + 2 * 0);
+                a = icc_read (s15f16, offset + 12 + 2 * 1);
+                b = icc_read (s15f16, offset + 12 + 2 * 2);
+                c = icc_read (s15f16, offset + 12 + 2 * 3);
+                d = icc_read (s15f16, offset + 12 + 2 * 4);
+                e = icc_read (s15f16, offset + 12 + 2 * 5);
+                f = icc_read (s15f16, offset + 12 + 2 * 6);
+                fprintf (stderr, "%f %f %f %f %f %f %f\n",
+                              g, a, b, c, d, e, f);
+            {
+              fprintf (stdout, "unhandled parametric sRGB formula TRC type %i\n", function_type);
+              *error = "unhandled sRGB formula like TRC";
+              return babl_trc_gamma (2.2);
+            }
+                              }
               break;
             default:
+              *error = "unhandled parametric TRC";
               fprintf (stdout, "unhandled parametric TRC type %i\n", function_type);
               return babl_trc_gamma (2.2);
             break;
@@ -399,14 +422,42 @@ switch (trc->type)
     icc_write (u32, state->o + 4, 0);
     icc_write (u32, state->o + 8, 0);
     break;
-  case BABL_TRC_GAMMA:
+  case BABL_TRC_FORMULA_GAMMA:
     icc_allocate_tag (state, name, 14);
     icc_write (sign, state->o, "curv");
     icc_write (u32, state->o + 4, 0);
     icc_write (u32, state->o + 8, 1);
     icc_write (u8f8, state->o + 12, trc->gamma);
     break;
+  case BABL_TRC_GAMMA_1_8:
+    icc_allocate_tag (state, name, 14);
+    icc_write (sign, state->o, "curv");
+    icc_write (u32, state->o + 4, 0);
+    icc_write (u32, state->o + 8, 1);
+    icc_write (u8f8, state->o + 12, 1.8);
+    break;
+  case BABL_TRC_GAMMA_2_2:
+    icc_allocate_tag (state, name, 14);
+    icc_write (sign, state->o, "curv");
+    icc_write (u32, state->o + 4, 0);
+    icc_write (u32, state->o + 8, 1);
+    icc_write (u8f8, state->o + 12, 2.2);
+    break;
+  case BABL_TRC_LUT:
+    icc_allocate_tag (state, name, 13 + trc->lut_size * 2);
+    icc_write (sign, state->o, "curv");
+    icc_write (u32, state->o + 4, 0);
+    icc_write (u32, state->o + 8, trc->lut_size);
+    {
+      int j;
+      for (j = 0; j < trc->lut_size; j ++)
+        icc_write (u16, state->o + 12 + j * 2, (int)(trc->lut[j]*65535.5f));
+    }
+    break;
+  // this is the case catching things not directly representable in v2
   case BABL_TRC_SRGB:
+  case BABL_TRC_FORMULA_SRGB:
+//  default:
     {
       int lut_size = 512;
       icc_allocate_tag (state, name, 13 + lut_size * 2);
@@ -417,28 +468,9 @@ switch (trc->type)
         int j;
         for (j = 0; j < lut_size; j ++)
         icc_write (u16, state->o + 12 + j * 2,
-            gamma_2_2_to_linear (j / (lut_size-1.0)) * 65535.5);
+            babl_trc_to_linear ((void*)trc, j / (lut_size-1.0)) * 65535.5);
       }
     }
-    break;
-  case BABL_TRC_LUT:
-    icc_allocate_tag (state, name, 13 + trc->lut_size * 2);
-    icc_write (sign, state->o, "curv");
-    icc_write (u32, state->o + 4, 0);
-    icc_write (u32, state->o + 8, trc->lut_size);
-    {
-      int j;
-      for (j = 0; j < trc->lut_size; j ++)
-        icc_write (u16, state->o + 12 + j * 2, (int)(trc->lut[j]*65535.5f));
-    }
-    break;
-  default:
-    icc_allocate_tag (state, name, 14);
-    icc_write (sign, state->o, "curv");
-    icc_write (u32, state->o + 4, 0);
-    icc_write (u32, state->o + 8, 1);
-    icc_write (u8f8, state->o + 12, trc->gamma);
-    break;
 }
 }
 
diff --git a/babl/babl-internal.h b/babl/babl-internal.h
index 440f7e8..c7c87cf 100644
--- a/babl/babl-internal.h
+++ b/babl/babl-internal.h
@@ -362,5 +362,7 @@ int babl_list_destroy (void *data);
 const char *
 babl_conversion_create_name (Babl *source, Babl *destination, int is_reference);
 void _babl_space_add_universal_rgb (const Babl *space);
+const Babl *
+babl_trc_formula_srgb (double gamma, double a, double b, double c, double d);
 
 #endif
diff --git a/babl/babl-trc.c b/babl/babl-trc.c
index b9f1c49..4aacdef 100644
--- a/babl/babl-trc.c
+++ b/babl/babl-trc.c
@@ -343,12 +343,6 @@ static inline float babl_powf (float x, float y)
   return expf (y * logf (x));
 }
 
-static inline float _babl_trc_gamma_to_linear (const Babl *trc_, float value)
-{
-  BablTRC *trc = (void*)trc_;
-  return babl_powf (value, trc->gamma);
-}
-
 
 static inline void _babl_trc_gamma_to_linear_buf (const Babl *trc_, const float *in, float *out, int in_gap, 
int out_gap, int components, int count)
 {
@@ -376,6 +370,48 @@ static inline float _babl_trc_gamma_from_linear (const Babl *trc_, float value)
   return babl_powf (value, trc->rgamma);
 }
 
+static inline float _babl_trc_gamma_to_linear (const Babl *trc_, float value)
+{
+  BablTRC *trc = (void*)trc_;
+  return babl_powf (value, trc->gamma);
+}
+
+static inline float _babl_trc_formula_srgb_from_linear (const Babl *trc_, float value)
+{
+  BablTRC *trc = (void*)trc_;
+  float x= value;
+  float g = trc->lut[0];
+  float a = trc->lut[1];
+  float b = trc->lut[2];
+  float c = trc->lut[3];
+  float d = trc->lut[4];
+  if (x > c * d)  // XXX: verify that this math is the correct inverse
+  {
+    float v = babl_powf (x, 1.0/g);
+    v = (v-b)/a;
+    return v;
+  }
+  return x / c;
+}
+
+static inline float _babl_trc_formula_srgb_to_linear (const Babl *trc_, float value)
+{
+  BablTRC *trc = (void*)trc_;
+  float x= value;
+  float g = trc->lut[0];
+  float a = trc->lut[1];
+  float b = trc->lut[2];
+  float c = trc->lut[3];
+  float d = trc->lut[4];
+
+  if (x >= d)
+  {
+    return babl_powf (a * x + b, g);
+  }
+  return c * x;
+}
+
+
 static inline float _babl_trc_gamma_1_8_to_linear (const Babl *trc_, float x)
 {
   if (x >= 0.01f && x < 0.7f)
@@ -691,12 +727,22 @@ babl_trc_new (const char *name,
       trc_db[i].fun_from_linear_buf = _babl_trc_linear_buf;
       trc_db[i].fun_to_linear_buf = _babl_trc_linear_buf;
       break;
-    case BABL_TRC_GAMMA:
+    case BABL_TRC_FORMULA_GAMMA:
       trc_db[i].fun_to_linear = _babl_trc_gamma_to_linear;
       trc_db[i].fun_from_linear = _babl_trc_gamma_from_linear;
       trc_db[i].fun_to_linear_buf = _babl_trc_gamma_to_linear_buf;
       trc_db[i].fun_from_linear_buf = _babl_trc_gamma_from_linear_buf;
       break;
+    case BABL_TRC_FORMULA_SRGB:
+      trc_db[i].lut = babl_calloc (sizeof (float), 5);
+      {
+        int j;
+        for (j = 0; j < 5; j++)
+          trc_db[i].lut[j] = lut[j];
+      }
+      trc_db[i].fun_to_linear = _babl_trc_formula_srgb_to_linear;
+      trc_db[i].fun_from_linear = _babl_trc_formula_srgb_from_linear;
+      break;
     case BABL_TRC_GAMMA_2_2:
       trc_db[i].fun_to_linear = _babl_trc_gamma_2_2_to_linear;
       trc_db[i].fun_from_linear = _babl_trc_gamma_2_2_from_linear;
@@ -739,6 +785,21 @@ babl_trc_class_for_each (BablEachFunction each_fun,
 }
 
 const Babl *
+babl_trc_formula_srgb (double gamma, double a, double b, double c, double d)
+{
+  char name[32];
+  int i;
+  float params[5]={gamma, a, b, c, d};
+
+  sprintf (name, "%.6f %.6f %.4f %.4f %.4f", gamma, a, b, c, d);
+  for (i = 0; name[i]; i++)
+    if (name[i] == ',') name[i] = '.';
+  while (name[strlen(name)-1]=='0')
+    name[strlen(name)-1]='\0';
+  return babl_trc_new (name, BABL_TRC_FORMULA_SRGB, gamma, 0, params);
+}
+
+const Babl *
 babl_trc_gamma (double gamma)
 {
   char name[32];
@@ -755,7 +816,7 @@ babl_trc_gamma (double gamma)
     if (name[i] == ',') name[i] = '.';
   while (name[strlen(name)-1]=='0')
     name[strlen(name)-1]='\0';
-  return babl_trc_new (name, BABL_TRC_GAMMA, gamma, 0, NULL);
+  return babl_trc_new (name, BABL_TRC_FORMULA_GAMMA, gamma, 0, NULL);
 }
 
 void
diff --git a/babl/babl-trc.h b/babl/babl-trc.h
index 0b7fb70..95020b9 100644
--- a/babl/babl-trc.h
+++ b/babl/babl-trc.h
@@ -26,10 +26,11 @@
 BABL_CLASS_DECLARE (trc);
 
 typedef enum {BABL_TRC_LINEAR,
-              BABL_TRC_GAMMA,
+              BABL_TRC_FORMULA_GAMMA,
               BABL_TRC_GAMMA_1_8,
               BABL_TRC_GAMMA_2_2,
               BABL_TRC_SRGB,
+              BABL_TRC_FORMULA_SRGB,
               BABL_TRC_LUT}
 BablTRCType;
 


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