Author: abrander
Date: 2009-09-23 17:10:54 +0200 (Wed, 23 Sep 2009)
New Revision: 2651
Added:
trunk/librawstudio/rs-color.c
trunk/librawstudio/rs-color.h
Modified:
trunk/librawstudio/Makefile.am
Log:
Added various color related function.
Modified: trunk/librawstudio/Makefile.am
===================================================================
--- trunk/librawstudio/Makefile.am 2009-09-23 14:39:02 UTC (rev 2650)
+++ trunk/librawstudio/Makefile.am 2009-09-23 15:10:54 UTC (rev 2651)
@@ -27,6 +27,7 @@
rs-job-queue.h \
rs-utils.h \
rs-math.h \
+ rs-color.h \
rs-settings.h \
rs-adobe-coeff.h \
rs-color-transform.h \
@@ -55,6 +56,7 @@
rs-job-queue.c rs-job-queue.h \
rs-utils.c rs-utils.h \
rs-math.c rs-math.h \
+ rs-color.c rs-color.h \
rs-settings.c rs-settings.h \
rs-adobe-coeff.c rs-adobe-coeff.h \
rs-color-transform.c rs-color-transform.h \
Added: trunk/librawstudio/rs-color.c
===================================================================
--- trunk/librawstudio/rs-color.c (rev 0)
+++ trunk/librawstudio/rs-color.c 2009-09-23 15:10:54 UTC (rev 2651)
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2006-2009 Anders Brander <[email protected]> and
+ * Anders Kvist <[email protected]>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
+ */
+
+#include <rawstudio.h>
+#include <math.h>
+#include "rs-color.h"
+
+/* We use XYZ with a D50 whitepoint as PCS (as recommended by ICC) */
+
+const RS_XYZ_VECTOR XYZ_WP_D50 = {0.964296, 1.0, 0.825105}; /* Computed by DNG
SDK */
+
+/* Scale factor between distances in uv space to a more user friendly "tint"
parameter. */
+static const gdouble tint_scale = -3000.0;
+
+/* Table from Wyszecki & Stiles, "Color Science", second edition, page 228. */
+
+struct ruvt {
+ gdouble r;
+ gdouble u;
+ gdouble v;
+ gdouble t;
+} temp_table[] = {
+ { 0, 0.18006, 0.26352, -0.24341 },
+ { 10, 0.18066, 0.26589, -0.25479 },
+ { 20, 0.18133, 0.26846, -0.26876 },
+ { 30, 0.18208, 0.27119, -0.28539 },
+ { 40, 0.18293, 0.27407, -0.30470 },
+ { 50, 0.18388, 0.27709, -0.32675 },
+ { 60, 0.18494, 0.28021, -0.35156 },
+ { 70, 0.18611, 0.28342, -0.37915 },
+ { 80, 0.18740, 0.28668, -0.40955 },
+ { 90, 0.18880, 0.28997, -0.44278 },
+ { 100, 0.19032, 0.29326, -0.47888 },
+ { 125, 0.19462, 0.30141, -0.58204 },
+ { 150, 0.19962, 0.30921, -0.70471 },
+ { 175, 0.20525, 0.31647, -0.84901 },
+ { 200, 0.21142, 0.32312, -1.0182 },
+ { 225, 0.21807, 0.32909, -1.2168 },
+ { 250, 0.22511, 0.33439, -1.4512 },
+ { 275, 0.23247, 0.33904, -1.7298 },
+ { 300, 0.24010, 0.34308, -2.0637 },
+ { 325, 0.24702, 0.34655, -2.4681 },
+ { 350, 0.25591, 0.34951, -2.9641 },
+ { 375, 0.26400, 0.35200, -3.5814 },
+ { 400, 0.27218, 0.35407, -4.3633 },
+ { 425, 0.28039, 0.35577, -5.3762 },
+ { 450, 0.28863, 0.35714, -6.7262 },
+ { 475, 0.29685, 0.35823, -8.5955 },
+ { 500, 0.30505, 0.35907, -11.324 },
+ { 525, 0.31320, 0.35968, -15.628 },
+ { 550, 0.32129, 0.36011, -23.325 },
+ { 575, 0.32931, 0.36038, -40.770 },
+ { 600, 0.33724, 0.36051, -116.45 }
+};
+
+void
+rs_color_whitepoint_to_temp(const RS_xy_COORD *xy, gfloat *temp, gfloat *tint)
+{
+ /* Convert to uv space. */
+ gdouble u = 2.0 * xy->x / (1.5 - xy->x + 6.0 * xy->y);
+ gdouble v = 3.0 * xy->y / (1.5 - xy->x + 6.0 * xy->y);
+
+ /* Search for line pair coordinate is between. */
+ gdouble last_dt = 0.0;
+
+ gdouble last_dv = 0.0;
+ gdouble last_du = 0.0;
+
+ guint index;
+ for (index = 1; index <= 30; index++)
+ {
+ /* Convert slope to delta-u and delta-v, with length 1. */
+ gdouble du = 1.0;
+ gdouble dv = temp_table[index] . t;
+
+ gdouble len = sqrt (1.0 + dv * dv);
+
+ du /= len;
+ dv /= len;
+
+ /* Find delta from black body point to test coordinate. */
+ gdouble uu = u - temp_table[index] . u;
+ gdouble vv = v - temp_table[index] . v;
+
+ /* Find distance above or below line. */
+
+ gdouble dt = - uu * dv + vv * du;
+
+ /* If below line, we have found line pair. */
+
+ if (dt <= 0.0 || index == 30)
+ {
+ /* Find fractional weight of two lines. */
+ if (dt > 0.0)
+ dt = 0.0;
+
+ dt = -dt;
+
+ gdouble f;
+
+ if (index == 1)
+ f = 0.0;
+ else
+ f = dt / (last_dt + dt);
+
+ /* Interpolate the temperature. */
+ if (temp)
+ *temp = 1.0E6 / (temp_table[index - 1] . r * f
+ temp_table[index ] . r * (1.0 - f));
+
+ /* Find delta from black body point to test coordinate.
*/
+ uu = u - (temp_table[index - 1] . u * f +
temp_table[index] . u * (1.0 - f));
+ vv = v - (temp_table[index - 1] . v * f +
temp_table[index] . v * (1.0 - f));
+
+ /* Interpolate vectors along slope. */
+ du = du * (1.0 - f) + last_du * f;
+ dv = dv * (1.0 - f) + last_dv * f;
+
+ len = sqrt (du * du + dv * dv);
+
+ du /= len;
+ dv /= len;
+
+ /* Find distance along slope. */
+ if (tint)
+ *tint = (uu * du + vv * dv) * tint_scale;
+
+ break;
+ }
+
+ /* Try next line pair. */
+
+ last_dt = dt;
+
+ last_du = du;
+ last_dv = dv;
+ }
+}
+
+RS_xy_COORD
+rs_color_temp_to_whitepoint(gfloat temp, gfloat tint)
+{
+ RS_xy_COORD xy;
+
+ /* Find inverse temperature to use as index. */
+ gdouble r = 1.0E6 / temp;
+
+ /* Convert tint to offset is uv space. */
+
+ gdouble offset = tint * (1.0 / tint_scale);
+
+ /* Search for line pair containing coordinate. */
+
+ guint index;
+ for (index = 0; index <= 29; index++)
+ {
+ if (r < temp_table[index + 1] . r || index == 29)
+ {
+ /* Find relative weight of first line. */
+
+ gdouble f = (temp_table[index + 1].r - r) /
(temp_table[index + 1].r - temp_table[index].r);
+
+ /* Interpolate the black body coordinates. */
+
+ gdouble u = temp_table[index].u * f + temp_table[index
+ 1].u * (1.0 - f);
+
+ gdouble v = temp_table[index].v * f + temp_table[index
+ 1].v * (1.0 - f);
+
+ /* Find vectors along slope for each line. */
+
+ gdouble uu1 = 1.0;
+ gdouble vv1 = temp_table[index].t;
+
+ gdouble uu2 = 1.0;
+ gdouble vv2 = temp_table[index + 1].t;
+
+ gdouble len1 = sqrt (1.0 + vv1 * vv1);
+ gdouble len2 = sqrt (1.0 + vv2 * vv2);
+
+ uu1 /= len1;
+ vv1 /= len1;
+
+ uu2 /= len2;
+ vv2 /= len2;
+
+ // Find vector from black body point.
+ gdouble uu3 = uu1 * f + uu2 * (1.0 - f);
+ gdouble vv3 = vv1 * f + vv2 * (1.0 - f);
+
+ gdouble len3 = sqrt (uu3 * uu3 + vv3 * vv3);
+
+ uu3 /= len3;
+ vv3 /= len3;
+
+ // Adjust coordinate along this vector.
+
+ u += uu3 * offset;
+ v += vv3 * offset;
+
+ // Convert to xy coordinates.
+
+ xy.x = 1.5 * u / (u - 4.0 * v + 2.0);
+ xy.y = v / (u - 4.0 * v + 2.0);
+
+ break;
+ }
+ }
+
+ return xy;
+}
+
+RS_XYZ_VECTOR
+xy_to_XYZ(const RS_xy_COORD *xy)
+{
+ RS_XYZ_VECTOR XYZ;
+
+ /* Watch out for division by zero and clipping */
+ gdouble x = CLAMP(xy->x, 0.000001, 0.999999);
+ gdouble y = CLAMP(xy->y, 0.000001, 0.999999);
+
+ /* Correct out of range color coordinates */
+ if ((x + y) > 0.999999)
+ {
+ gdouble scale = 0.999999 / (x + y);
+ x *= scale;
+ y *= scale;
+ }
+
+ XYZ.X = x / y;
+ XYZ.Y = 1.0;
+ XYZ.Z = (1.0 - x - y) / y;
+
+ return XYZ;
+}
+
+RS_xy_COORD
+XYZ_to_xy(const RS_XYZ_VECTOR *XYZ)
+{
+ RS_xy_COORD xy;
+
+ gfloat sum = XYZ->X + XYZ->Y + XYZ->Z;
+
+ if (sum > 0.0)
+ {
+ xy.x = XYZ->X / sum;
+ xy.y = XYZ->Y / sum;
+ }
+ else
+ xy = XYZ_to_xy(&XYZ_WP_D50);
+
+ return xy;
+}
+
+/**
+ * http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
+ */
+RS_MATRIX3
+rs_calculate_map_white_matrix(const RS_xy_COORD *from_xy, const RS_xy_COORD
*to_xy)
+{
+ RS_MATRIX3 adapt;
+
+ /* Bradford adaption matrix */
+ RS_MATRIX3 bradford = {{
+ { 0.8951, 0.2664, -0.1614, },
+ { -0.7502, 1.7135, 0.0367, },
+ { 0.0389, -0.0685, 1.0296 }
+ }};
+
+ RS_XYZ_VECTOR from_xyz;
+ RS_XYZ_VECTOR to_xyz;
+ RS_VECTOR3 ws, wd;
+ RS_MATRIX3 tmp;
+
+ from_xyz = xy_to_XYZ(from_xy);
+ to_xyz = xy_to_XYZ(to_xy);
+
+ ws = vector3_multiply_matrix(&from_xyz, &bradford);
+ wd = vector3_multiply_matrix(&to_xyz, &bradford);
+
+ ws.x = MAX(ws.x, 0.0);
+ ws.y = MAX(ws.y, 0.0);
+ ws.z = MAX(ws.z, 0.0);
+
+ wd.x = MAX(wd.x, 0.0);
+ wd.y = MAX(wd.y, 0.0);
+ wd.z = MAX(wd.z, 0.0);
+
+ matrix3_identity(&tmp);
+
+ tmp.coeff[0][0] = CLAMP(0.1, ws.x > 0.0 ? wd.x / ws.x : 10.0, 10.0);
+ tmp.coeff[1][1] = CLAMP(0.1, ws.y > 0.0 ? wd.y / ws.y : 10.0, 10.0);
+ tmp.coeff[2][2] = CLAMP(0.1, ws.z > 0.0 ? wd.z / ws.z : 10.0, 10.0);
+
+ adapt = matrix3_invert(&bradford);
+ matrix3_multiply(&adapt, &tmp, &adapt);
+ matrix3_multiply(&adapt, &bradford, &adapt);
+
+ return adapt;
+}
Added: trunk/librawstudio/rs-color.h
===================================================================
--- trunk/librawstudio/rs-color.h (rev 0)
+++ trunk/librawstudio/rs-color.h 2009-09-23 15:10:54 UTC (rev 2651)
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006-2009 Anders Brander <[email protected]> and
+ * Anders Kvist <[email protected]>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
+ */
+
+#ifndef RS_COLOR_H
+#define RS_COLOR_H
+
+extern const RS_MATRIX3 PCStoProPhoto;
+extern const RS_XYZ_VECTOR XYZ_WP_D50;
+
+extern void rs_color_whitepoint_to_temp(const RS_xy_COORD *xy, gfloat *temp,
gfloat *tint);
+extern RS_xy_COORD rs_color_temp_to_whitepoint(gfloat temp, gfloat tint);
+extern RS_XYZ_VECTOR xy_to_XYZ(const RS_xy_COORD *xy);
+extern RS_xy_COORD XYZ_to_xy(const RS_XYZ_VECTOR *XYZ);
+extern RS_MATRIX3 rs_calculate_map_white_matrix(const RS_xy_COORD *from_xy,
const RS_xy_COORD *to_xy);
+
+#endif /* RS_COLOR_H */
_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit