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

Reply via email to