[babl] babl: add babl_space_rgb_icc
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [babl] babl: add babl_space_rgb_icc
- Date: Sat, 19 Aug 2017 21:08:52 +0000 (UTC)
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]