Author: abrander
Date: 2009-12-31 03:50:18 +0100 (Thu, 31 Dec 2009)
New Revision: 2950
Added:
branches/rawstudio-ng-color/plugins/colorspace-transform/rs-cmm.c
branches/rawstudio-ng-color/plugins/colorspace-transform/rs-cmm.h
Modified:
branches/rawstudio-ng-color/plugins/colorspace-transform/Makefile.am
branches/rawstudio-ng-color/plugins/colorspace-transform/colorspace_transform.c
Log:
Made RSColorspaceTransform aware of ICC-based colorspaces.
Modified: branches/rawstudio-ng-color/plugins/colorspace-transform/Makefile.am
===================================================================
--- branches/rawstudio-ng-color/plugins/colorspace-transform/Makefile.am
2009-12-31 02:48:10 UTC (rev 2949)
+++ branches/rawstudio-ng-color/plugins/colorspace-transform/Makefile.am
2009-12-31 02:50:18 UTC (rev 2950)
@@ -18,4 +18,4 @@
colorspace_transform_la_LIBADD = @PACKAGE_LIBS@
colorspace_transform_la_LDFLAGS = -module -avoid-version
-colorspace_transform_la_SOURCES = colorspace_transform.c
+colorspace_transform_la_SOURCES = colorspace_transform.c rs-cmm.c rs-cmm.h
Modified:
branches/rawstudio-ng-color/plugins/colorspace-transform/colorspace_transform.c
===================================================================
---
branches/rawstudio-ng-color/plugins/colorspace-transform/colorspace_transform.c
2009-12-31 02:48:10 UTC (rev 2949)
+++
branches/rawstudio-ng-color/plugins/colorspace-transform/colorspace_transform.c
2009-12-31 02:50:18 UTC (rev 2950)
@@ -21,6 +21,7 @@
#include <rawstudio.h>
#include <lcms.h>
+#include "rs-cmm.h"
#define RS_TYPE_COLORSPACE_TRANSFORM (rs_colorspace_transform_type)
#define RS_COLORSPACE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
RS_TYPE_COLORSPACE_TRANSFORM, RSColorspaceTransform))
@@ -33,6 +34,7 @@
struct _RSColorspaceTransform {
RSFilter parent;
+ RSCmm *cmm;
};
struct _RSColorspaceTransformClass {
@@ -74,6 +76,9 @@
static void
rs_colorspace_transform_init(RSColorspaceTransform *colorspace_transform)
{
+ /* FIXME: unref this at some point */
+ colorspace_transform->cmm = rs_cmm_new();
+ rs_cmm_set_num_threads(colorspace_transform->cmm,
rs_get_number_of_processor_cores());
}
static RSFilterResponse *
@@ -94,18 +99,28 @@
RSColorSpace *output_space =
rs_filter_param_get_object_with_type(RS_FILTER_PARAM(request), "colorspace",
RS_TYPE_COLOR_SPACE);
response = rs_filter_response_clone(previous_response);
- g_object_unref(previous_response);
- output = rs_image16_copy(input, FALSE);
- convert_colorspace16(colorspace_transform, input, output, input_space,
output_space);
+ printf("\033[33m16 input_space: %s\033[0m\n", (input_space) ?
G_OBJECT_TYPE_NAME(input_space) : "none");
+ printf("\033[33m16 output_space: %s\n\033[0m", (output_space) ?
G_OBJECT_TYPE_NAME(output_space) : "none");
+ if (input_space && output_space)
+ {
+ g_object_unref(previous_response);
+ output = rs_image16_copy(input, FALSE);
- rs_filter_response_set_image(response, output);
- g_object_unref(output);
+ convert_colorspace16(colorspace_transform, input, output,
input_space, output_space);
- /* Process output */
+ rs_filter_response_set_image(response, output);
+ g_object_unref(output);
+ g_object_unref(input);
- g_object_unref(input);
- return response;
+ return response;
+ }
+ else
+ {
+ g_debug("No conversion done");
+ return previous_response;
+ }
+
}
static RSFilterResponse *
@@ -125,6 +140,9 @@
RSColorSpace *input_space =
rs_filter_param_get_object_with_type(RS_FILTER_PARAM(previous_response),
"colorspace", RS_TYPE_COLOR_SPACE);
RSColorSpace *output_space =
rs_filter_param_get_object_with_type(RS_FILTER_PARAM(request), "colorspace",
RS_TYPE_COLOR_SPACE);
+ printf("\033[33m8 input_space: %s\033[0m\n", (input_space) ?
G_OBJECT_TYPE_NAME(input_space) : "none");
+ printf("\033[33m8 output_space: %s\n\033[0m", (output_space) ?
G_OBJECT_TYPE_NAME(output_space) : "none");
+
response = rs_filter_response_clone(previous_response);
g_object_unref(previous_response);
output = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, input->w,
input->h);
@@ -140,11 +158,6 @@
return response;
}
-//static cmsHTRANSFORM
-//get_lcms_transform16(RSColorspaceTransform *colorspace_transform,
RSIccProfile *input_profile, RSIccProfile *output_profile)
-//{
-//}
-
static void
transform8_c(RS_IMAGE16 *input, GdkPixbuf *output, RS_MATRIX3 *matrix, guchar
*table8)
{
@@ -266,8 +279,15 @@
/* If a CMS is needed, do the transformation using LCMS */
else if (RS_COLOR_SPACE_REQUIRES_CMS(input_space) ||
RS_COLOR_SPACE_REQUIRES_CMS(output_space))
{
- g_warning("FIXME: (stub) LCMS support is not implemented yet");
- memcpy(output_image->pixels, input_image->pixels,
input_image->rowstride*input_image->h*2);
+ const RSIccProfile *i, *o;
+
+ i = rs_color_space_get_icc_profile(input_space);
+ o = rs_color_space_get_icc_profile(output_space);
+
+ rs_cmm_set_input_profile(colorspace_transform->cmm, i);
+ rs_cmm_set_output_profile(colorspace_transform->cmm, o);
+
+ rs_cmm_transform16(colorspace_transform->cmm, input_image,
output_image);
}
/* If we get here, we can transform using simple vector math */
@@ -304,11 +324,19 @@
/* If a CMS is needed, do the transformation using LCMS */
if (RS_COLOR_SPACE_REQUIRES_CMS(input_space) ||
RS_COLOR_SPACE_REQUIRES_CMS(output_space))
{
- g_warning("FIXME: (stub) LCMS support is not implemented yet");
+ const RSIccProfile *i, *o;
+
+ i = rs_color_space_get_icc_profile(input_space);
+ o = rs_color_space_get_icc_profile(output_space);
+
+ rs_cmm_set_input_profile(colorspace_transform->cmm, i);
+ rs_cmm_set_output_profile(colorspace_transform->cmm, o);
+
+ rs_cmm_transform8(colorspace_transform->cmm, input_image,
output_image);
}
/* If we get here, we can transform using simple vector math and a
lookup table */
-// else
+ else
{
const RS_MATRIX3 a =
rs_color_space_get_matrix_from_pcs(input_space);
const RS_MATRIX3 b =
rs_color_space_get_matrix_to_pcs(output_space);
Added: branches/rawstudio-ng-color/plugins/colorspace-transform/rs-cmm.c
===================================================================
--- branches/rawstudio-ng-color/plugins/colorspace-transform/rs-cmm.c
(rev 0)
+++ branches/rawstudio-ng-color/plugins/colorspace-transform/rs-cmm.c
2009-12-31 02:50:18 UTC (rev 2950)
@@ -0,0 +1,243 @@
+/*
+ * 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 <lcms.h>
+#include "rs-cmm.h"
+
+struct _RSCmm {
+ GObject parent;
+
+ const RSIccProfile *input_profile;
+ const RSIccProfile *output_profile;
+ gint num_threads;
+
+ gboolean dirty8;
+ gboolean dirty16;
+
+ cmsHPROFILE lcms_input_profile;
+ cmsHPROFILE lcms_output_profile;
+
+ cmsHTRANSFORM lcms_transform8;
+ cmsHTRANSFORM lcms_transform16;
+};
+
+G_DEFINE_TYPE (RSCmm, rs_cmm, G_TYPE_OBJECT)
+
+static void load_profile(RSCmm *cmm, const RSIccProfile *profile, const
RSIccProfile **profile_target, cmsHPROFILE *lcms_target);
+static void prepare8(RSCmm *cmm);
+static void prepare16(RSCmm *cmm);
+
+static void
+rs_cmm_dispose(GObject *object)
+{
+ G_OBJECT_CLASS(rs_cmm_parent_class)->dispose (object);
+}
+
+static void
+rs_cmm_class_init(RSCmmClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->dispose = rs_cmm_dispose;
+}
+
+static void
+rs_cmm_init(RSCmm *cmm)
+{
+}
+
+RSCmm *
+rs_cmm_new(void)
+{
+ return g_object_new(RS_TYPE_CMM, NULL);
+}
+
+void
+rs_cmm_set_input_profile(RSCmm *cmm, const RSIccProfile *input_profile)
+{
+ g_assert(RS_IS_CMM(cmm));
+ g_assert(RS_IS_ICC_PROFILE(input_profile));
+
+ load_profile(cmm, input_profile, &cmm->input_profile,
&cmm->lcms_input_profile);
+}
+
+void
+rs_cmm_set_output_profile(RSCmm *cmm, const RSIccProfile *output_profile)
+{
+ g_assert(RS_IS_CMM(cmm));
+ g_assert(RS_IS_ICC_PROFILE(output_profile));
+
+ load_profile(cmm, output_profile, &cmm->output_profile,
&cmm->lcms_output_profile);
+}
+
+void
+rs_cmm_set_num_threads(RSCmm *cmm, const gint num_threads)
+{
+ g_assert(RS_IS_CMM(cmm));
+
+ cmm->num_threads = MAX(1, num_threads);
+}
+
+gboolean
+rs_cmm_transform16(RSCmm *cmm, RS_IMAGE16 *input, RS_IMAGE16 *output)
+{
+ printf("rs_cms_transform16()\n");
+ gint y;
+ g_assert(RS_IS_CMM(cmm));
+ g_assert(RS_IS_IMAGE16(input));
+ g_assert(RS_IS_IMAGE16(output));
+
+ g_return_val_if_fail(input->w == output->w, FALSE);
+ g_return_val_if_fail(input->h == output->h, FALSE);
+ g_return_val_if_fail(input->pixelsize == 4, FALSE);
+
+ if (cmm->dirty16)
+ prepare16(cmm);
+
+ for(y=0;y<input->h;y++)
+ {
+ gushort *in = GET_PIXEL(input, 0, y);
+ gushort *out = GET_PIXEL(output, 0, y);
+ cmsDoTransform(cmm->lcms_transform16, in, out, input->w);
+ }
+ return TRUE;
+}
+
+gboolean
+rs_cmm_transform8(RSCmm *cmm, RS_IMAGE16 *input, GdkPixbuf *output)
+{
+ g_assert(RS_IS_CMM(cmm));
+ g_assert(RS_IS_IMAGE16(input));
+ g_assert(GDK_IS_PIXBUF(output));
+
+ g_return_val_if_fail(input->w == gdk_pixbuf_get_width(output), FALSE);
+ g_return_val_if_fail(input->h == gdk_pixbuf_get_height(output), FALSE);
+ g_return_val_if_fail(input->pixelsize == 4, FALSE);
+
+ if (cmm->dirty8)
+ prepare8(cmm);
+
+ /* FIXME: Render */
+ g_warning("rs_cmm_transform8() is a stub");
+
+ return TRUE;
+}
+
+static guchar *
+pack_rgb_w4(void *info, register WORD wOut[], register LPBYTE output)
+{
+ *(LPWORD) output = wOut[0]; output+= 2;
+ *(LPWORD) output = wOut[1]; output+= 2;
+ *(LPWORD) output = wOut[2]; output+= 4;
+
+ return(output);
+}
+
+static guchar *
+unroll_rgb_w4(void *info, register WORD wIn[], register LPBYTE accum)
+{
+ wIn[0] = *(LPWORD) accum; accum+= 2;
+ wIn[1] = *(LPWORD) accum; accum+= 2;
+ wIn[2] = *(LPWORD) accum; accum+= 4;
+
+ return(accum);
+}
+
+static void
+load_profile(RSCmm *cmm, const RSIccProfile *profile, const RSIccProfile
**profile_target, cmsHPROFILE *lcms_target)
+{
+// DEBUG START
+ gchar *filename;
+ g_object_get((void *) profile, "filename", &filename, NULL);
+ printf("load_profile(%p [%s])\n", profile, filename);
+// DEBUG END
+ gchar *data;
+ gsize length;
+
+ if (*profile_target == profile)
+ return;
+
+ *profile_target = profile;
+
+ if (*lcms_target)
+ cmsCloseProfile(*lcms_target);
+
+ if (rs_icc_profile_get_data(profile, &data, &length))
+ *lcms_target = cmsOpenProfileFromMem(data, length);
+
+ g_warn_if_fail(*lcms_target != NULL);
+
+ cmm->dirty8 = TRUE;
+ cmm->dirty16 = TRUE;
+ printf("load_profile() DONE\n");
+}
+
+static void
+prepare8(RSCmm *cmm)
+{
+}
+
+gdouble
+estimate_gamma(cmsHPROFILE *profile)
+{
+ gdouble gamma_value[3] = {1.0, 1.0, 1.0};
+ LPGAMMATABLE gamma[3];
+
+ gamma[0] = cmsReadICCGamma(profile, icSigRedTRCTag);
+ gamma[1] = cmsReadICCGamma(profile, icSigGreenTRCTag);
+ gamma[2] = cmsReadICCGamma(profile, icSigBlueTRCTag);
+
+ if (gamma[0] && gamma[1] && gamma[2])
+ {
+ gamma_value[0] = cmsEstimateGamma(gamma[0]);
+ gamma_value[1] = cmsEstimateGamma(gamma[1]);
+ gamma_value[2] = cmsEstimateGamma(gamma[2]);
+ }
+ else
+ printf("No tables\n");
+
+ return (gamma_value[0] + gamma_value[1] + gamma_value[2]) / 3.0;
+}
+
+static void
+prepare16(RSCmm *cmm)
+{
+ if (!cmm->dirty16)
+ return;
+
+ if (cmm->lcms_transform16)
+ cmsDeleteTransform(cmm->lcms_transform16);
+
+ printf("INPUT GAMMA: %f\n", estimate_gamma(cmm->lcms_input_profile));
+ printf("OUTPUT GAMMA: %f\n", estimate_gamma(cmm->lcms_output_profile));
+
+ cmm->lcms_transform16 = cmsCreateTransform(
+ cmm->lcms_input_profile, TYPE_RGB_16,
+ cmm->lcms_output_profile, TYPE_RGB_16,
+ INTENT_PERCEPTUAL, 0);
+
+ g_warn_if_fail(cmm->lcms_transform16 != NULL);
+
+ /* Enable packing/unpacking for pixelsize==4 */
+ cmsSetUserFormatters(cmm->lcms_transform16,
+ TYPE_RGB_16, unroll_rgb_w4,
+ TYPE_RGB_16, pack_rgb_w4);
+
+ cmm->dirty16 = FALSE;
+}
Added: branches/rawstudio-ng-color/plugins/colorspace-transform/rs-cmm.h
===================================================================
--- branches/rawstudio-ng-color/plugins/colorspace-transform/rs-cmm.h
(rev 0)
+++ branches/rawstudio-ng-color/plugins/colorspace-transform/rs-cmm.h
2009-12-31 02:50:18 UTC (rev 2950)
@@ -0,0 +1,57 @@
+/*
+ * 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_CMM_H
+#define RS_CMM_H
+
+#include <rawstudio.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define RS_TYPE_CMM rs_cmm_get_type()
+#define RS_CMM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RS_TYPE_CMM, RSCmm))
+#define RS_CMM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RS_TYPE_CMM,
RSCmmClass))
+#define RS_IS_CMM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RS_TYPE_CMM))
+#define RS_IS_CMM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RS_TYPE_CMM))
+#define RS_CMM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RS_TYPE_CMM,
RSCmmClass))
+
+typedef struct _RSCmm RSCmm;
+
+typedef struct {
+ GObjectClass parent_class;
+} RSCmmClass;
+
+GType rs_cmm_get_type(void);
+
+RSCmm *rs_cmm_new(void);
+
+void rs_cmm_set_input_profile(RSCmm *cmm, const RSIccProfile *input_profile);
+
+void rs_cmm_set_output_profile(RSCmm *cmm, const RSIccProfile *output_profile);
+
+void rs_cmm_set_num_threads(RSCmm *cmm, const gint num_threads);
+
+gboolean rs_cmm_transform16(RSCmm *cmm, RS_IMAGE16 *input, RS_IMAGE16 *output);
+
+gboolean rs_cmm_transform8(RSCmm *cmm, RS_IMAGE16 *input, GdkPixbuf *output);
+
+G_END_DECLS
+
+#endif /* RS_CMM_H */
_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit