[babl] babl: add babl_space_rgb_icc



commit 018cc8100c47b56296488cc852dd93b9a707607e
Author: Øyvind Kolås <pippin gimp org>
Date:   Sat Aug 19 23:08:03 2017 +0200

    babl: add babl_space_rgb_icc

 babl/Makefile.am     |    1 +
 babl/babl-icc.c      |  262 ++++++++++++++++++++++++++++++++++++++++++++++++++
 babl/babl-internal.h |    3 +
 babl/babl.h          |   16 +++-
 4 files changed, 281 insertions(+), 1 deletions(-)
---
diff --git a/babl/Makefile.am b/babl/Makefile.am
index 1a6d38d..403c249 100644
--- a/babl/Makefile.am
+++ b/babl/Makefile.am
@@ -20,6 +20,7 @@ c_sources =                           \
        babl-fish.c                     \
        babl-format.c                   \
        babl-hash-table.c               \
+       babl-icc.c                      \
        babl-image.c                    \
        babl-internal.c                 \
        babl-introspect.c               \
diff --git a/babl/babl-icc.c b/babl/babl-icc.c
new file mode 100644
index 0000000..7fd9b32
--- /dev/null
+++ b/babl/babl-icc.c
@@ -0,0 +1,262 @@
+#include "config.h"
+#include "babl-internal.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ICC_HEADER_LEN 128
+#define TAG_COUNT_OFF  ICC_HEADER_LEN
+
+static int load_byte (const char *icc, int offset)
+{
+  return *(uint8_t*) (&icc[offset]);
+}
+
+static int16_t load_u1Fixed15 (const char *icc, int offset)
+{
+  return load_byte (icc, offset + 1) +
+         (load_byte (icc, offset + 0) << 8);
+}
+
+static uint16_t load_uint16 (const char *icc, int offset)
+{
+  return load_byte (icc, offset + 1) +
+         (load_byte (icc, offset + 0) << 8);
+}
+
+static double load_s15Fixed16 (const char *icc, int offset)
+{
+  return load_u1Fixed15 (icc, offset) + load_uint16 (icc, offset + 2) / 65535.0f;
+}
+
+static double load_u16Fixed16 (const char *icc, int offset)
+{
+  return load_uint16 (icc, offset) + load_uint16 (icc, offset + 2) / 65535.0;
+}
+
+static uint32_t load_uint32 (const char *icc, int offset)
+{
+  return load_byte (icc, offset + 3) +
+         (load_byte (icc, offset + 2) << 8) +
+         (load_byte (icc, offset + 1) << 16) +
+         (load_byte (icc, offset + 0) << 24);
+}
+
+static void load_sign (const char *icc, int offset, char *sign)
+{
+  sign[0]=load_byte(icc, offset);
+  sign[1]=load_byte(icc, offset + 1);
+  sign[2]=load_byte(icc, offset + 2);
+  sign[3]=load_byte(icc, offset + 3);
+  sign[4]=0;
+}
+
+/* looks up offset and length for a specifi icc tag
+ */
+static int icc_tag (const char *icc, const char *tag, int *offset, int *length)
+{
+  int tag_count = load_uint32 (icc, TAG_COUNT_OFF);
+  int profile_size = load_uint32 (icc, 0);
+  int t;
+
+  for (t =  0; t < tag_count; t++)
+  {
+     char tag_signature[5];
+     load_sign (icc, TAG_COUNT_OFF + 4 + 12 * t, tag_signature);
+     if (!strcmp (tag_signature, tag))
+     {
+        if (!offset)
+          return 1;
+        *offset = load_uint32 (icc, TAG_COUNT_OFF + 4 + 12* t + 4);
+        /* avert some potential for maliciousnes.. */
+        if (*offset >= profile_size)
+          {
+            *offset = profile_size - 1;
+          }
+        if (!length)
+          return 1;
+        *length = load_uint32 (icc, TAG_COUNT_OFF + 4 + 12* t + 4 * 2);
+        /* avert some potential for maliciousnes.. */
+        if (*offset + *length >= profile_size)
+          {
+            *length = profile_size - *offset - 1;
+          }
+        return 1;
+     }
+  }
+  return 0;
+}
+
+static const Babl *babl_trc_from_icc (const char *icc,
+                                      int         length,
+                                      char      **error)
+{
+  int offset = 0;
+  {
+    int count = load_uint32 (icc, offset + 8);
+    int i;
+    {
+      if (count == 0)
+      {
+        return babl_trc_gamma (1.0);
+      }
+      else if (count == 1)
+      {
+        return babl_trc_gamma (load_byte (icc, offset + 12) +
+                               load_byte (icc, offset + 12 + 1) / 255.0);
+      }
+      else
+      {
+        return babl_trc_gamma (2.2);
+
+        // XXX: todo implement a curve trc babl type
+        //      as well as detect sRGB curve from LUTs
+
+        for (i = 0; i < count && i < 10; i ++)
+        {
+          fprintf (stdout, "%i=%i ", i, load_uint16 (icc, offset + 12 + i * 2));
+          if (i % 7 == 0)
+           fprintf (stdout, "\n");
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+const Babl *
+babl_space_rgb_icc (const char *icc,
+                    int         length,
+                    char      **error)
+{
+  int  profile_size          = load_uint32 (icc, 0);
+  int  icc_ver_major         = load_byte (icc, 8);
+  const Babl *trc_red = NULL;
+  const Babl *trc_green = NULL;
+  const Babl *trc_blue = NULL;
+  char profile_class[5];
+  char color_space[5];
+
+  if (profile_size != length)
+  {
+    *error = "icc profile length inconsistency";
+    return NULL;
+  }
+  if (icc_ver_major > 2)
+  {
+    *error = "only ICC v2 profiles supported";
+    return NULL;
+  }
+  load_sign (icc, 12, profile_class);
+  if (strcmp (profile_class, "mntr"))
+  {
+    *error = "not a monitor-class profile";
+    return NULL;
+  }
+  load_sign (icc, 16, color_space);
+  if (strcmp (color_space, "RGB "))
+  {
+    *error = "not defining an RGB space";
+    return NULL;
+  }
+  {
+     int offset, element_size;
+     if (icc_tag (icc, "rTRC", &offset, &element_size))
+     {
+       trc_red = babl_trc_from_icc (icc + offset, element_size, error);
+       if (*error)
+         return NULL;
+     }
+     if (icc_tag (icc, "gTRC", &offset, &element_size))
+     {
+       trc_green = babl_trc_from_icc (icc + offset, element_size, error);
+       if (*error)
+         return NULL;
+     }
+     if (icc_tag (icc, "bTRC", &offset, &element_size))
+     {
+       trc_blue = babl_trc_from_icc (icc + offset, element_size, error);
+       if (*error)
+         return NULL;
+     }
+  }
+
+  if (!trc_red || !trc_green || !trc_blue)
+  {
+     *error = "missing TRC";
+     return NULL;
+  }
+
+  if (icc_tag (icc, "chrm", NULL, NULL) &&
+      icc_tag (icc, "wtpt", NULL, NULL))
+  {
+     int offset, element_size;
+     double redX, redY, greenX, greenY, blueX, blueY;
+
+     icc_tag (icc, "chrm", &offset, &element_size);
+     {
+     int channels   = load_uint16 (icc, offset + 8);
+     int phosporant = load_uint16 (icc, offset + 10);
+
+     redX    = load_s15Fixed16 (icc, offset + 12);
+     redY    = load_s15Fixed16 (icc, offset + 12 + 4);
+     greenX  = load_s15Fixed16 (icc, offset + 20);
+     greenY  = load_s15Fixed16 (icc, offset + 20 + 4);
+     blueX   = load_s15Fixed16 (icc, offset + 28);
+     blueY   = load_s15Fixed16 (icc, offset + 28 + 4);
+
+     fprintf (stdout, "chromaticity:\n");
+     fprintf (stdout, "  channels: %i\n", channels);
+     fprintf (stdout, "  phosphorant: %i\n", phosporant);
+     fprintf (stdout, "  CIE xy red: %f %f\n", redX, redY);
+     fprintf (stdout, "  CIE xy green: %f %f\n", greenX, greenY);
+     fprintf (stdout, "  CIE xy blue: %f %f\n", blueX, blueY);
+     }
+
+     icc_tag (icc, "wtpt", &offset, &element_size);
+     {
+       double wX = load_u16Fixed16 (icc, offset + 8);
+       double wY = load_u16Fixed16 (icc, offset + 8 + 4);
+       double wZ = load_u16Fixed16 (icc, offset + 8 + 4 * 2);
+
+       return babl_space_rgb_chromaticities (NULL,
+                       wX / (wX + wY + wZ),
+                       wY / (wX + wY + wZ),
+                       redX, redY,
+                       greenX, greenY,
+                       blueX, blueY,
+                       trc_red, trc_green, trc_blue);
+
+     }
+  }
+  else if (icc_tag (icc, "rXYZ", NULL, NULL) &&
+           icc_tag (icc, "gXYZ", NULL, NULL) &&
+           icc_tag (icc, "bXYZ", NULL, NULL))
+  {
+     int offset, element_size;
+     double rx, gx, bx;
+     double ry, gy, by;
+     double rz, gz, bz;
+
+     icc_tag (icc, "rXYZ", &offset, &element_size);
+     rx = load_u16Fixed16 (icc, offset + 8 + 4 * 0);
+     ry = load_u16Fixed16 (icc, offset + 8 + 4 * 1);
+     rz = load_u16Fixed16 (icc, offset + 8 + 4 * 2);
+     icc_tag (icc, "gXYZ", &offset, &element_size);
+     gx = load_u16Fixed16 (icc, offset + 8 + 4 * 0);
+     gy = load_u16Fixed16 (icc, offset + 8 + 4 * 1);
+     gz = load_u16Fixed16 (icc, offset + 8 + 4 * 2);
+     icc_tag (icc, "bXYZ", &offset, &element_size);
+     bx = load_u16Fixed16 (icc, offset + 8 + 4 * 0);
+     by = load_u16Fixed16 (icc, offset + 8 + 4 * 1);
+     bz = load_u16Fixed16 (icc, offset + 8 + 4 * 2);
+
+     return babl_space_rgb_matrix (NULL,
+                rx, gx, bx,
+                ry, gy, by,
+                rz, gz, bz,
+                trc_red, trc_green, trc_blue);
+  }
+
+  *error = "didnt find RGB primaries";
+  return NULL;
+}
diff --git a/babl/babl-internal.h b/babl/babl-internal.h
index 9181bd9..33132e6 100644
--- a/babl/babl-internal.h
+++ b/babl/babl-internal.h
@@ -392,6 +392,9 @@ float babl_trc_to_linearf   (const Babl *trc, float value);
 void babl_space_to_xyz   (const Babl *space, const double *rgb, double *xyz);
 void babl_space_from_xyz (const Babl *space, const double *xyz, double *rgb);
 
+const Babl *babl_space_from_icc (const char *icc,
+                                 int         length,
+                                 char      **error);
 
 
 #endif
diff --git a/babl/babl.h b/babl/babl.h
index 31d58dc..4edec9a 100644
--- a/babl/babl.h
+++ b/babl/babl.h
@@ -123,7 +123,7 @@ const Babl * babl_space_rgb_chromaticities (const char *name,
                                             const Babl *trc_blue);
 
 /**
- * babl_space_rgb_chromaticities:
+ * babl_space_rgb_matrix:
  *
  * Creates a new RGB matrix color space definition using a precomputed
  * D50 adapted 3x3 matrix, as possibly read from an ICC profile.
@@ -136,6 +136,20 @@ babl_space_rgb_matrix (const char *name,
                        const Babl *trc_red,
                        const Babl *trc_green,
                        const Babl *trc_blue);
+/**
+ * babl_space_rgb_icc:
+ *
+ * Create a babl space from an in memory ICC profile, the
+ * profile does no longer need to be loaded for the space to work,
+ * multiple calls with the same icc profile will result in the
+ * same space.
+ *
+ * If a BablSpace cannot be created from the profile NULL is returned and
+ * a static string is set on the provided error location.
+ */
+const Babl *babl_space_rgb_icc (const char *icc,
+                                int         length,
+                                char      **error);
 
 const double * babl_space_get_rgbtoxyz (const Babl *space);
 void babl_space_to_xyz   (const Babl *space, const double *rgb, double *xyz);


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